问题
I am trying to run multiple commands on a list of files based on a pattern (all files of form *.config under sub directories of a given directory), like so:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="BuildSolution" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="TransformXml"
      AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <TransformConfiguration>Release</TransformConfiguration>
    <PublishFolder>$(OutDir)_PublishedWebsites</PublishFolder>
  </PropertyGroup>
  <Target Name="BuildSolution">
    <MSBuild Projects="$(MSBuildProjectDirectory)\SolutionName.sln"
      ContinueOnError="false"
      Properties="PublishProfile=$(TransformConfiguration);DeployOnBuild=true" />
  </Target>
  <ItemGroup>
    <ConfigFiles Include="$(PublishFolder)\**\*.config" />
  </ItemGroup>
  <Target Name="TransformWebConfig" AfterTargets="BuildSolution" 
            Condition="'@(ConfigFiles)'!=''"
            Outputs="%(ConfigFiles.Identity)">
    <PropertyGroup>
      <ConfigFile>%(ConfigFiles.Identity)</ConfigFile>
      <BackupFile>$([System.IO.Path]::ChangeExtension($(ConfigFile),".Source.config"))</BackupFile>
      <TransformFile>$([System.IO.Path]::ChangeExtension($(ConfigFile),$(TransformConfiguration) + ".Source.config"))</TransformFile>
    </PropertyGroup>
    <Message Text="$(ConfigFile)" />
    <Message Text="$(BackupFile)" />
    <Message Text="$(TransformFile)" />
    <Copy SourceFiles="$(ConfigFile)"
          DestinationFiles="$(BackupFile)" />
    <Exec Command="attrib -r $(ConfigFile)" />
    <TransformXml Source="$(BackupFile)"
                  Transform="$(TransformFile)"
                  Destination="$(ConfigFile)"
                  StackTrace="false" />
  </Target>
</Project>
However, the batch processing of the matching files is not performed.
- From outputs I have added I see that the property $(PublishFolder)points to the correct directory, however, the item@(ConfigFiles)is left empty.
I also tried manually listing the directory names and configuration file names like so:
  <ItemGroup>
    <Sites Include="Site1" />
    <Sites Include="Site2" />
  </ItemGroup>
  <ItemGroup>
    <ConfigFiles Include="Web" />
    <ConfigFiles Include="NLog" />
  </ItemGroup>
  <Target Name="TransformWebConfig" AfterTargets="BuildSolution">
    <PropertyGroup>
      <SiteConfigFile>$(PublishFolder)\%(Sites.Identity)\%(ConfigFiles.Identity)</SiteConfigFile>
    </PropertyGroup>
    <Message Text="$(SiteConfigFile)" />
    <Copy SourceFiles="$(SiteConfigFile).config"
          DestinationFiles="$(SiteConfigFile).Source.config"/>
    <Exec Command="attrib -r $(SiteConfigFile).config" />
    <TransformXml Source="$(SiteConfigFile).Source.config"
                  Transform="$(SiteConfigFile).$(TransformConfiguration).config"
                  Destination="$(SiteConfigFile).config"
                  StackTrace="false" />
  </Target>
However, in this case, the transform is only applied on one file in one site.
Any idea what to do to get this working?
Similar questions and MSDN references I have gone through:
MSBUild: Copy files with a name based on the original (following a pattern)
MSBuild multiple outputpath
How to invoke the same msbuild target twice with different parameters from within msbuild project file itself
msbuild array iteration
http://msdn.microsoft.com/en-us/library/ms171454.aspx
Edit:
Moving the ItemGroup under the task enabled reading the file list after the files were created, however, now only the first file from the list is transformed:
<ItemGroup>
  <ConfigFiles Include="$(PublishFolder)\**\Web.config;$(PublishFolder)\**\NLog.config"
               Exclude="$(PublishFolder)\**\Packages.config;$(PublishFolder)\**\*.*.config;$(PublishFolder)\**\bin\*.config" />
</ItemGroup>
<PropertyGroup>
  <ConfigFile>%(ConfigFiles.Identity)</ConfigFile>
  <BackupFile>$([System.IO.Path]::ChangeExtension($(ConfigFile),".Source.config"))</BackupFile>
  <TransformFilePrefix>$([System.String]::Concat($(TransformConfiguration), ".config"))</TransformFilePrefix>
  <TransformFile>$([System.IO.Path]::ChangeExtension($(ConfigFile), $(TransformFilePrefix)))</TransformFile>
</PropertyGroup>
<Message Text="$(PublishFolder)" />
<Message Text="@(ConfigFiles)" />
<Message Text="$(ConfigFile)" />
<Message Text="$(BackupFile)" />
<Message Text="$(TransformFile)" />
<Copy SourceFiles="$(ConfigFile)"
      DestinationFiles="$(BackupFile)" />
<Exec Command="attrib -r $(ConfigFile)" />
<TransformXml Source="$(BackupFile)"
              Transform="$(TransformFile)"
              Destination="$(ConfigFile)"
              StackTrace="false" />
回答1:
Found the solution:
Create one target for creating the item group:
  <Target Name="ListWebConfigs" AfterTargets="BuildSolution">
    <ItemGroup>
      <ConfigFiles Include="$(PublishFolder)\**\Web.config;$(PublishFolder)\**\NLog.config"
                   Exclude="$(PublishFolder)\**\Packages.config;$(PublishFolder)\**\*.*.config;$(PublishFolder)\**\bin\*.config" />
    </ItemGroup>
    <Message Text="$(PublishFolder)" />
    <Message Text="@(ConfigFiles)" />
  </Target>
Then another for the actual transforms:
  <!-- \x to prevent MSBuild from skipping "because all output files are up-to-date" -->
  <Target Name="TransformWebConfig" AfterTargets="ListWebConfigs" Inputs="@(ConfigFiles)" Outputs="%(ConfigFiles.Identity)\x">
    <PropertyGroup>
      <ConfigFile>%(ConfigFiles.Identity)</ConfigFile>
      <BackupFile>$([System.IO.Path]::ChangeExtension($(ConfigFile),".Source.config"))</BackupFile>
      <TransformFilePrefix>$([System.String]::Concat($(TransformConfiguration), ".config"))</TransformFilePrefix>
      <TransformFile>$([System.IO.Path]::ChangeExtension($(ConfigFile), $(TransformFilePrefix)))</TransformFile>
    </PropertyGroup>
    <Message Text="$(PublishFolder)" />
    <Message Text="@(ConfigFiles)" />
    <Message Text="$(ConfigFile)" />
    <Message Text="$(BackupFile)" />
    <Message Text="$(TransformFile)" />
    <Copy SourceFiles="$(ConfigFile)" DestinationFiles="$(BackupFile)" />
    <Exec Command="attrib -r $(ConfigFile)" />
    <TransformXml Source="$(BackupFile)"
                  Transform="$(TransformFile)"
                  Destination="$(ConfigFile)"
                  StackTrace="false" />
  </Target>
来源:https://stackoverflow.com/questions/24614093/transforming-multiple-config-files-for-multiple-projects-via-msbuildproj-file