How To: Recursively Copy Files Using the Task
Have you ever run into a situation where you had to recursively copy files from one folder into another as a part of your build process? We certainly have run into it a few times, and I thought I'd share with you a neat trick that involves the use of metadata and the Copy task.
Before you can copy a set of files, you need to be able to recursively add those files to an item list. Here's how you do that when declaring items.
<
ItemGroup>
<Compile Include=".\**\*.cs" />
</ItemGroup>
The ** wildcard is used in item includes to indicate recursive includes.
So, once you have an item declared as such, you can rely on a piece of standard meta-data that goes with all items (i.e. RecursiveDir) to accomplish your recursive copy. The RecursiveDir metadata when used will return the evaluated value of the ** metadata for each item - and you can use that value to preserve the folder structure for each file when performing the copy. Here's how you invoke the <Copy> task using this piece of metadata to copy recursively.
<
Copy SourceFiles="@(Compile)" DestinationFolder="c:\foocopy\%(RecursiveDir)"></Copy>
Hope this helps! Let us know if these tips/tricks and how-tos are useful.
[ Author: Faisal Mohamood ]
Comments
Anonymous
December 20, 2005
This is very useful. Is there a way to skip files with a certain extension?Anonymous
March 01, 2006
Well, this is very good, but what should i do, if i have to copy only files with certain extensions and form certain subdirectories of one give subtree root. For example, in NAnt i do it like this:
<copy todir="sdfTestWeb/private">
<fileset basedir="${solution.path}/sdf.SPanel/private">
<include name=".sdf"/>
<include name=".aspx"/>
<include name=".asmx"/>
<include name=".inc"/>
<include name="web.config"/>
<include name="images//."/>
<include name="scripts//."/>
<include name="styles//."/>
<include name="xml//."/>
<include name="xsl//."/>
<exclude name="/*.vss"/>
</fileset>
</copy>
It copies all specified files resembling the directory structure. Only necessary files, as you can see. In fact, the subtree contains also a whole bunch of unneded files.
How could i do it with MSBuild?Anonymous
March 02, 2006
In MSBuild, to copy a part of subtree, resembling directory structure, you have to write small and simple task. ...Anonymous
April 17, 2006
copy files using <a href="http://www.yaodownload.com/utilites/file-disk-management/filemonkey/">FileMonkey</a>">http://www.yaodownload.com/utilites/file-disk-management/filemonkey/">FileMonkey</a> , it's really good!
http://www.yaodownload.com/utilites/file-disk-management/filemonkey/Anonymous
May 10, 2006
Did you ever just want a simple way to copy a folder from one place to annother without any fuss? Xcopy works pretty good.
<Exec Command='xcopy /E <from> <to>' />
Anonymous
June 14, 2006
I'm really growing to like MSBuild, but some of it's syntax is just needlessly cryptic.&nbsp; For example...Anonymous
September 19, 2006
As part of my conversion to Asp.Net 2 I had decided to utilise Msbuild over Nant. In my Asp.net 1.1 buildAnonymous
October 11, 2006
I'm just learning msbuild ( mostly done NAnt in the past ) and I'm wondering why this doesn't work when the ItemGroup Include attribute points to a UNC path? Basically my files get copied, but they are flattened into a single destination directory. If I map the drive and change my Include attribute it works correctly.Anonymous
October 12, 2006
I've further determined that it fails with administrative shares such as \servere$ but not normal shares such as \serverbuildoutputAnonymous
October 31, 2006
Excellent Tip! Keep 'em coming. That's really sorted me out. I'm using the new web deployment http://weblogs.asp.net/scottgu/archive/2005/11/06/429723.aspx project which is great. Somehow though it copies all the .csproj files and everything into it's release directory??? Strange, I thought it would operate more like a "Publish" of the web site like in Visual Studio? Oh well.Anonymous
November 14, 2006
I'm running into some weird problems. Following is the file collection I am using: <!--File Collection--> <ItemGroup> <SourceFiles Include="$(SOURCECODE_ROOT)$(FolderName)coremdsWinRel***.dll" /> <SourceFiles Include="$(SOURCECODE_ROOT)$(FolderName)coreWinRel***.dll" /> <SourceFiles Include="$(SOURCECODE_ROOT)$(FolderName)coreWinRel***.exe" /> <SourceFiles Include="$(SOURCECODE_ROOT)$(FolderName)coreWinRel***.tlb" /> <SourceFiles Include="$(SOURCECODE_ROOT)$(FolderName)coreWinRel***.ocx" /> </ItemGroup> Here is the copy task I am using: <Copy SourceFiles="@(SourceFiles)" DestinationFiles="@(SourceFiles->'$(EXECUTABLES_ROOT)$(FolderName)$(BuildLevel)%(RecursiveDir)%(Filename)%(Extension)')" /> This only sometimes works. For instance, today, the .exe didn't get copied nor did any of the subdirectories. Does anyone see anything wrong with the above? Thanks!Anonymous
November 16, 2006
I was able to get the Copy tasks to work consistently by moving these tasks into a separate target. Previously, I had: <msbuild ... > <copy ... > <removedir ... > <copy ... > <msbuild ... > When I move the copy/removedir/copy into a separate task it works fine every time. Pretty weird.Anonymous
January 03, 2007
We got a great question at msbuild@microsoft.com last week: What is the preferred method to retrieveAnonymous
August 16, 2007
The reason the copy task seemed to sometimes work and not other is because I was bit by the ItemGroup being created as soon as the build script was loaded. If some of the files didn't exist when the build script was loaded then they would not be copied. The way around this, as probably everyone knew but me, is to use a CreateItem task and create the items dynamically: <CreateItem Include="$(SOURCECODE_ROOT)$(FolderName)fvw_coreMapDataServerWinRel***.dll; $(SOURCECODE_ROOT)$(FolderName)fvw_coreWinRel***.dll; $(SOURCECODE_ROOT)$(FolderName)fvw_coreWinRel***.exe; $(SOURCECODE_ROOT)$(FolderName)fvw_coreWinRel***.tlb; $(SOURCECODE_ROOT)$(FolderName)fvw_coreWinRel***.ocx"> <Output TaskParameter="Include" ItemName="SourceFiles" /> </CreateItem>Anonymous
August 23, 2007
I have this code: <ItemGroup> <ReleaseFiles Include="$(FuentesDir)PruebabinRelease*.dll"/> </ItemGroup> <Target Name = "build" > <MSBuild Projects = "Prueba.sln" Properties = "Configuration=Release" /> <Copy SourceFiles="@(ReleaseFiles)" DestinationFolder="$(ReleaseDir)" /> </Target> The copy dont work because at first @(ReleaseFiles) is empty. Could somebody hep me?Anonymous
October 10, 2007
I am trying to use MSBuild Copy function to copy a single text file (a version file) that is created imediately upon build to several specific projects releasebin folder. In affect I have this structure: Original_Product_DirectoryversionFile.Txt This single fiel I want copied to the following folder structure: New_Product_DirectorySub_Product_AReleaseBin New_Product_DirectorySub_Product_BReleaseBin New_Product_DirectorySub_Product_CReleaseBin New_Product_DirectorySub_Product_DReleaseBin ... .. . The Sub_Product _? folder can be one of many and may change over time so the task has to eb somewhat dynamic. Please provide any suggestions or examples that would help. Thanks.Anonymous
December 11, 2007
I got today hysterical message from a good friend that implementing in his company automatic build withAnonymous
February 17, 2008
The comment has been removedAnonymous
February 28, 2008
Doesn't work for me, all files end up in the same dir. Shouldn't you copy using DestinationFiles and a transform?Anonymous
February 28, 2008
Ah, didn't work because the folder was a UNC path. Looks like more people had that problem.Anonymous
November 02, 2008
I found the code did not work: <Copy SourceFiles="@(Compile)" DestinationFolder="c:foocopy%(RecursiveDir)"></Copy> Correct version <Copy SourceFiles="@(Compile)" DestinationFolder="c:foocopy%(RecursiveDir)%(Filename)%(Extension)"></Copy>Anonymous
December 16, 2008
PingBack from http://adallow.wordpress.com/2008/12/17/msbuild-copying-files/Anonymous
January 15, 2009
The comment has been removedAnonymous
February 20, 2009
I'm trying to copy from "%INSDIR%add_distSQL Server" to "ISDIRmediadefaultdiskmagesDisk1". Also, SQL Server has another sub directory. I've tried following code in my batch file. I'm getting an error like : The syntax of the command is incorrect. <ItemGroup> <MySourceFiles Include="%ISDIR%add_dist***.*"/> </ItemGroup> <Target Name="CopyFiles"> <Copy SourceFiles="@(MySourceFiles)" DestinationFolder="%ISDIR%mediadefaultdisk imagesDisk1" /> </Target>Anonymous
October 12, 2009
Can any one suggest me how we can copy to multiple destination using a single target.Below is the syntax to do it for one location but I want to do it for multiple locations. <Target Name="CopyFiles"> <Copy SourceFiles="@(MySourceFiles)" DestinationFiles="@(MySourceFiles->'c:MyDstnTree %(RecursiveDir)%(Filename)%(Extension)')" /></Target> It would be real good if someone can achieve the same using RoboCopy. Please help. I am in dire need of solution. You can mail me atvishrut24@gmail.comAnonymous
November 30, 2009
this article is rubbish, how is a person that has never used MSBuild before supposed to know that <Copy SourceFiles="@(Compile)" DestinationFolder="c:foocopy%(RecursiveDir)"></Copy> is supposed to be wrapped inside a task element? how about providing a full working template instead of assuming everybody knows how to impliment this?Anonymous
March 05, 2010
Hi Team, Thanks this saved me some time. Could you guys please fix the msdn documentation at http://msdn.microsoft.com/en-us/library/3e54c37h%28v=VS.90%29.aspx so that it works as the above code does. Could you also work in an "Exclude" example that is more than trivial. Otherwise very useful. Cheers SimonAnonymous
July 06, 2010
Something totally different. I want to create a parameterized target with MSBuild. Is this possible? If not, are there plans to implement this in a later version?Anonymous
February 12, 2011
The Bounce (github.com/.../bounce) build framework makes recursive directory copy pretty straightforward: github.com/.../CopyTaskAnonymous
April 07, 2011
What if I want to copy a folder, together with its contents? That is irrecpective of their different extensions.