I use to make a lot of TFS customizations and had to apply the template changes to multiple team projects which took a bit of time. Depending on the method you use it could be a quick or loooong process Smile. When I first started doing customizations I used the TFS Power Tools to upload changes which is a lot of effort because you are uploading one work item definition at a time into one team project.

Using Command Line

After a while I started using command line (witadmin importwitd), this was slightly faster but I found myself keeping a list commands in a txt file and then searching for the one I need when needed and run it.

A Basic PowerShell Script

I follow Martin Hinshelwood on various social media and one day he posted a blog post titled Upgrading to Visual Studio Scrum 3.0 process template in TFS 2013, although I had been at this point playing a lot with upgrading from TFS 2012 to TFS 2013 there was one piece of magic in that post that changed the way I applied process template changes up until today. It was a script that simple looped through the work item definitions in a set folder and imported them into TFS

[string] $CollectionUrlParam = $(Read-Host -prompt "Collection (enter to pick):"),
[string] $TeamProjectName = $(Read-Host -prompt "Team Project:"),
[string] $ProcessTemplateRoot = $(Read-Host -prompt "Process Template Folder:")

$TeamProjectName = "teamswithareas"
$ProcessTemplateRoot = "C:\Users\mrhinsh\Desktop\TfsProcessTemplates\Microsoft Visual Studio Scrum 3.0 - Preview"
$CollectionUrl = "http://kraken:8080/tfs/tfs01"

$TFSConfig = "${env:ProgramFiles}\Microsoft Team Foundation Server 11.0\Tools\TFSConfig.exe"
$WitAdmin = "${env:ProgramFiles(x86)}\Microsoft Visual Studio 12.0\Common7\IDE\witadmin.exe"

witds = Get-ChildItem "$ProcessTemplateRoot\WorkItem TrackingType\Definitions"

foreach ($witd in $witds)
Write-Host "Importing $witd"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$($witd.FullName)
$WitAdmin importcategories /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProcessTemplateRoot\WorkItem Tracking\Categories.xml"
$WitAdmin importprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProcessTemplateRoot\WorkItem Tracking\Process\ProcessConfiguration.xml"

Small Script Evolution

This worked for a while but I still had keep a couple of PowerShell files for the different projects I want to import the process templates into. I ended up adding over the next while adding a couple of additions to the script like publishing new global lists

#if there is a file with the name GlobalLists-ForImport.xml import it as Global List info for the current collection
if (Test-Path "$ProcessTemplateRoot\GlobalLists-ForImport.xml")
Write-Host "Importing GlobalLists-ForImport.xml"
& $WitAdmin importgloballist /collection:$CollectionUrl /f:"$ProcessTemplateRoot\GlobalLists-ForImport.xml"

and imported linked types

#import each Link Type for the $CollectionName
foreach($witd_LinkType in $witd_LinkTypes)
Write-Host "Importing $($witd_LinkType.Name)"
& $WitAdmin importlinktype /collection:$CollectionUrl /f:$($witd_LinkType.FullName)

ALM Rangers - vsarUpgradeGuide & vsarSAFe


The first project I joined after joining the ALM Rangers was the TFS Upgrade Guide. The last part of my contributions for the upgrade guide was a PowerShell script that could help you easily upgrade your process templates (or at least publish them) after you have made the changes required to make them compatible with TFS 2013. And for some reason it wasn't until then that I made the script target multiple team projects in the same collection.


The latest small modifications that were made to the script were for the project vsarSAFe which looks at how to modify your process template to make them SAFe aware. If you aren't familiar with SAFe it stands for Scaled Agile Framework. As I'm writing this we are showing up as Delayed on the Flight Plan but will be landing soon Open-mouthed smile


Most of the changes included here were just around adding comments and cleaning the script up a bit to make it easier to read.

So what does the script look like?

The final script (as it is now) looks like below

# Copyright © Microsoft Corporation.  All Rights Reserved.
# This code released under the terms of the
# Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
$server = "MyTfsServer"
$port = 8080
$virtualDirectory = "tfs"
$CollectionName = "DefaultCollection"
$TeamProjectNames = @("Team Project 1", "Team Project 2", "Team Project 7", "Sample Scrum Project 1")
$ProcessTemplateRoot = "C:\templates\Microsoft Visual Studio Scrum 2013.3"

