MSBuild items

MSBuild items are inputs into the build system, and they typically represent files (the files are specified in the Include attribute). Items are grouped into item types based on their element names. Item types are named lists of items that can be used as parameters for tasks. The tasks use the item values to perform the steps of the build process.

Because items are named by the item type to which they belong, the terms "item" and "item value" can be used interchangeably.

Create items in a project file

You declare items in the project file as child elements of an ItemGroup element. Valid item names begin with an uppercase or lowercase letter or underscore (_); valid subsequent characters include alphanumeric characters (letters or digits), underscore, and hyphen (-). The name of the child element is the type of the item. The Include attribute of the element specifies the items (files) to be included with that item type. For example, the following XML creates an item type that's named Compile, which includes two files.

<ItemGroup>
    <Compile Include = "file1.cs"/>
    <Compile Include = "file2.cs"/>
</ItemGroup>

The item file2.cs doesn't replace the item file1.cs; instead, the file name is appended to the list of values for the Compile item type.

The following XML creates the same item type by declaring both files in one Include attribute. Notice that the file names are separated by a semicolon.

<ItemGroup>
    <Compile Include = "file1.cs;file2.cs"/>
</ItemGroup>

The Include attribute is a path that is interpreted relative to the project file's folder, $(MSBuildProjectPath), even if the item is in an imported file such as a .targets file.

Create items during execution

Items that are outside Target elements are assigned values during the evaluation phase of a build. During the subsequent execution phase, items can be created or modified in the following ways:

  • Any task can emit an item. To emit an item, the Task element must have a child Output element that has an ItemName attribute.

  • The CreateItem task can emit an item. This usage is deprecated.

  • Starting in the .NET Framework 3.5, Target elements may contain ItemGroup elements that may contain item elements.

Reference items in a project file

To reference item types throughout the project file, you use the syntax @(<ItemType>). For example, you would reference the item type in the previous example by using @(Compile). By using this syntax, you can pass items to tasks by specifying the item type as a parameter of that task. For more information, see How to: Select the files to build.

By default, the items of an item type are separated by semicolons (;) when it's expanded. You can use the syntax @(<ItemType>, '<separator>') to specify a separator other than the default. For more information, see How to: Display an item list separated with commas.

Use wildcards to specify items

You can use the **, *, and ? wildcard characters to specify a group of files as inputs for a build instead of listing each file separately.

  • The ? wildcard character matches a single character.
  • The * wildcard character matches zero or more characters.
  • The ** wildcard character sequence matches a partial path.

For example, you can specify all the .cs files in the directory that contains the project file by using the following element in your project file.

<CSFile Include="*.cs"/>

The following element selects all .vb files on the D: drive:

<VBFile Include="D:/**/*.vb"/>

If you would like to include literal * or ? characters in an item without wildcard expansion, you must escape the wildcard characters.

For more information about wildcard characters, see How to: Select the files to build.

Use the Exclude attribute

Item elements can contain the Exclude attribute, which excludes specific items (files) from the item type. The Exclude attribute is typically used together with wildcard characters. For example, the following XML adds every .cs file in the directory to the CSFile item type, except the DoNotBuild.cs file.

<ItemGroup>
    <CSFile  Include="*.cs"  Exclude="DoNotBuild.cs"/>
</ItemGroup>

The Exclude attribute affects only the items that are added by the Include attribute in the item element that contains them both. The following example wouldn't exclude the file Form1.cs, which was added in the preceding item element.

<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">

For more information, see How to: Exclude files from the build.

Item metadata

Items may contain metadata in addition to the information in the Include and Exclude attributes. This metadata can be used by tasks that require more information about the items or to batch tasks and targets. For more information, see Batching.

Metadata is a collection of key-value pairs that are declared in the project file as child elements of an item element. The name of the child element is the name of the metadata, and the value of the child element is the value of the metadata.

The metadata is associated with the item element that contains it. For example, the following XML adds Culture metadata that has the value Fr to both the one.cs and the two.cs items of the CSFile item type.

