vRealize Automation and TFS integration

This post is going to be all about how we integrated TFS and vRA.  Particularly, there was this diagram I posted a couple weeks ago… I’ve had a few questions about how I did the following:

TFS Automated Builds

First off, please note that we run Chef BEFORE TFS… I know the above diagram would lead you to believe otherwise, but this isn’t a flowchart, its just an “x talks to y” kind of diagram.  I’d call it a dependency map if a) those words didn’t have particular connotations with respect to builds and b) if all the arrows on the diagram were actual dependencies.  Its very important that we run Chef first, though, because it is our Chef recipes that actually configure the server to be an application stack, add the deployment method toolkits if any, and to allow our build service accounts permission to deploy code to the server.

TFS API Programming

The money here is all in a few lines of code… backed up by tons of vendor code, of course!  Go ahead and create a new C# Console app, then you’re going to need references to the below.  If you don’t know how, just right-click the References folder in Solution Explorer and choose Add Reference…  These are added through choosing the dll’s you’ll find in C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\ (path may vary depending on your verson of Visual Studio and TFS)

  • Microsoft.TeamFoundation
  • Microsoft.TeamFoundation.Client
  • Microsoft.TeamFoundation.Common
  • Microsoft.TeamFoundation.Build
  • Microsoft.TeamFoundation.Build.Client
  • Microsoft.TeamFoundation.Build.Workflow
  • Microsoft.TeamFoundation.Build.Workflow.Activities
  • Microsoft.TeamFoundation.Build.Common
  • Microsoft.TeamFoundation.WorkItemTracking.Client

Then, edit Program.cs.  The following code does what we need (and even explains itself pretty well along the way!)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Build;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
using Microsoft.TeamFoundation.Build.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

using System.Security.Principal;

namespace QueueBuildWithParams
    class Program
        static void Main(string[] args)
            // args:
            // TeamProjectCollectionURL TeamProjectName BuildName Param=Value,Param=Value,…

            if (args.Length < 4)
                Console.WriteLine(“QueueBuildWithParams.exe TeamProjectCollectionURL TeamProjectName BuildName Param=Value,Param=Value,…”);
            Uri collectionUri = new Uri(args[0]);
            using (TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(collectionUri, System.Net.CredentialCache.DefaultNetworkCredentials, new UICredentialsProvider()))

                //log in the current user and ensure we got the right permissions…
                if (tfs.HasAuthenticated)
                        //Get the build server, create a new build request
                        IBuildServer buildServer = tfs.GetService(typeof(IBuildServer)) as IBuildServer;

                        IBuildDefinition buildDef = buildServer.GetBuildDefinition(args[1], args[2]);

                        IBuildRequest req = buildDef.CreateBuildRequest();

                        //Get the build parameters
                        var process = WorkflowHelpers.DeserializeProcessParameters(req.BuildDefinition.ProcessParameters);

                        //Parse the replacement parameters from the command line
                        string[] parameters = args[3].Split(new char[] { ‘,’ });

                        //set the parameters where found
                        foreach (string parameter in parameters)
                            string[] parsed = parameter.Split(new char[] { ‘=’ });
                            process[parsed[0]] = parsed[1];

                        //Re-serialize the parameters and queue the build
                        req.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);

                        IQueuedBuild myBuild = buildServer.QueueBuild(req);

One Bird, Two Stones

Throughout our development, we ended up with two different ways to call this automation; they’re both useful, and we’ve flip-flopped which way we prefer a few times.  I want to present both options to you because I don’t think either one is definitely THE best way to do it… BTW, both of these methods require you to have a service account that has login rights to the place you’re running the above code (more on that in a second), as well as the permissions required in TFS to actually queue the build(s) in question.  Which brings us to… where, exactly, do you want to run your code?

Jump Box

The first way we tried was to use a jump box.  Basically, we already had a VM we were using to run some powershell scripts we had to create to get around some limitations of the (vRO) AD plugin at the time.  The AD plugin has since been fixed, but once you have a jump box, well a lot of problems look like nails to that particular hammer, so we still have things we’re doing we can’t get rid of yet, and this is one of them…

Basically, I installed the QueueBuildWithParams program on it, and we use the “Run Script in Guest” workflow from COE to call it as appropriate.

Chef Recipe

