Replicating Folder Structures in New Environments with MSBuild

I recently received the task of modifying an existing MSBuild script to copy configuration files from one location to another while preserving all but the top levels of their original folder structure.  Completing this task required a refresher in MSBuild well-known metadata and task batching (among other things), so I’m recounting my process here for future reference.

The config files that needed copying were already collected into an item via a CreateItem task.  Since we’re using MSBuild 4.0 though, I replaced it with the simpler ItemGroup.  CreateItem has been deprecated for awhile, but can still be used.  There is a bit of debate over the precise differences between CreateItem and ItemGroup, but for me the bottom line is the same (or superior) functionality with less XML.

Creating a new folder on the fly is easy enough with the MakeDir task.  There’s no need to manually check whether or not the directory you’re trying to create already exists or not.  The task just works.

The trickiest part of  this task was figuring out what combination of well-known metadata needed to go in the DestinationFiles attribute of the Copy task to achieve the desired result.  The answer ended up looking like this:

<Copy SourceFiles="@(ConfigFiles)" DestinationFiles="$(OutDir)_Config\$(Environment)\%(ConfigFiles.RecursiveDir)%(ConfigFiles.Filename)%(ConfigFiles.Extension)" />

The key bit of metadata is the RecursiveDir part.  Since the ItemGroup that builds the file collection uses the ** wildcard, and it covered all the original folder structure I needed, putting after the new “root” destination and before the file names gave me the result I wanted.  Another reason that well-known metadata was vital to the task is that all the files have the same name (Web.config), so the easiest way to differentiate them for the purpose of copying was their location in the folder structure.

In addition to the links above, this book by Sayed Ibrahim Hashimi was very helpful.  In a previous job where configuration management was a much larger part of my role, I referred to it (and on a daily basis.