$CollectionUrl = "http://$($server)$(if ($port -ne 80) { ":$port" })$(if (![string]::IsNullOrEmpty($virtualDirectory)) { "/$virtualDirectory" })/$($CollectionName)"
$API_Version = "12.0"

# don't edit below this line

#get a reference to the witadmin executable path for the current api version
$WitAdmin = "${env:ProgramFiles(x86)}\Microsoft Visual Studio $API_Version\Common7\IDE\witadmin.exe"

#if there is a file with the name GlobalLists-ForImport.xml import it as Global List info for the current collection
if (Test-Path "$ProcessTemplateRoot\GlobalLists-ForImport.xml")
Write-Host "Importing GlobalLists-ForImport.xml"
& $WitAdmin importgloballist /collection:$CollectionUrl /f:"$ProcessTemplateRoot\GlobalLists-ForImport.xml"

#get a reference to all work item type definitions
$wit_TypeDefinitions = Get-ChildItem "$ProcessTemplateRoot\WorkItem Tracking\TypeDefinitions\*.*" -include "*.xml"

#get a reference to all work item link types
$witd_LinkTypes = Get-ChildItem "$ProcessTemplateRoot\WorkItem Tracking\LinkTypes\*.*" -include "*.xml"

#import each Link Type for the $CollectionName
foreach($witd_LinkType in $witd_LinkTypes)
Write-Host "Importing $($witd_LinkType.Name)"
& $WitAdmin importlinktype /collection:$CollectionUrl /f:$($witd_LinkType.FullName)

foreach ($TeamProjectName in $TeamProjectNames)
Write-Host "Upgrading $TeamProjectName."

#import each Type Definition for the $TeamProjectName
foreach($wit_TypeDefinition in $wit_TypeDefinitions)
Write-Host "Importing $($wit_TypeDefinition.Name)"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$($wit_TypeDefinition.FullName)

#import work item categories for the $TeamProjectName
& $WitAdmin importcategories /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProcessTemplateRoot\WorkItem Tracking\Categories.xml"

#import work item process configuration for the $TeamProjectName
& $WitAdmin importprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProcessTemplateRoot\WorkItem Tracking\Process\ProcessConfiguration.xml"
Write-Host "Done upgrading team projects"

This script now targets unlimited team projects in 1 team project collection, updates the categories, configuration, global lists and link types. You can grab the script off GitHub as well under my Gists (upgrade-tfs-2013-process-templates.ps1).

This takes care of all the things I need when making process template changes as I now make what ever changes I need run the script and check my changes in the browser. It doesn't get much easier than this but if you have a easier way do let me know Smile.


UPDATE: This has been identified as a bug and will be fixed in the next release for on-premise

So if you have a lot customizations in your process template there is a slight chance you would have seen the error below after the upgrade.


If you have completed the Configure Features option


and still see the error odds are you have need to follow similar steps to below

Look for the actual exception

Take a look at the event log under the Microsoft-Team Foundation Server/Debug section of Applications and Services Log


When the error occurs do you see an error? I received the error below that pointed towards something with the add panel being wrong

Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.InvalidProjectSettingsException: Object reference not set to an instance of an object. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.DefaultSettingsValidatorDataProvider.GetFieldType(String workItemTypeName, String fieldReferenceName)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.<>c__DisplayClass4b.<>c__DisplayClass4f.<ValidateAddPanels>b__41(String type)
   at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.<>c__DisplayClass4b.<ValidateAddPanels>b__40(String refName)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.ValidateAddPanels()
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.ValidateContent(OptionalFeatures featuresToValidate)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.Validate(OptionalFeatures featuresToValidate, Boolean validateStructureOnly)
   --- End of inner exception stack trace ---
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.Validate(OptionalFeatures featuresToValidate, Boolean validateStructureOnly)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProcessSettingsValidator.Validate(TeamFoundationRequestContext requestContext, ProjectProcessConfiguration settings, String projectUri, Boolean correctWarnings, OptionalFeatures featuresToValidate)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProjectConfigurationService.GetProcessSettings(TeamFoundationRequestContext requestContext, String projectUri, Boolean validate, Boolean bypassCache)
   at Microsoft.TeamFoundation.Server.WebAccess.WorkItemTracking.Common.ProjectConfigurationService.GetCommonSettings(TeamFoundationRequestContext requestContext, String projectUri, Boolean validateSettings)
   at Microsoft.TeamFoundation.Server.WebAccess.Agile.AgileAreaRegistration.CanDisplayTiles(TfsWebContext webContext)

