How To: Recursively Copy Files Using the <Copy> 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.

Compile Include=.\**\*.cs” /

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 (31)

  1. Pablo says:

    This is very useful. Is there a way to skip files with a certain extension?

  2. 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"/>



    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?

  3. In MSBuild, to copy a part of subtree, resembling directory structure, you have to write small and simple task. …

  4. AndrewSeven says:

    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>’ />

  5. I’m really growing to like MSBuild, but some of it’s syntax is just needlessly cryptic.&amp;nbsp; For example…

  6. As part of my conversion to Asp.Net 2 I had decided to utilise Msbuild over Nant. In my 1.1 build

  7. Christopher Painter says:

    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.

  8. Christopher Painter says:

    I’ve further determined that it fails with administrative shares such as \servere$ but not normal shares such as \serverbuildoutput

  9. Matt Wright says:

    Excellent Tip! Keep ’em coming. That’s really sorted me out. I’m using the new web deployment 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.

  10. George says:

    I’m running into some weird problems.  Following is the file collection I am using:

    <!–File Collection–>


        <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" />


    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!

  11. George says:

    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.

  12. We got a great question at last week: What is the preferred method to retrieve

  13. George says:

    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;





           <Output TaskParameter="Include" ItemName="SourceFiles" />


  14. Patricio says:

    I have this code:


    <ReleaseFiles Include="$(FuentesDir)PruebabinRelease*.dll"/>


    <Target Name = "build" >

    <MSBuild Projects = "Prueba.sln" Properties = "Configuration=Release" />

    <Copy SourceFiles="@(ReleaseFiles)" DestinationFolder="$(ReleaseDir)" />


    The copy dont work because at first @(ReleaseFiles) is empty.

    Could somebody hep me?

  15. T L says:

    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:


    This single fiel I want copied to the following folder structure:







    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.


  16. Maor David says:

    I got today hysterical message from a good friend that implementing in his company automatic build with

  17. Photo by: mistyeiz A couple of weeks ago I had one hell of a time with an MSBuild script. I felt like

  18. Wout says:

    Doesn’t work for me, all files end up in the same dir. Shouldn’t you copy using DestinationFiles and a transform?

  19. Wout says:

    Ah, didn’t work because the folder was a UNC path. Looks like more people had that problem.

  20. David says:

    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>

  21. Patrick Martin says:

    I found that this corrected code did not work for me:

    <Copy SourceFiles="@(Compile)" DestinationFolder="c:foocopy%(RecursiveDir)%(Filename)%(Extension)"></Copy>

    This code produced the following error in the build log:

    …error MSB4094: <filelist> …is an invalid value for the "DestinationFolder" parameter of the "Copy" task. Multiple items cannot be passed into a parameter of type "Microsoft.Build.Framework.ITaskItem".

    Using Team Build 2008 the copy task needed to be changed as follows:

    <Copy SourceFiles="@(Compile)" DestinationFiles="c:foocopy%(RecursiveDir)%(Filename)%(Extension)"></Copy>

  22. Mihir says:

    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.


           <MySourceFiles Include="%ISDIR%add_dist***.*"/>


       <Target Name="CopyFiles">



               DestinationFolder="%ISDIR%mediadefaultdisk imagesDisk1"



  23. Vishrut says:

    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)"




    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

  24. stephen says:

    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?

  25. Simon Francesco says:

    Hi Team,

    Thanks this saved me some time. Could you guys please fix the msdn documentation at 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.



  26. David says:

    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?

  27. Tim Macfarlane says:

    The Bounce (…/bounce) build framework makes recursive directory copy pretty straightforward:…/CopyTask

  28. Jongilizwe Nicholas Gqozo says:

    What if I want to copy a folder, together with its contents?  That is irrecpective of their different extensions.