MSbuild Copy whole folder

trying to copy a whole folder, but when i do this:

<Copy SourceFiles="$(TargetDir)\*.*" DestinationFolder="$(BuildOutput)\SomeDir" />

the copy attempts to do this: copy c:\source\*.* c:\destination\SomeDir\*.* and fails with "illegal characters"


Solution 1:

Specify your ItemGroup for SourceFiles explicitly.

<ItemGroup>
    <_CopyItems Include="$(TargetDir)\*.*" />
</ItemGroup>
<Copy
    SourceFiles="@(_CopyItems)"
    DestinationFolder="$(BuildOutput)\SomeDir"
    />

Note that _CopyItems is an item type, so it's referenced using '@' symbol rather than '$'.

Solution 2:

Copying files can be done with the following code snippet which handles antivirus programs and subdirectories

  <ItemGroup>
        <SomeAppStuff Include="$(SolutionDir)\ProjectXXX\bins\**\*.*" />
  </ItemGroup>
  <Copy 
      SourceFiles="@(SomeAppStaff)" 
      DestinationFolder="$(OutputPath)\%(RecursiveDir)" 
      SkipUnchangedFiles="true"
      OverwriteReadOnlyFiles="true" 
      Retries="3"
      RetryDelayMilliseconds="300"/>

Specifying $(OutputPath)\%(RecursiveDir) will ask Copy task to respect subfolders, so it will place subfolders of source directory to subfolders of target directories.

SkipUnchangedFiles will increase build speed on computers with enough memory, because Windows optimizes IO for frequently used files when there's enough RAM.

Retries and RetryDelayMilliseconds handles issues related a) Compressed NTFS file system, when builds fails in seldom cases b) Antivirus Software with SSD drives.

Solution 3:

If you put the folder in the root of your c# project then you can simple put this in your csproj.

<ItemGroup>
    <None Update="FolderToCopy\**\*.*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
</ItemGroup>

I have only tested in the 2017 version of csproj, but I assume it's backwards compatible. Could be wrong on that though

Solution 4:

Looking at the MSDN documentation, I believe the SourceFiles parameter requires an ITaskItem[] value. See MSDN MSBuild Copy Task

The last example on the above link is to do a recursive copy from one directory to another, maintaining the folder structure.

Solution 5:

Succeeded to accomplish this task like this

<Target Name="AfterBuild">
  <ItemGroup>
    <SomeDir Include="$(SolutionDir)\SomeOtherProject\SomeDir\**\*" />
  </ItemGroup>
  <Copy 
    SourceFiles="@(SomeDir)" 
    DestinationFiles="@(SomeDir->'$(OutDir)\SomeDir\%(RecursiveDir)%(Filename)%(Extension)')" 
    SkipUnchangedFiles="true" 
    OverwriteReadOnlyFiles="true" 
    Retries="3" 
    RetryDelayMilliseconds="300" />