The other option, and the one we’ll probably end up using long term, is to have a chef recipe that both installs and calls the QueueBuildWithParams program.  This does take an extra minute or two during a VM build, but allows us to remove an external dependency for success.  For my money, that’s the “right” decision to make, but that doesn’t mean what’s right for us is going to be right for you.  The Chef code we use is as below.  Please note that I had to create a setup and deployment project and add the output to the chef recipe’s “files” folder for this to work.  We already had a databag called “defaults” with a “Web_Deploy” item within it, where we store any constants needed for web deployments.

download_location = data_bag_item(“defaults”, “Web_Deploy”)[“download_location”]
teamName = node[‘team_name’]
branchName = node[‘branch_name’]
params = node[‘params’]

directory “#{download_location}” do
    action :create

cookbook_file “QBuild” do
    source “Queue Build With Params.msi”
    path “#{download_location}\\Queue Build With Params.msi”
    action :create

cookbook_file “QBuild cab” do
    source “Data1.cab”
    path “#{download_location}\\Data1.cab”
    action :create

windows_package ‘Queue Build With Params’ do
    package_name ‘Queue Build With Params’
    version ‘1.00.0000’
    source “#{download_location}\\Queue Build With Params.msi”
    options “/passive /quiet /norestart”
    action :install

windows_batch ‘Queue Build’ do
    code <<-EOH
        QueueBuildWithParams http://TFSFQDN:8080/tfs “#{node[‘team_name’]}” “#{node[‘build_name’]}” “#{node[‘params’]}” > C:\\chef\\batch.txt
    cwd “C:\\Program Files (x86)\\Inmar Enterprises, Inc\\Queue Build With Params\\”


We build up the parameters used from a combination of custom properties on the blueprint and custom scripting actions in vRO – basically, every build gets “ServersToBuild=vmname” added as a parameter by default.  If we’re creating an IIS server, we also add “,AppToDeploy=Website Name” – what this means is our developers have to have two parameters in their build, ServersToBuild and AppToDeploy, that will receive these values and customize their Automated Build workflow to use them.

Text Transform Template Technology (T4)

T4 is the final piece of the puzzle; a lot of the stuff we automate won’t be able to get all of its configuration details from the build parameters; especially with older .NET stuff, its going to be buried in .config files somewhere and not editable through build constants or just pointing MSDeploy at the right server… in those cases, we’re going to write the correct data out to a .xml file in a well known location before running the build.  Biggest downside to this mechanism is you can only have one build queued at a time; that’s a problem I’ll solve someday, surely, but for today the development teams are going to be warned about this limitation and asked to pay attention to their workflow to avoid it.

T4 basically let’s you write code in the middle of a text document, to be run at compile time.  This code can, in a very ASP (not-.NET) way, insert data directly into your text document.  Here’s the sample we’ve been using with development teams:

<#@ template debug=”false” hostspecific=”false” language=”C#” #>
<#@ assembly name=”System.Core” #>
<#@ assembly name=”System.Xml” #>
<#@ import namespace=”System.Linq” #>
<#@ import namespace=”System.Text” #>
<#@ import namespace=”System.Collections.Generic” #>
<#@ output extension=”.config” #>
System.Xml.XmlDocument configurationData = new System.Xml.XmlDocument();

<?xml version=”1.0″?>

For more information on how to configure your ASP.NET application, please visit

        <add key=”SomeConfiguration” value=”<#= configurationData.DocumentElement.GetElementsByTagName(“SomeConfiguration”)[0].InnerText #>” />
        <add key=”SomeOtherConfiguration” value=”<#= configurationData.DocumentElement.GetElementsByTagName(“SomeOtherConfiguration”)[0].InnerText #>” />
        <add key=”ConfigTime” value=”<#= System.DateTime.Now.ToString() #>” />


That’s it for today!  Post a comment, tell me what you liked or what needs more clarification on this concept, or just tell me you enjoyed my article!

As always, follow @merlinjim on twitter to be notified when I write new articles.


I've been automating everything I can get my hands on since I was a wee lad, these days its mostly Office, UC4, or VMWare - but I have a strong interest in AI, microfluidics, and 3D printing when I'm not slaving for "da man"

Tagged with: , , , , , ,
Posted in Automation, TFS, vRA

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

Head Shot of Jim

Jim McCracken

Enter your email address to follow this blog and receive notifications of new posts by email.

Follow me on Twitter
Past Posts
Automate The Cloud pages
%d bloggers like this: