Repeating a task for each item in a MSBuild item list is really easy if the task supports ; seperated lists, if not, well it's still easy but trying to remember the syntax is another matter!
This keeps catching me out and I've seen few examples of its use around so if for no other reason than as a reminder to myself here's how to iterate a list of items with MSBuild.
Define your item list as something like:
<InstallerFiles Include="$(MSBuildProjectDirectory)\Setup\**\Release\*.msi" />
In this example I have a folder .\Setup\ which contains multiple subfolders of different setup projects which generate msi files.
<Message Text="Copying installers to Build Output folder. Source = @(InstallerFiles)"/>
<Copy SourceFiles="@(InstallerFiles)" DestinationFolder="$(BuildOutputFolder)" />
This example copies all of the msi files into the BuildOutputFolder.
This method relies on the Copy target to accept a ; separated list of values. Sadly if you have a task that only takes a single value then your a little stuffed with the @ operator.
<Message Text="Copying installers to Build Output folder. Source = %(InstallerFiles.FullPath)"/>
<Copy SourceFiles="%(InstallerFiles.FullPath)" DestinationFolder="$(BuildOutputFolder)" />
This method will call the Copy task once for each item in the InstallerFiles list. But that's not really a fair example as you can just use the @ operator for Copy.
Here's another example that's more appropriate.
<SetupProjects Include="$(DeploymentLocalPath)**\*.vdproj" />
<!-- Some bits to set MSIVersion normally go here and have been removed for clarity →
<Exec Command='$(VersionUpdater) -msi "%(SetupProjects.FullPath)" version=$(MSIVersion)'/>
Here I use the VS.NET Deployment Project Version Updater (http://www.codeproject.com/KB/install/VersionVDProj.aspx) to update each of the setup projects with the MSIVersion number, but this could be any colsole application that took a filename.
The .FullPath is a Wellknown Item Metadata property. Theirs more listed on the MSDN page
Sara Ford also has an example of a good use of metadata for recursive copying (http://blogs.msdn.com/saraford/archive/2005/11/08/490445.aspx).
Theirs also an interesting MSBuild wiki over on Channel 9.