Who Got The Func Part 2: Property Functions in MSBuild

Not so long ago I posted about string manipulations in SQL. Seeing as I recently had to use the MSBuild property functions I thought it best to post a fairly advanced example of using the .Net property functions in MSBuild as most of the examples  I have found online are useful to no one. The kind of example I am talking about is found on the MSDN page:


$(ProjectOutputFolder.Substring(0,3))

It’s useful to know the syntax, but really not going to help me out in my scenario. Namely, one of the devs wanted to use the build number in the web config file of one of our solutions. Simple enough, however he did not want the build definition that prefixes the date and revision. Our build number format goes like this:


BuildNumberFormat = $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)

I had initially hoped to pass through just $(Date:yyyyMMdd)$(Rev:.r) into a Property, however whenever I did that I would get a build error stating that “The expression “Rev:.r” cannot be evaluated.”. Not to be deterred I knew that I could use the .Net property functions that were made available in MSBuild 4 to extract the date and revision number.

The challenge here was that the build definition is different for every build, so I couldn’t assume to start from a set position: I had to find the position.The first thing I did was create a new Target called Version Number. In this I created a property and added the $(BuildNumber) as its value.


<Target Name="VersionNumber">
<PropertyGroup>
<BuildNumberToSubString>$(BuildNumber)</BuildNumberToSubString>
</PropertyGroup>

I then created another property called AppVersionNumber. Here I would use the Property Functions to get the date and revision number.


<PropertyGroup>
<AppVersionNumber>$(BuildNumberToSubString.Substring($(BuildNumberToSubString.IndexOf('2')),$([MSBuild]::Subtract($(BuildNumberToSubString.length), $(BuildNumberToSubString.IndexOf('2'))))))</AppVersionNumber>
</PropertyGroup>

<Message Text="AppVersionNumber: $(AppVersionNumber)"/>
</Target>

Let’s go through that AppVersionNumber value one item at a time:

<AppVersionNumber>$(BuildNumberToSubString.Substring($(BuildNumberToSubString.IndexOf(‘2′)),

$([MSBuild]::Subtract($(BuildNumberToSubString.length), $(BuildNumberToSubString.IndexOf(‘2′))))))</AppVersionNumber>

Here I am referencing the BuildNumberToSubString Property above and that I am taking a substring of that. The first number I have to give is the starting value. As our BuildNumberFormat is $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r) I know that the first “2” I come across is going to be the year. Using the IndexOf function I am able to locate the first “2”. So it’s not the 2nd position of the string but rather the index of the first “2” that is going to be the starting point. So this will definitely stop working come the year 3000. I can live with that.

<AppVersionNumber>$(BuildNumberToSubString.Substring($(BuildNumberToSubString.IndexOf(‘2′)),

$([MSBuild]::Subtract($(BuildNumberToSubString.length), $(BuildNumberToSubString.IndexOf(‘2′))))))</AppVersionNumber>

For the second number, my finishing point, what I do here is find the length of my string, and then subtract from that the index of the first “2”, which again will be the year. So at the end of this I will end up with the value of the length of the date and revision. The value of the second number always has to be not the position in the entire string, but the length that you wish the substring to be.

Here is the target in it’s entirety:

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

<PropertyGroup>
 <BuildNumberToSubString>$(BuildNumber)</BuildNumberToSubString>
 </PropertyGroup>
 <PropertyGroup>
 <AppVersionNumber>$(BuildNumberToSubString.Substring($(BuildNumberToSubString.IndexOf('2')),$([MSBuild]::Subtract($(BuildNumberToSubString.length), $(BuildNumberToSubString.IndexOf('2'))))))</AppVersionNumber>
 </PropertyGroup>

<BuildStep Name="UpdateAppVersion"
 Message="AppVersionNumber: $(AppVersionNumber)"
 TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
 BuildUri="$(BuildURI)"
 Condition="'$(IsDesktopBuild)' != 'true'">
 <Output TaskParameter="Id"
 PropertyName="AppVersionNumberId" />
 </BuildStep>

<Message Text="AppVersionNumber: $(AppVersionNumber)"/>

<BuildStep Id="$(AppVersionNumberId)"
 Name="UpdateLocalTestSettings"
 TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
 BuildUri="$(BuildURI)"
 Condition="'$(IsDesktopBuild)' != 'true'"
 Status="Succeeded" />
 </Target>

</Project>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s