Calling a task with a list of files in MSBuild

November 3, 2007

MSBuild tasks can handle a list of files in several ways. Many of them will take them all in one go, through a single attribute. The list comes through as ITaskItem[] inside the task itself. We may not always want to call the task in this way, and not all support this. In some scenarios we might want to call the task once for each file.

Lets start by creating an itemgroup that defines all our files. Were going to give it the Name MyFiles and we’ll use a wildcard on the include attribute to select all the files in a directory.

<ItemGroup>
    <MyFiles Include="C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\*"/>
</ItemGroup>

A lot of targets in MSBuild can take a list seperated by semicolons. the CSC task for the C# compiler can take a list of source files in this way. To pass our list of files in this way we use the @(itemgroup) syntax, like this:

<Message Importance="normal" Text="@(MyFiles)"/>

In this example with the message task we our passing a single string with all our filenames seperated by semicolons.

Often what we actually want to do is call the task once for every file in the itemgroup. To do this we use the %(itemgroup.itemmetadata) syntax. In our itemgroup we haven’t defined any item metadata, fortunately msbuild provides some well known item metadata for us automatically. This includes such things as the file name, path, extension.

<Message Importance="normal" Text="%(MyFiles.FullPath)"/>        

Here we will call the message task once for every file and we will pass the full path.

The whole msbuild file:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <MyFiles Include="C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\*"/>
    </ItemGroup>
        
    <Target Name="Build">
        <!--Pass all in one call ';' seperated-->        
        <Message Importance="normal" Text="@(MyFiles)"/>

        <!--Call Target once for each file-->
        <Message Importance="normal" Text="%(MyFiles.FullPath)"/>        
    </Target>    
</Project>

When we run it with msbuild, we firstly get the output from the first call to the message task which received the text as a single string seperated by ‘;’. After this we have the output where it called the message target once for each file.

__________________________________________________
Project “C:\Temp\multiple.xml” (default targets):

Target Build:
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\alinkui.dll;C:\Windows\Mi
crosoft.NET\Framework\v2.0.50727\1033\cscompui.dll;C:\Windows\Microsoft.NET\Fram
ework\v2.0.50727\1033\CvtResUI.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727
\1033\vbc7ui.dll;C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjscui.dll;C
:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjslibui.dll;C:\Windows\Micros
oft.NET\Framework\v2.0.50727\1033\Vsavb7rtUI.dll

    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\alinkui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\cscompui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\CvtResUI.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vbc7ui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjscui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\vjslibui.dll
    C:\Windows\Microsoft.NET\Framework\v2.0.50727\1033\Vsavb7rtUI.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.05

Leave a comment