I had to write a custom task to do this:
Here is how it works
<ItemGroup>
<ItemsToChange Include="@(SolutionToBuild)">
<Properties>ChangedValue</Properties>
</ItemsToChange>
<MetaDataToChange Include="Properties"/>
</ItemGroup>
<UpdateMetadata SourceList="@(SolutionToBuild)" ItemsToModify="@(ItemsToChange)" MetadataToModify="@(MetaDataToChange)">
<Output TaskParameter="NewList" ItemName="SolutionToBuildTemp" />
</UpdateMetadata>
<ItemGroup>
<SolutionToBuild Remove="@(SolutionToBuild)"/>
<SolutionToBuild Include ="@(SolutionToBuildTemp)"/>
</ItemGroup>
It fills a new item called SolutionToBuildTemp with the changed value. I then remove everything in the SolutionToBuild item and fill it iwith the SolutionToBuildTemp item.
Here is the code for the task if anyone is interested (I did submit it to the MSBuildExtenstionPack too).
// By Stephen Schaff (Vaccano).
// Free to use for your code. Need my Permission to Sell it.
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace UpdateMetadata
{
///<summary>
/// Used to update the metadata in a ItemGroup (Note: Requires an MSBuild Call After using this task to complete the update. See Usage.)
/// Usage:
/// <?xml version="1.0" encoding="utf-8"?>
///<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Testing" ToolsVersion="3.5">
///
/// <!-- Do not edit this -->
/// <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
/// <UsingTask AssemblyFile="C:\Base\Junk\UpdateMetadata\UpdateMetadata\bin\Debug\UpdateMetadata.dll" TaskName="UpdateMetadata"/>
///
///
/// <!--Re-setup the solutions to build definition-->
/// <ItemGroup>
/// <SolutionToBuild Include="$(BuildProjectFolderPath)\ChangeThisOne.sln">
/// <Properties>Change</Properties>
/// </SolutionToBuild>
/// <SolutionToBuild Include="$(BuildProjectFolderPath)\ChangeThisToo.sln">
/// <Properties>Change</Properties>
/// </SolutionToBuild>
/// <SolutionToBuild Include="$(BuildProjectFolderPath)\DontChangeThisOne.sln">
/// <Properties>Don'tChange</Properties>
/// </SolutionToBuild>
/// </ItemGroup>
///
/// <Target Name="Testing">
/// <Message Text="Before = %(SolutionToBuild.Identity) %(SolutionToBuild.Properties)" />
///
/// <ItemGroup>
/// <ItemsToChange Include="@(SolutionToBuild)">
/// <Properties>ChangedValue</Properties>
/// </ItemsToChange>
///
/// <ItemsToChange Remove="%(ItemsToChange.rootdir)%(ItemsToChange.directory)DontChangeThisOne%(ItemsToChange.extension)"/>
/// </ItemGroup>
///
/// <ItemGroup>
/// <MetaDataToChange Include="Properties"/>
/// </ItemGroup>
///
/// <UpdateMetadata SourceList="@(SolutionToBuild)" ItemsToModify="@(ItemsToChange)" MetadataToModify="@(MetaDataToChange)">
/// <Output TaskParameter="NewList" ItemName="SolutionToBuildTemp" />
/// </UpdateMetadata>
///
/// <ItemGroup>
/// <SolutionToBuild Remove="@(SolutionToBuild)"/>
/// <SolutionToBuild Include ="@(SolutionToBuildTemp)"/>
/// </ItemGroup>
///
/// <Message Text="After = %(SolutionToBuild.Identity) %(SolutionToBuild.Properties)"/>
/// </Target>
///</Project>
///</summary>
public class UpdateMetadata : Task
{
///<summary>
/// The list to modify.
///</summary>
[Required]
public ITaskItem[] SourceList { get; set; }
///<summary>
/// Items in <see cref="SourceList"/> to change the Metadata for.
/// It should have the valid metadata set.
///</summary>
[Required]
public ITaskItem[] ItemsToModify { get; set; }
///<summary>
/// List of metadata to modify. This is an item group, but any metadata in it is ignored.
///</summary>
public ITaskItem[] MetadataToModify { get; set; }
///<summary>
/// If true then info about the update is output
///</summary>
public Boolean OutputMessages { get; set; }
///<summary>
/// Changed List. If you call the following it can replace the <see cref="SourceList"/>:
///</summary>
[Output]
public ITaskItem[] NewList { get; set; }
///<summary>
/// Runs the task to output the updated version of the property
///</summary>
///<returns></returns>
public override bool Execute()
{
// If we got empty params then we are done.
if ((SourceList == null) || (ItemsToModify == null) || (MetadataToModify == null))
{
Log.LogMessage("One of the inputs to ModifyMetadata is Null!!!", null);
return false;
}
if (OutputMessages)
Log.LogMessage(MessageImportance.Low, "Beginning Metadata Changeover", null);
int sourceIndex = 0;
foreach (ITaskItem sourceItem in SourceList)
{
// Fill the new list with the source one
NewList = SourceList;
foreach (ITaskItem itemToModify in ItemsToModify)
{
// See if this is a match. If it is then change the metadat in the new list
if (sourceItem.ToString() == itemToModify.ToString())
{
foreach (ITaskItem metadataToModify in MetadataToModify)
{
try
{
if (OutputMessages)
Log.LogMessage(MessageImportance.Low, "Changing {0}.{1}",
NewList[sourceIndex].ToString(), metadataToModify.ToString());
// Try to change the metadata in the new list.
NewList[sourceIndex].SetMetadata(metadataToModify.ToString(),
itemToModify.GetMetadata(metadataToModify.ToString()));
}
catch (System.ArgumentException exception)
{
// We got some bad metadata (like a ":" or something).
Log.LogErrorFromException(exception);
return false;
}
}
}
}
sourceIndex += 1;
}
return true;
}
}
}
I hope this is useful to some one, but the code is obviously "Use at your own risk".
Vaccano