 <p>When you specify the DestinationFolder for the Copy task, it takes all items from the SourceFiles collection and copies them to the DestinationFolder. This is expected, as there is no way for the Copy task to figure out what part of each item's path needs to be replaced with the DestinationFolder in order to keep the tree structure. For example, if your SourceDir collection is defined like this:</p> <pre><code>&lt;ItemGroup&gt; &lt;SourceDir Include="$(Source)\**\*" /&gt; &lt;SourceDir Include="E:\ExternalDependencies\**\*" /&gt; &lt;SourceDir Include="\\sharedlibraries\gdiplus\*.h" /&gt; &lt;/ItemGroup&gt; </code></pre> <p>What would you expect the destination folder tree look like?</p> <p>To preserve the tree, you need to do identity transformation and generate one destination item for each item in the SourceFiles collection. Here's an example:</p> <pre><code>&lt;Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile-&gt;'$(DropPath)%(Identity)')" /&gt; </code></pre> <p>The Copy task will take the each item in the SourceFiles collection, and will transform its path by replacing the part before the ** in the source item specification with $(DropPath).</p> <p>One could argue that the DestinationFolder property should have been written as a shortcut to the following transformation:</p> <pre><code>&lt;Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile-&gt;'$(DestinationFolder)%(Identity)')" /&gt; </code></pre> <p>Alas, that would prevent the deep copy to flat folder scenario that you are trying to avoid, but other people might using in their build process.</p>