Learn to use Visual Studio, Visual Studio Online, Application Insights and Team Foundation Server to decrease rework, increase transparency into your application and increase the rate at which you can ship high quality software throughout the application lifecycle

Get started with some basic TFBuild scripts

You want to run some of your business logic during your TFBuild process. Maybe before, or maybe after Team Foundation Build (TFBuild) compiles or tests your code. For example, before you compile, you want to set the version of your assembly files. Or after you compile, you want to control the build outputs that get dropped to your staging location.

Until recently, you would have to customize your build process. Plenty has been written about how to develop a custom build process. I recently released a topic that I hope makes getting started on this kind of effort a bit easier: Create a custom build process. Regardless, developing and using custom build process activities of any complexity can be tricky and requires a learning curve.

What if you just want to run a simple batch (.bat) file? Or maybe you need a bit more power and you want to run a PowerShell script, perhaps to leverage even a bit of .Net code. Well, I'm here to share some good news: with Visual Studio and Team Foundation Server 2013 you can do it! In fact, to help you kick off your adventure in TFBuild scripting, following are a few examples you can literally copy, paste, and check in to your team project and use today.

As you can see, the following build definition is based on the default template; no customizations up my sleeve:

Before you begin using these scripts, a few bits about how they work:

ApplyVersionToAssemblies

The Build number format is set to provide the script with the version data it needs in 0.0.0.0 form, as shown above.

The script applies the version data to your AssemblyInfo files so that it is stamped on the binaries when they are compiled.

GatherItemsForDrop

Output location is set to AsConfigured so that the script controls what output files are dropped later in the build process.

After the code is compiled, the script copies binaries from the source folder to the binaries folder so that these files can later be dropped to your staging location.

To use these scripts, simply copy the code below into .ps1 files, check them into your codebase, and then reference them from your build process as shown above. Also make sure to include the folder that contains your script on the build definition Workspace tab.

Run a script before building: version your assemblies

While there are many tasks you might want to perform before MSBuild compiles your code, one of the most common of these might be to apply a version to your assemblies. Jim Lamb wrote a canonical blog post on build process customization: Create a Custom WF Activity to Sync Version and Build Numbers. I patterned the following script using his approach to assembly versioning.

Run a script after building: prepare your binaries to be staged

When you set Output location to AsConfigured, TFBuild yields control of which binaries are dropped to you. The binaries are compiled and left in the source directory, organized essentially the same way as if you used Visual Studio to compile them locally on your dev machine. The following script gathers some of the typical binary types from the typical locations and copies them to the folder from which TFBuild copies and drops to your staging location.

A few final bits

You'll notice that these scripts leverage some environment variables to get the key bits of data they need to perform their functions. I've cataloged these and all the other environment variables that are available to your scripts: Run your scripts in a default build process. (Note: there is a known bug with the TF_BUILD_TESTRESULTSDIRECTORY not being correctly handled by TFS 2013 Preview. This bug will be fixed in the next release.)

To debug the script while logged on to your dev machine or on the build server, you can manually set the TF_BUILD environment variables in your PowerShell console session. In fact, you'll notice the scripts automatically prompts you to do so. Use the -verbose parameter if you want to get details about what the script is doing and view them from the diagnostic log. Specify -disable if you want to disable any changes the script might make while leaving it referenced by your build process.

@Thorsten: Agreed. I thought some about how to provide that option. In the spirit of agile, I decided to ship these in their current form now.

Kevin T

29 Jul 2013 1:49 PM

@Andy, can we expect to get complete build script examples with check-in, check-out of the of the assembly version file? Agile doesn't mean you can ship incomplete forever...and I worry that this post will be mothballed for all eternity here on MSDN without completed scripts.

@Kevin T, @Thorsten, and all others who want to check in the assembly files: I've talked this angle over with a few folks on the product team. I've got a fix in hand to do this, but before I update this post, please share some information about your scenarios. Specifically:

1. Why do you want to check in the change to the assembly files? I ask because in this scenario, the data that supplies the version stamp is automatically generated. So please help me understand: What benefit do you get from hard coding it each time into your assembly files?

2. Do you also want to associate the changeset generated by the assembly file check-in with the build? I need to know because doing this is tricky and likely would require you to customize the default build process the way it exists in its current form today.

The answers to these questions will not only help me formulate the next version of these scripts, but also may help the product team make some decisions about future enhancements.

Kevin

5 Aug 2013 9:54 AM

@Andy - please post the updated scripts.

To answer your questions:

1) We checkin the assembly files because we don't trust labels (slip the label, etc). We need to have the assembly version in source control so when we re-gen the build (turning off increment) we have the exact same binaries / version numbers.

2) Yes we also want the associated changeset for the build to include the fact that the TFS Service account versioned the files. We need this to have a BOM that includes ALL changes that went into the build.

Thanks for the dialogue and the script examples!

Kim Bonson

5 Aug 2013 11:15 AM

@Andy -For those of us who are using MTM we depend on the build number to be consisently stamped into the version info of the builds we are installing in our lab environment. We also have the build number stamped into our WIX installer, deployed SQL Database instance name, and we update our testplan description in MTM with the build number out of version control.

We also would want the changesets in the build to include the fact that the build process itself touched the file and incremented the number so the build report would accurately ALL of the changes.

Gary Carty

6 Aug 2013 9:12 AM

Taking a look at 2013, can you please post the complete scripts with checkin of the assembly?

I've been sharing your feedback with the product team. So far as I can tell at the moment, associating the check-in with the build for this scenario cannot be done only with a script given the current design of the product.

Gary Carty

8 Aug 2013 1:52 PM

@Andy - thanks for posting the command. The more examples you can provide the better!

@AndyLewis - There is no stage pipeline in TFSBuild and that makes build process very manual and more difficult to manage.

We work 90% of the time with SQL code changes via database projects...deployment of SQL changes via DACPAC's with MSBuild parameters is hard, would new buildscripts make easier? Example SQL deploys with teambuild scripts would be most helpful.

Ryan Cromwell

19 Aug 2013 7:29 AM

I really dislike the use of $env to pass parameters to the script (i.e. $Env:TF_BUILD_SOURCESDIRECTORY)

Why are these not explicit parameters that are passed to the script like this: