Here's an MSBuild script:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="AugmentItemGroup" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<ItmGrp Include="File1.txt">
<Dest>dest\%(FileName)%(Extension)</Dest>
</ItmGrp>
<ItmGrp Include="File2.txt">
<Dest>dest\%(FileName)%(Extension)</Dest>
</ItmGrp>
<ItmGrp Include="File3.txt">
<Dest>dest\%(FileName)%(Extension)</Dest>
</ItmGrp>
</ItemGroup>
<Target Name="AugmentItemGroup">
<ItemGroup>
<ItmGrp Include="File4.txt">
<Dest>dest\%(FileName)%(Extension)</Dest>
</ItmGrp>
</ItemGroup>
<Message Text="%(ItmGrp.FullPath) to %(ItmGrp.Dest)" />
</Target>
</Project>
The output I would expect from it is:
D:\t\File1.txt to dest\File1.txt
D:\t\File2.txt to dest\File2.txt
D:\t\File3.txt to dest\File3.txt
D:\t\File4.txt to dest\File4.txt
But the result is:
D:\t\File1.txt to dest\File1.txt
D:\t\File2.txt to dest\File2.txt
D:\t\File3.txt to dest\File3.txt
D:\t\File4.txt to dest\File1.txt
D:\t\File4.txt to dest\File2.txt
D:\t\File4.txt to dest\File3.txt
Why is the behavior of the %(FileName)%(Extension)
well-known metadata reference is different when an ItemGroup is inside a target?
Is it possible to get the "outside a target" behavior inside a target?
This will give the output you desire. Though it may not be the correct approach in the general case, it does avoid the batching that occurs with "File4" by making the custom metadata a part of the item definition that is calculated:
<Project
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="AugmentItemGroup"
ToolsVersion="4.0">
<ItemDefinitionGroup>
<ItmGrp>
<Dest>dest\%(FileName)%(Extension)</Dest>
</ItmGrp>
</ItemDefinitionGroup>
<ItemGroup>
<ItmGrp Include="File1.txt" />
<ItmGrp Include="File2.txt" />
<ItmGrp Include="File3.txt" />
</ItemGroup>
<Target Name="AugmentItemGroup">
<ItemGroup>
<ItmGrp Include="File4.txt" />
</ItemGroup>
<Message Text="%(ItmGrp.FullPath) to %(ItmGrp.Dest)" />
</Target>
</Project>
edit:
If (as your comment below says) each item has a different value for %(Dest), you just need to make the final value calculated:
<Project ...>
<ItemDefinitionGroup>
<ItmGrp>
<_Dest />
</ItmGrp>
</ItemDefinitionGroup>
<ItemGroup>
<ItmGrp Include="File1.txt"><Dest>dest1</Dest></ItmGrp>
<ItmGrp Include="File2.txt"><Dest>dest2</Dest></ItmGrp>
<ItmGrp Include="File3.txt"><Dest>dest3</Dest></ItmGrp>
</ItemGroup>
<Target Name="AugmentItemGroup">
<ItemGroup>
<ItmGrp Include="File4.txt"><Dest>dest4</Dest></ItmGrp>
<ItmGrp>
<_Dest>%(Dest)\%(FileName)%(Extension)</_Dest>
</ItmGrp>
</ItemGroup>
<Message Text="%(ItmGrp.FullPath) to %(ItmGrp._Dest)" />
</Target>
</Project>
Excerpted from MSBuild Trickery tricks #70, 71