<ItemGroup>
    <CSFile Include="one.cs;two.cs">
        <Culture>Fr</Culture>
    </CSFile>
</ItemGroup>

An item can have zero or more metadata values. You can change metadata values at any time. If you set metadata to an empty value, you effectively remove it from the build.

Reference item metadata in a project file

You can reference item metadata throughout the project file by using the syntax %(<ItemMetadataName>). If ambiguity exists, you can qualify a reference by using the name of the item type. For example, you can specify %(<ItemType.ItemMetaDataName>).The following example uses the Display metadata to batch the Message task. For more information about how to use item metadata for batching, see Item metadata in task batching.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <Stuff Include="One.cs" >
            <Display>false</Display>
        </Stuff>
        <Stuff Include="Two.cs">
            <Display>true</Display>
        </Stuff>
    </ItemGroup>
    <Target Name="Batching">
        <Message Text="@(Stuff)" Condition=" '%(Display)' == 'true' "/>
    </Target>
</Project>

Well-known item metadata

When an item is added to an item type, that item is assigned some well-known metadata. For example, all items have the well-known metadata %(<Filename>), whose value is the file name of the item (without the extension). For more information, see Well-known item metadata.

Transform item types by using metadata

You can transform item lists into new item lists by using metadata. For example, you can transform an item type CppFiles that has items that represent .cpp files into a corresponding list of .obj files by using the expression @(CppFiles -> '%(Filename).obj').

The following code creates a CultureResource item type that contains copies of all EmbeddedResource items with Culture metadata. The Culture metadata value becomes the value of the new metadata CultureResource.TargetDirectory.

<Target Name="ProcessCultureResources">
    <ItemGroup>
        <CultureResource Include="@(EmbeddedResource)"
            Condition="'%(EmbeddedResource.Culture)' != ''">
            <TargetDirectory>%(EmbeddedResource.Culture) </TargetDirectory>
        </CultureResource>
    </ItemGroup>
</Target>

For more operations on items, see MSBuild item functions and Transforms.

Item definitions

Starting in the .NET Framework 3.5, you can add default metadata to any item type by using the ItemDefinitionGroup element. Like well-known metadata, the default metadata is associated with all items of the item type that you specify. You can explicitly override default metadata in an item definition. For example, the following XML gives the Compile items one.cs and three.cs the metadata BuildDay with the value "Monday". The code gives the item two.cs the metadata BuildDay with the value "Tuesday".

<ItemDefinitionGroup>
    <Compile>
        <BuildDay>Monday</BuildDay>
    </Compile>
</ItemDefinitionGroup>
<ItemGroup>
    <Compile Include="one.cs;three.cs" />
    <Compile Include="two.cs">
        <BuildDay>Tuesday</BuildDay>
    </Compile>
</ItemGroup>

For more information, see Item definitions.

Attributes for items in an ItemGroup of a Target

Starting in the .NET Framework 3.5, Target elements may contain ItemGroup elements that may contain item elements. The attributes in this section are valid when they are specified for an item in an ItemGroup that's in a Target.

Remove attribute

The Remove attribute removes specific items (files) from the item type. This attribute was introduced in the .NET Framework 3.5 (inside targets only). Both inside and outside targets are supported starting in MSBuild 15.0.

The following example removes every .config file from the Compile item type.

<Target>
    <ItemGroup>
        <Compile Remove="*.config"/>
    </ItemGroup>
</Target>

MatchOnMetadata attribute

The MatchOnMetadata attribute is applicable only to Remove attributes that reference other items (for example, Remove="@(Compile);@(Content)") and instructs the Remove operation to match items based on the values of specified metadata names, instead of matching based on the item values.

Matching rule for B Remove="@(A)" MatchOnMetadata="M": remove all items from B that have metadata M, whose metadata value V for M matches any item from A with metadata M of value V.

