How to delete all file and folders with msbuild - msbuild

How can I delete all files and folders from a given path?
I tried this, but I'm unable to select the directories.
<Target Name="CleanSource" Condition="$(path)!=''">
<Message Text="path=$(path)"/>
<ItemGroup>
<fileToDelete Include="$(path)\**\*.*" />
<directoryToDelete Include="$(path)\**\" /><!these doest not select any directory at all-->
</ItemGroup>
<Message Text="file to delete:#(fileToDelete)"/>
<Message Text="directory to delete:#(directoryToDelete)"/>
<Delete Files="#(fileToDelete)" />
<Message Text="file effectively deleted:#(DeletedFiles)"/>
<RemoveDir Directories="#(directoryToDelete)" />
<Message Text="Directory effectively deleted:#(RemovedDirectories)"/>
</Target>

The RemoveDir task removes the specified directories and all of its files and subdirectories. You don't have to remove the files and subdirectories first. Just pass the directory name to RemoveDir.
<ItemGroup>
<DirsToClean Include="work" />
</ItemGroup>
<Target Name="CleanWork">
<RemoveDir Directories="#(DirsToClean)" />
</Target>

While there are ways to construct this using just MSBuild, I'd highly recommend the MSBuild Extension pack.
http://msbuildextensionpack.codeplex.com/ [has been moved]
GitHub: MSBuildExtensionPack
Using the pack, you get a RemoveContent task that does exactly what you are needing. Once you install, you'd just do something like:
<MSBuild.ExtensionPack.FileSystem.Folder
TaskAction="RemoveContent" Path="$(PathtoEmpty)"/>

I'm arriving to this conversation a little late, but I found the easiest way to accomplish this was to use the Exec task to execute the batch command given by lain in response to a similar question (with minor edits by yours truly):
<Exec Command="FOR /D %%p IN ("$(path)*.*") DO rmdir "%%p" /s /q" />

Finally I did use powershell wich is much more fast:
<exec>
<executable>powershell.exe</executable>
<buildArgs><![CDATA[-command "& {if( [System.IO.Directory]::Exists($pwd) ){dir $pwd | ri -recurse
-force}}"]]></buildArgs>
</exec>

Related

How to publish additional files using msbuild file and TeamCity?

I'm using a msbuild file, TeamCity and Web Deploy to deploy my siteand everything works just fine, for the files included in the Visual Studio csproj file. In addition to these files I want to publish a couple of more files such as license files etc depending on environment.
This is my build file DeployToTest.proj:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<LicenseSourceFiles Include="License.config"/>
<RobotSourceFile Include="robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
As you can see I tried to copy the license.config and robots.txt without any luck.
This .proj file is selected as the 'Build file path' in TeamCity.
Any suggestions on how I can accomplish this?
To solve this problem it may be worth executing the build script with the verbosity set to the 'detailed' or 'diagnostic' level. That should tell you exactly why the copy step fails.
However one of the most likely problems could be the fact that the script is using relative file paths, which depend on the working directory being set to the correct value. For build scripts I prefer use absolute paths to prevent any file path problems.
To get the absolute path you can use the MSBuildProjectDirectory property. The value of this property points to the path of the directory containing the currently executing MsBuild script. With that you can change your MsBuild script like this:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<BaseDir>$(MSBuildProjectDirectory)</BaseDir>
</PropertyGroup>
<ItemGroup>
<LicenseSourceFiles Include="$(BaseDir)\License.config"/>
<RobotSourceFile Include="$(BaseDir)\robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="$(BaseDir)\..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="$(BaseDir)\..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="$(BaseDir)\..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
Now this should fix the problem if there is indeed a problem with the relative file paths.
Solution was to change settings for the web project in Visual Studio. Under Package/Publish Web i set 'Items to deploy' to 'All files in this project folder'. I then added a filter to remove all .cs files and other unwanted files.

Deleting files on a remote machine (shared folder) using msbuild

I want to delete files kept in a shared folder on a remote machine using msbuild. I have googled but couldn't get a proper solution. Please help.
Thank you
To answer my own question: Following code is working.
<ItemGroup>
<ServiceLocation Include="\\ServerName\FolderName\*.*"></ServiceLocation>
</ItemGroup>
<Target Name="Deploy">
<Delete Files="#(ServiceLocation)" />
</Target>
try with this one,
<Target Name="SomeTarget">
<ItemGroup>
<FilesToDelete Include="Path\To\Obj\**\*"/>
</ItemGroup>
<Delete Files="#(FilesToDelete)" />
</Target>

xcopy with MsBuild

