Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3841552
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 19, 20262026-05-19T15:40:08+00:00 2026-05-19T15:40:08+00:00

I am attempting to write a build script for our source tree. This tree

  • 0

I am attempting to write a build script for our source tree. This tree consists of a (large) number of solutions with assembly references between them. I have created an ItemGroup containing all the solutions and am batching over this ItemGroup to build the solutions.

I also need to copy some project outputs to an “exes output” folder, each in their own folder. I’ve attached some metadata to the solution item pointing to the projects that I want to grab the output from. As I can have potentially more than one project to output from each solution, I am doing this by giving the metadata the value that is passed to an ItemGroup’s Include to create an ItemGroup separately. This works happily and I am able to batch over this dynamically created ItemGroup.

The final step I want to do, which is causing me a headache, is that for some of those output projects, I want to specify a special folder name. Now, I can do this by altering the metadata inside the target that is doing the work, like this:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         DefaultTargets="Build">

  <!-- Define all the solutions to build, and any projects we want to handle the output of -->
  <ItemGroup>

    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln">
      <ProjectsToOutput>
        $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj;
        $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj;
      </ProjectsToOutput>
    </SolutionsToBuild>
    <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln">
      <ProjectsToOutput>
        $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj;
        $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj;
      </ProjectsToOutput>
    </SolutionsToBuild>

  </ItemGroup>

  <Target Name="Build">

    <CallTarget Targets="DoBuild" />

  </Target>

  <Target Name="DoBuild" Outputs="%(SolutionsToBuild.Identity)">

    <Message Text="Building project: %(SolutionsToBuild.FullPath)" />
    <!-- e.g. <MSBuild Projects="%(SolutionsToBuild.FullPath)" /> -->

    <PropertyGroup>
      <ProjectsToOutputIncludeMask>%(SolutionsToBuild.ProjectsToOutput)</ProjectsToOutputIncludeMask>
    </PropertyGroup>

    <ItemGroup>
      <OutputProjects Include="$(ProjectsToOutputIncludeMask)" />

      <!-- Now create the OutputTo metadata -->
      <!-- Default to the same name as the project file -->
      <OutputProjects>
        <OutputTo>%(OutputProjects.FileName)</OutputTo>
      </OutputProjects>

      <!-- Now override specific projects OutputTo metadata -->
      <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project1A'">
        <OutputTo>ArbitraryFolder1</OutputTo>
      </OutputProjects>
      <OutputProjects Condition="'%(OutputProjects.FileName)' == 'Project2B'">
        <OutputTo>ArbitraryFolder2</OutputTo>
      </OutputProjects>

    </ItemGroup>

    <Message Text=" Outputting project: %(OutputProjects.FullPath) -> %(OutputTo)" />

  </Target>      
</Project>

However, this build script needs to be maintained by all developers on the team, not all of whom are familiar with MSBuild. Therefore, I’d like to define another ItemGroup at the top of the script that defines any special names. They can then ignore all the targets and tasks and just maintain the ItemGroups, like this:

<ItemGroup>

  <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution1\Solution1.sln">
    <ProjectsToOutput>
      $(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj;
      $(MSBuildProjectDirectory)\Solution1\Project1B\Project1B.csproj;
    </ProjectsToOutput>
  </SolutionsToBuild>
  <SolutionsToBuild Include="$(MSBuildProjectDirectory)\Solution2\Solution2.sln">
    <ProjectsToOutput>
      $(MSBuildProjectDirectory)\Solution2\Project2A\Project2A.csproj;
      $(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj;
    </ProjectsToOutput>
  </SolutionsToBuild>

  <OutputNames Include="Project1A">
    <OutputFolder>ArbitraryFolder1</OutputFolder>
  </OutputNames>
  <OutputNames Include="Project2B">
    <OutputFolder>ArbitraryFolder2</OutputFolder>
  </OutputNames>

</ItemGroup>

However, any way I’ve tried to get the DoBuild target to update the metadata falls on its face. I thought I could do this:

  <!-- Now override specific projects OutputTo metadata -->
  <OutputProjects Condition="'%(OutputProjects.FileName)' == '%(OutputNames.Identity)'">
    <OutputTo>%(OutputNames.OutputFolder)</OutputTo>
  </OutputProjects>

But that code batches over The OutputProjects item group and then over the OutputNames item group, so the condition is never true (one of the arguments to the comparison is always empty).

I’m unfortunately, at this stage, unable to change either the solution structure or the output folder structure requirements. Is there any trick of MSBuild that I’m missing that could help me here? I’m not averse to including a custom task to do the job, but would prefer a straight MSBuild solution if possible.

If it makes a difference, I am using MSBuild v4.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-19T15:40:08+00:00Added an answer on May 19, 2026 at 3:40 pm

    Ah. Stumbled on an answer whilst playing around with this.

    Firstly, I was investigating this post about getting the intersection of two item groups. I therefore changed my OutputNames item group to have the same Identity as the OutputProjects ItemGroup:

    <OutputNames Include="$(MSBuildProjectDirectory)\Solution1\Project1A\Project1A.csproj">
      <OutputFolder>ArbitraryFolder1</OutputFolder>
    </OutputNames>
    <OutputNames Include="$(MSBuildProjectDirectory)\Solution2\Project2B\Project2B.csproj">
      <OutputFolder>ArbitraryFolder2</OutputFolder>
    </OutputNames>
    

    This let me batch on %(Identity) and get the intersection like this:

    <Message Condition="'%(Identity)' != '' and
             '@(OutputProjects)' != '' and
             '@(OutputNames)' != ''"
             Text="Found a match for %(Identity)" />
    

    However, when also referring to the OutputFolder metadata in the same Task, that became part of the batching as well resulting in the following never printing to the output:

    <Message Condition="'%(Identity)' != '' and
             '@(OutputProjects)' != '' and
             '@(OutputNames)' != ''"
             Text="Found a match for %(Identity): %(OutputNames.OutputFolder)" />
    

    But, by using a transform over the property instead of direct access, it isn’t treated as part of the batching:

    <Message Condition="'%(Identity)' != '' and
             '@(OutputProjects)' != '' and
             '@(OutputNames)' != ''"
             Text="Found a match for %(Identity): @(OutputNames->'%(OutputFolder)')" />
    

    Therefore, I can do the following to update my metadata:

      <!-- Now override specific projects OutputTo metadata -->
      <OutputProjects Condition="'%(Identity)' != '' AND
                                 '@(OutputProjects)' != '' AND
                                 '@(OutputNames)' != ''">
        <OutputTo>@(OutputNames->'%(OutputFolder)')</OutputTo>
      </OutputProjects>
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am attempting to write a one-line Perl script that will toggle a line
I am attempting to write a launchd script that runs once a day, on
I've been attempting to write a Lisp macro that would perfom the equivalent of
I am attempting to write an application that uses libCurl to post soap requests
I'm attempting to write a Python C extension that reads packed binary data (it
I have been attempting to write some routines to read RSS and ATOM feeds
I am attempting to write a component in C# to be consumed by classic
I am attempting to write a .NET component. The component will be dropped onto
I've written a web service using ASP.NET (in C#) and I'm attempting to write
Currently trying to build a script utilizing cmdlets from the MS released Team Foundation

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.