<Project>
  <ItemGroup>
    <A Include='a1' M1='1' M2='a' M3="e"/>
    <A Include='b1' M1='2' M2='x' M3="f"/>
    <A Include='c1' M1='3' M2='y' M3="g"/>
    <A Include='d1' M1='4' M2='b' M3="h"/>

    <B Include='a2' M1='x' m2='c' M3="m"/>
    <B Include='b2' M1='2' m2='x' M3="n"/>
    <B Include='c2' M1='2' m2='x' M3="o"/>
    <B Include='d2' M1='3' m2='y' M3="p"/>
    <B Include='e2' M1='3' m2='Y' M3="p"/>
    <B Include='f2' M1='4'        M3="r"/>
    <B Include='g2'               M3="s"/>

    <B Remove='@(A)' MatchOnMetadata='M1;M2'/>
  </ItemGroup>

  <Target Name="PrintEvaluation">
    <Message Text="%(B.Identity) M1='%(B.M1)' M2='%(B.M2)' M3='%(B.M3)'" />
  </Target>
</Project>

In the above example, item values b2, c2, and d2 are removed from item B because:

  • b2 and c2 from B match against b1 from A on M1=2 and M2=x
  • d2 from B matches against c1 from A on M1=3 and M2=y

The Message task outputs the following:

  a2 M1='x' M2='c' M3='m'
  e2 M1='3' M2='Y' M3='p'
  f2 M1='4' M2='' M3='r'
  g2 M1='' M2='' M3='s'

Example usage of MatchOnMetadata from the msbuild common sdk:

      <_TransitiveItemsToCopyToOutputDirectory Remove="@(_ThisProjectItemsToCopyToOutputDirectory)" MatchOnMetadata="TargetPath" MatchOnMetadataOptions="PathLike" />

The above line removes items from _TransitiveItemsToCopyToOutputDirectory that have the same TargetPath metadata values from items in _ThisProjectItemsToCopyToOutputDirectory

MatchOnMetadataOptions attribute

Specifies the string matching strategy used by MatchOnMetadata for matching the metadata values between items (metadata names are always matched case insensitive). Possible values are CaseSensitive, CaseInsensitive, or PathLike. The default value is CaseSensitive.

PathLike applies path aware normalization to the values like normalizing slash orientations, ignoring trailing slashes, eliminating . and .., and making all relative paths absolute against the current directory.

KeepMetadata attribute

If an item is generated within a target, the item element can contain the KeepMetadata attribute. If this attribute is specified, only the metadata that is specified in the semicolon-delimited list of names will be transferred from the source item to the target item. An empty value for this attribute is equivalent to not specifying it. The KeepMetadata attribute was introduced in the .NET Framework 4.5.

The following example illustrates how to use the KeepMetadata attribute.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">

    <ItemGroup>
        <FirstItem Include="rhinoceros">
            <Class>mammal</Class>
            <Size>large</Size>
        </FirstItem>

    </ItemGroup>
    <Target Name="MyTarget">
        <ItemGroup>
            <SecondItem Include="@(FirstItem)" KeepMetadata="Class" />
        </ItemGroup>

        <Message Text="FirstItem: %(FirstItem.Identity)" />
        <Message Text="  Class: %(FirstItem.Class)" />
        <Message Text="  Size:  %(FirstItem.Size)"  />

        <Message Text="SecondItem: %(SecondItem.Identity)" />
        <Message Text="  Class: %(SecondItem.Class)" />
        <Message Text="  Size:  %(SecondItem.Size)"  />
    </Target>
</Project>

<!--
Output:
  FirstItem: rhinoceros
    Class: mammal
    Size:  large
  SecondItem: rhinoceros
    Class: mammal
    Size:
-->

RemoveMetadata attribute

If an item is generated within a target, the item element can contain the RemoveMetadata attribute. If this attribute is specified, all metadata is transferred from the source item to the target item except metadata whose names are contained in the semicolon-delimited list of names. An empty value for this attribute is equivalent to not specifying it. The RemoveMetadata attribute was introduced in the .NET Framework 4.5.

