79
votes

I'm trying to write a MSBuild Task that deletes the Obj directory and PDBs from my bin folder on my production build scripts and can't seem to get it to work right.

Does anyone have an example where they do this or similar, or a link to a simple example of removing files and a directory with MSBuild?

8

8 Answers

97
votes

If you're looking to delete an entire directory you require the RemoveDir task:

<RemoveDir Directories="Path/To/Obj" />

And if you're wanting to delete the PDB files from bin you'll want the Delete task:

<Delete Files="Path/To/Bin/MyApp.pdb" />

Note that you cannot use wildcards in the Delete task, so if you have multiple pdb files you're have to provide an ItemGroup as an argument.

134
votes

You can delete the files in those directories first and then the dir itself with

<Target Name="SomeTarget">
    <ItemGroup>
        <FilesToDelete Include="Path\To\Obj\**\*"/>
    </ItemGroup>   
    <Delete Files="@(FilesToDelete)" />   
    <RemoveDir Directories="Path\To\Obj\" />
</Target>
19
votes

Posting for others that might have ran into the same problem I was having.

The Delete task cannot delete readonly files, which I needed to be able to do, as when MSBuild gets latest from TFS, the files are marked as readonly. I used the EXEC command to delete readonly files:

<ItemGroup>
    <FileToDelete Include="c:\temp\fileToDelete.txt"/>
</ItemGroup>
<Exec Command="del /F /Q &quot;@(FileToDelete)&quot;"/>
10
votes

The posted answers will work as long as you have to deal with a single directory. If you happen to have nested folders, RemoveDir will fail with Directory not empty error.

A slightly generic approach takes care of nested folders as well:

<Target Name="CleanOutDir">
    <ItemGroup>
        <FilesToClean Include="$(OutDir)\**\*.*" />

        <!-- Bit of .Net to get all folders and subfolders -->
        <FoldersToClean Include="$([System.IO.Directory]::GetDirectories(&quot;$(OutDir)&quot;))" />
    </ItemGroup>

    <Delete Files="@(FilesToClean)"/>
    <RemoveDir Directories="@(FoldersToClean)" />
</Target>
5
votes

This code is so ugly it should come with an airsickness bag. ;-) But it is fast because it doesn't build a list of files to delete etc.

<Target Name="DeleteBuildFolder">
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
    <Exec Command="RmDir /S /Q &quot;$(BuildFolder)&quot;" />
</Target>

How many RmDir commands are needed? Enough so a few RmDir commands return "The system cannot find the file specified" instead of "The directory is not empty." On my machine it seems to take another RmDir if $(BuildFolder) is open in Windows Explorer. The antivirus program may affect RmDir like it occasionally does Subversion but I'd rather have blanket AV protection than (mis)manage an exclusion list.

4
votes

It is also possible to first remove the readonly property from the file and to execute the msbuild delete Task.

Like so:

<Target Name="DeleteFiles">
 <Message Text="Delete File" Importance="high"/>
 <Attrib Files="$(FileToDelete)" ReadOnly="false" />
 <Delete Files="$(FileToDelete)" />
</Target>`
2
votes

In Visual Studio 2013, added this to the end of my .csproj file just before the </Project> closing tag

<Target Name = "clean_folders" AfterTargets="Clean">
 <Exec Command = "rd /S /Q obj" />
 <Exec Command = "rd /S /Q bin" />
</Target>

At first it didn't appear to work but I noticed that Visual Studio (or R#, not sure) re-re-added DesignTimeResolveAssemblyReferencesInput.cache to the obj folder and it also re-added the current \bin folder (I have different builds in different subfolders under \bin). It cleaned away everything else, including the 25 other build configs I have from imported .csproj files (yes, I know).

Be careful if you Batch Rebuild more than one config as it just wipes all previous efforts on each rebuild leaving you with only the last one. Whups.

1
votes

Just to add one more wrinkle that I've discovered. I'm using Visual Studio 2015. The posted answers that are deleting via wildcard are still troublesome for me. I suspect that the wildcards are evaluated before the build, not after. That means the deletions won't happen if the files you want to delete are created during the build. It also leads to wonderful behavior where the delete works every second time you build, which makes this all very enjoyable to test.

I'm giving up on wildcards. For what I'm doing I know the files that are causing trouble and I'm hard-coding (if it can be called that inside of a project file) the actual file names.