MSBuild String Manipulation Chaos

The other day, I was trying to split a string and then get the various parts of it from within an MSBuild project, but it went totally nuts on me. When I tried to access the item at a given index of the split result, I’d get nonsense including semicolons that weren’t there in the first place! Why are semicolons suddenly appearing in the result of a String Split when there were none in the original string?

Once I realized I should take this to the command line and break it down, it made a lot more sense and was quickly resolved (isn’t that usually the case?). I’m posting this so that maybe someone else will find it useful later.

The Goal

Imagine that you have a property that you want to split, and then rejoin all or some of the parts later. A build number seems like a good general example here. You’ve got access to String.Split here, so it seems a natural solution.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Split>$(BuildNumber.Split('.'))</Split>
  </PropertyGroup>
  
  <Target Name="Dump">
    <Message text="$(BuildNumber)" />
    <Message text="$(Split[0]).$(Split[1]).$(Split[2]).$(Split[3])" />
  </Target>
</Project>

I expected Split[0] to be 8, Split[1] to be 67, etc. What really happened was:

Dump:
8.67.5309.9001
8.;.6.7

Huh?

Where did that semicolon come from, and why do I get 6 and 7 instead of 67? I’ll admit I hacked and searched on this for way too long before turning to the old standby of “echo something out,” but once I did…

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Split>$(BuildNumber.Split('.'))</Split>
  </PropertyGroup>
  
  <Target Name="Dump">
    <Message text="$(BuildNumber)" />
    <Message text="$(Split)" />
  </Target>
</Project>

I got some very informative output…

Dump:
8.67.5309.9001
8;67;5309;9001

The Property Is A String

What is happening here is that the property that I’m creating is a string, not an array. It gets rejoined automatically, with semicolons as the delimiters. What I ended up doing was immediately capturing the chunks as separate properties.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Major>$(BuildNumber.Split('.')[0])</Major>
    <Minor>$(BuildNumber.Split('.')[1])</Minor>
    <Build>$(BuildNumber.Split('.')[2])</Build>
    <PowerLevel>$(BuildNumber.Split('.')[3])</PowerLevel>
  </PropertyGroup>
  
  <Target Name="Dump">
    <Message Condition="$(PowerLevel)&gt;9000" text="IT'S OVER 9000!" />
  </Target>
</Project>
Dump:
IT'S OVER 9000!

I’ve heard that there are some extensions out there that will split and assign to multiple properties a bit more fluidly, but this worked in a pinch. I’d be interested in hearing about other ways people have attacked this problem.

About David Ruttka

I've been "making computers do things" since I first saw King's Quest on a 286 PC in the mid-80's, but I turned it into a career just over a decade ago. While the majority of my experience has been on the Microsoft stack (C#, .NET, ASP.NET), I've recently been diving deeper into JavaScript and exploring the Ruby universe. Occasionally, I'll do a public speaking gig or write a blog post. When I'm not coding, I enjoy spending time with my family, watching hockey, and playing the occasional video game. You can also find me on Stack Overflow, Google Plus, and Twitter. Microsoft Certified Programming in HTML5 with JavaScript and CSS3 Specialist; MCPD Windows Developer 3.5
This entry was posted in Development, Stories. Bookmark the permalink.

2 Responses to MSBuild String Manipulation Chaos

  1. Hey How I can get the Size of the array for example if I have :

    config.test.con
    I want to get the number [2]

    • Anonymous says:

      Try $(YourArray.Length) … although wouldn’t it be 3 in your example? 2 would be the max index, but the size/length is 3.

Leave a reply to Anonymous Cancel reply