The following example illustrates how to use the RemoveMetadata attribute.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <MetadataToRemove>Size;Material</MetadataToRemove>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item2 Include="@(Item1)" RemoveMetadata="$(MetadataToRemove)" />
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)" />
        <Message Text="  Size:     %(Item1.Size)" />
        <Message Text="  Color:    %(Item1.Color)" />
        <Message Text="  Material: %(Item1.Material)" />
        <Message Text="Item2: %(Item2.Identity)" />
        <Message Text="  Size:     %(Item2.Size)" />
        <Message Text="  Color:    %(Item2.Color)" />
        <Message Text="  Material: %(Item2.Material)" />
    </Target>
</Project>

<!--
Output:
  Item1: stapler
    Size:     medium
    Color:    black
    Material: plastic
  Item2: stapler
    Size:
    Color:    black
    Material:
-->

For more operations on items, see MSBuild item functions.

KeepDuplicates attribute

If an item is generated within a target, the item element can contain the KeepDuplicates attribute. KeepDuplicates is a Boolean attribute that specifies whether an item should be added to the target group if the item is an exact duplicate of an existing item.

If the source and target item have the same Include value but different metadata, the item is added even if KeepDuplicates is set to false. An empty value for this attribute is equivalent to not specifying it. The KeepDuplicates attribute was introduced in the .NET Framework 4.5.

The following example illustrates how to use the KeepDuplicates attribute.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <ItemGroup>
        <Item1 Include="hourglass;boomerang" />
        <Item2 Include="hourglass;boomerang" />
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item1 Include="hourglass" KeepDuplicates="false" />
            <Item2 Include="hourglass" />
        </ItemGroup>

        <Message Text="Item1: @(Item1)" />
        <Message Text="  %(Item1.Identity)  Count: @(Item1->Count())" />
        <Message Text="Item2: @(Item2)" />
        <Message Text="  %(Item2.Identity)  Count: @(Item2->Count())" />
    </Target>
</Project>

<!--
Output:
  Item1: hourglass;boomerang
    hourglass  Count: 1
    boomerang  Count: 1
  Item2: hourglass;boomerang;hourglass
    hourglass  Count: 2
    boomerang  Count: 1
-->

Updating metadata on items in an ItemGroup outside of a Target

Items outside of targets can have their existing metadata updated via the Update attribute. This attribute is not available for items under targets.

<Project>
    <PropertyGroup>
        <MetadataToUpdate>pencil</MetadataToUpdate>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Color>red</Color>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="notebook">
            <Size>SMALL</Size>
            <Color>YELLOW</Color>
        </Item2>

        <!-- Metadata can be expressed either as attributes or as elements -->
        <Item1 Update="$(MetadataToUpdate);stapler;er*r;@(Item2)" Price="10" Material="">
            <Color>RED</Color>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: medium
    Color: RED
    Material:
    Price: 10
Item1: pencil
    Size: small
    Color: RED
    Material:
    Price: 10
Item1: eraser
    Size:
    Color: RED
    Material:
    Price: 10
Item1: notebook
    Size: large
    Color: RED
    Material:
    Price: 10
-->

Updating metadata on items in an ItemGroup of a Target

Metadata can be modified inside targets too, by a less expressive syntax than Update:

<Project>
    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Size>small</Size>
            <Color>red</Color>
            <Material>gum</Material>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="pencil">
            <Size>MEDIUM</Size>
            <Color>RED</Color>
            <Material>PLASTIC</Material>
            <Price>10</Price>
        </Item2>

        <Item2 Include="ruler">
            <Color>GREEN</Color>
        </Item2>

    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <!-- Metadata can be expressed either as attributes or as elements -->
            <Item1 Size="GIGANTIC" Color="%(Item2.Color)">
                <Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
            </Item1>
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)
    Model: %(Item1.Model)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: pencil
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: eraser
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: notebook
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
-->

See also