I have a really simple build script that looks like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Bundle">
<ItemGroup>
<BuildArtifacts Include="..\_buildartifacts" />
<Application Include="..\_application" />
</ItemGroup>
<Target Name="Clean">
<RemoveDir Directories="#(BuildArtifacts)" />
<RemoveDir Directories="#(Application)" />
</Target>
<Target Name="Init" DependsOnTargets="Clean">
<MakeDir Directories="#(BuildArtifacts)" />
<MakeDir Directories="#(Application)" />
</Target>
<Target Name="Bundle" DependsOnTargets="Compile">
<Exec Command="xcopy.exe %(BuildArtifacts.FullPath) %(Application.FullPath) /e /EXCLUDE:$(MSBuildProjectDirectory)\files_to_ignore_when_bundling.txt" WorkingDirectory="C:\Windows\" />
</Target>
The problem is the Bundle target, only the %(BuildArtifacts.FullPath) gets extracted, %(BuildArtifacts.FullPath) is ignored when the scripts executes.
The command looks like this when executing:
xcopy.exe C:\#Code\blaj_buildartifacts /e /EXCLUDE:C:\#Code\blaj\files_to_ignore_when_bundling.txt" exited with code 4
As you can see, the destination path is not there, if I hard code the paths or just the destination path it all works. Any suggestion on what I am doing wrong here?
Update
I managed to solve the problem, I removed the last part WorkingDirectory="C:\Windows\"
And changed the script into this:
<Exec Command="xcopy.exe #(BuildArtifacts) #(Application) /e /EXCLUDE:$(MSBuildProjectDirectory)\files_to_ignore_when_bundling.txt" />
and now it's working :)
I managed to solve this. I've updated the question with the solution.
I removed the last part WorkingDirectory="C:\Windows\" And changed the script into this:
<Exec Command="xcopy.exe #(BuildArtifacts) #(Application) /e /EXCLUDE:$(MSBuildProjectDirectory)\files_to_ignore_when_bundling.txt" />
and now it's working :)
You need to execute xcopy twice. You are trying to use task batching for two different item arrays in the same invocation, it doesn't work like that. Try this:
<Target Name="Bundle" DependsOnTargets="Compile">
<Exec Command="xcopy.exe %(BuildArtifacts.FullPath) /e /EXCLUDE:$(MSBuildProjectDirectory)\files_to_ignore_when_bundling.txt" WorkingDirectory="C:\Windows\" />
<Exec Command="xcopy.exe %(Application.FullPath) /e /EXCLUDE:$(MSBuildProjectDirectory)\files_to_ignore_when_bundling.txt" WorkingDirectory="C:\Windows\" />
</Target>

How do I select all read-only files with msbuild?

I'm trying to write an MsBuild script to zip some files up. I need to select all of the read-only files recursively from a folder into an ItemGroup to add to the zip.
I'm using the community tasks Zip task, but am struggling with selecting files based on their attributes.
Is there anything around to do this out of the box, or do I need to write a custom task?
Thanks for you help.
You can use Property Functions (added to msbuild 4) to figure out if a file is read-only like so:
<ItemGroup>
<MyFiles Include="Testing\*.*" >
<ReadOnly Condition='1 == $([MSBuild]::BitwiseAnd(1, $([System.IO.File]::GetAttributes("%(Identity)"))))'>True</ReadOnly>
</MyFiles>
</ItemGroup>
<Target Name="Run" Outputs="%(MyFiles.Identity)">
<Message Text="%(MyFiles.Identity)" Condition="%(MyFiles.ReadOnly) != True"/>
<Message Text="%(MyFiles.Identity) ReadOnly" Condition="%(MyFiles.ReadOnly) == True" />
</Target>
Have you looked at the community build tasks site?
It has a zip task and an attribute change task - they should get you most of they way there.
This seems to do the job with a bit of dirty command line usage.
<Exec Command="dir .\RelPath\ToFolder\ToSearchIn /S /AR /B > readonlyfiles.temp.txt"/>
<ReadLinesFromFile File="readonlyfiles.temp.txt">
<Output TaskParameter="Lines" ItemName="ReadOnlyFiles"/>
</ReadLinesFromFile>
<Delete Files="readonlyfiles.temp.txt"/>
That gives absolute paths to the files.
To get relative paths, try something like this:
<Exec Command="dir .\RelPath\ToFolder\ToSearchIn /S /AR /B > readonlyfiles.temp.txt"/>
<FileUpdate Files="readonlyfiles.temp.txt"
Multiline="True"
Regex="^.*\\RelPath\\ToFolder\\ToSearchIn"
ReplacementText="RelPath\ToFolder\ToSearchIn"
/>
<ReadLinesFromFile File="readonlyfiles.temp.txt">
<Output TaskParameter="Lines" ItemName="ReadOnlyZipFiles"/>
</ReadLinesFromFile>
<Delete Files="readonlyfiles.temp.txt"/>

MSBuild Task syntax for deleting files

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?
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>
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.
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 "#(FileToDelete)""/>
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("$(OutDir)"))" />
</ItemGroup>
<Delete Files="#(FilesToClean)"/>
<RemoveDir Directories="#(FoldersToClean)" />
</Target>
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 "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
<Exec Command="RmDir /S /Q "$(BuildFolder)"" />
</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.
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>`
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.
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.