Find the problem

I went over to the process configuration which seemed to be the logical starting point based off the error on screen and stack trace from the event log. I compared all the customizations I had with what is in the default Scrum 2013.2 template and saw that I had extra fields in one of my Add Panels


I removed these and imported the ProcessConfiguration.xml using the witAdmin importprocessconfig tool, this worked and the site was working as normal without the error.

Fix the problem

Obviously we couldn't just remove the extra fields and be on our way because those were there for a reason. The Add Panel changes were applied for the Requirements Backlog in our case. We took a look at the Categories.xml to verify which the work item types were that were part of the requirements and found the 4 below


We currently only use new Product Backlog Items and the other 3 are "old" work item types that are in TFS because we used to use them and don't want to remove them because there are existing work items of this type in our TFS project. So we went to the 3 other WITd and made sure that they each had these 3 fields, we found as we expected that they didn't have each of them.

After adding the fields we re-imported the WITd for all requirement types and then tried to import the ProcessConfiguration.xml and it imported without any issues and our TFS was working again without any errors.

What Happened then?

Before the update we were obviously using this template so everything use to work, although I must admit it makes more sense that all WITd's need the fields being displayed in the Add Panel for it's categories, it use to not be the case so after upgrading this was a rather unusual error for us. It could possible have been looked at as a bug here this wasn't required to match. If I find out the reason for the change I'll update here Smile


Did you hear? Somasegar blogged that Team Foundation Server 2013 RC is a go-live release. What does that mean for you and your customers? One word


You might be wonder why I'm so excited about this release. One of the many reasons why I'm so excited about this release is because Work Item Charting which was announced last September and then updated in VSO with the November service updates to support Chart Pinning, and now this feature has made it's way to on premise with TFS 2013 Update 2.

Although this was released for on premise 3 weeks ago in the CTP release it was not a go-live release at that point.

Using Chart Pinning to transform your teams dashboard

After upgrading to TFS 2013 Update 2 your pinned items would look something like below.  This information is very useful for your team as it allows you to easily see bugs from your 2 main product sprints with a 3rd tile telling you other bugs that exist across other products. You are also able to see defects which are the bugs that exist out in the real work in builds that have already been deployed.


Getting any value of this is possible but probably a lot more effort at times with all these numbers staring at you. What if you could represent all 7 of these tiles in a way that is easy to take in with a quick glance and at the same time extend on the information about what the other product sprints are that contain bugs.

Enter Chart Pinning, transforming these tiles is as easily as creating a chart for the work item query Open Defects and creating a new query that includes all bugs and not just specific products. Next you pin those charts to your dashboard using the Pin to homepage button


and then also unpin the 7 tiles that we are replacing. With the current library being used for the home page grid you will notice that if you place a chart in the second or third column that it leaves empty spaces to it's left if you have regular queries pinned, for that reason I'd recommend moving the pinned charts to the first and second position on your dashboard and you get something like below which is a lot more meaning full the team to glance at as the are passing the home page


As you can see pinning charts can provide a lot of extra value to your work item data. But let's see how easy it is to dig deeper if you wanted to, we will go through to the Bugs Not Done chart by clicking on the chart (yes the charts work the same way as the tiles do with clicking to go through the query Smile). We'll add a new chart using the Pivot table chart with a row of our team name and have the columns as the product sprint name and change the Sort to label. Click OK and you have the same chart that you would usually only get by exporting your work item results to excel (pre charts) and then need some complicated manual morphing to see the same thing as below


Hopefully you are preparing to upgrade to TFS 2013 Update 2 and if you weren't before reading this you are now planning to upgrade really soon Smile.