One of the Team Foundation Server Process Template customisations I do frequently is changing a project to make use of a custom team field rather than the default Area Path to scope Work Items to teams.
If you haven’t made use of teams in TFS 2012 or TFS 2013 yet then check out these links
Multiple Teams with Microsoft Team Foundation Server 2012 & Visual Studio Scrum
TFS 2013: Collaborate using team resources
If you don’t know what is involved in customisation then you need to check out this page.
Customize a team project to support team fields
Now, you can, as with any process update, make changes offline and any subsequent projects created using that template will see the changes. Or, you can update an existing in-flight project with template changes.
It’s not particularly difficult to change your template to make use of a team field but it is time consuming so I wrote a PowerShell script to do it both to save me time and to play around with using PowerShell to do XML transformations.
My script downloads the required files from a Visual Studio Scrum 2013 project, backs them up, performs an XML Transform on them and uploads them to your project. If you are using a different process template then you will need to edit the XML transforms and the selected Work Item definitions but the technique is the same.
You can call the script Add-Teams.ps1 from the command line and provide 3 parameters
Add-Teams.ps1 “http://TFS2013:8080/tfs/DefaultCollection” MyProject “C:\TemplateUpdates”
Defaults are specified at the beginning of the script so if you plan to run it using PowerShell ISE for example, then simply change the values.
#TFS Collection Url
[string]$CollectionUrl = "http://TFS2013:8080/tfs/DefaultCollection",
#Name of the TFS Team Project to transform
[string]$TeamProjectName = "MyProject",
#Working folder to store the XML transforms, downloaded files and backup
[string]$WorkingFolder = "C:\TemplateUpdates"
There is some (hopefully) useful logging throughout the script which uses write-verbose, so if you want to turn it on then give the script a –verbose flag when you run it.
The script
First we create a function called Transform-XML that takes an XML file and a transform file to apply. We’ll use it to alter the Work Item definitions, the Process Configuration and add a Global List.
function Transform-XML
{
Param (
[Parameter(Mandatory=$True)][ValidateNotNull()]$Wit,
[Parameter(Mandatory=$True)][ValidateNotNull()]$Tfm
)
Next, the necessary Work Item definitions (Product Backlog Item, Task, Bug, Feature & Test Plan) are downloaded from your project using WitAdmin.exe (usually found in C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Witadmin.exe)
# Export Work Item definitions
write-Verbose "Exporting PBI definition"
& $WitAdmin exportwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$PBIDefinition /n:"Product Backlog Item"
write-Verbose "Exporting Task definition"
& $WitAdmin exportwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$TaskDefinition /n:"Task"
write-Verbose "Exporting Bug definition"
& $WitAdmin exportwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$BugDefinition /n:"Bug"
write-Verbose "Exporting Feature definition"
& $WitAdmin exportwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$FeatureDefinition /n:"Feature"
# Required if using TFS 2013 Update 3 or later
write-Verbose "Exporting Test Plan definition"
& $WitAdmin exportwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$TestPlanDefinition /n:"Test Plan"
# Export Process Configuration
write-Verbose "Exporting Process Configuration"
& $WitAdmin exportprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:$PCDefinition
# Export Global List
write-Verbose "Exporting Global List"
& $witadmin exportgloballist /collection:$CollectionUrl /f:$GLDefinition
The we copy all the downloaded files into a backup directory. If your Team project was called MyProject then all the files would be downloaded to C:\TemplateUpdates\MyProject and a backup would be copied to C:\TemplateUpdates\MyProjectBackup\110914.161115 where the date is 11\09\2014 and the time is 16:11 and 15 seconds. This way, if anything goes wrong, you have your original files to upload.
# Create backup of process files
write-Verbose "Backing up process files"
$timestamp = Get-Date -UFormat "%d%m%y.%T" | foreach {$_ -replace ":", ""}
Copy-Item -Path $ProjectFolder -Container -Destination "$($ProjectFolder)Backup\$timestamp" -Recurse -force
After that we call the Transform-XML function against the required files
try
{
#Try transforming the required files and exit the script if there are any problems
# Add Global List
write-Verbose "Adding Team Global List"
Transform-XML $GLDefinition $GLTransform
# Update Work Item Definitions to add new Team field and include on form
write-Verbose "Updating PBI Definition"
Transform-XML $PBIDefinition $WITTransform
write-Verbose "Updating Task Definition"
Transform-XML $TaskDefinition $WITTransform
write-Verbose "Updating Bug Definition"
Transform-XML $BugDefinition $WITTransform
write-Verbose "Updating Feature Definition"
Transform-XML $FeatureDefinition $WITTransform
# Required if using TFS 2013 Update 3 or later
write-Verbose "Updating Test Plan Definition"
Transform-XML $TestPlanDefinition $WITTransform
# Update Process Template to make use of new Team field instead of AreaPath
write-Verbose "Updating Process Configuration"
Transform-XML $PCDefinition $PCTransform
}
The XML transform for a Work Item looks like this for example
<?xml version="1.0"?>
<witd:WITD xmlns:witd="http://schemas.microsoft.com/VisualStudio/2008/workitemtracking/typedef" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<WORKITEMTYPE name="Bug">
<FIELDS>
<!-- If the team field has already been added then remove it first-->
<FIELD name="Team" xdt:Transform="Remove" xdt:Locator="Match(name)" />
<FIELD name="Team" refname="RippleRock.Scrum.Team" type="String" reportable="dimension" xdt:Transform="Insert">
<HELPTEXT>Name of the team that will do the work.</HELPTEXT>
<ALLOWEXISTINGVALUE />
<ALLOWEDVALUES >
<GLOBALLIST name="Teams" />
</ALLOWEDVALUES >
<DEFAULT from="value" value="Unassigned" />
</FIELD>
</FIELDS>
<FORM>
<Layout>
<Group>
<Column>
<Group Label="Status">
<Column PercentWidth="100">
<!-- If the team field has already been added then remove it first-->
<Control FieldName="RippleRock.Scrum.Team" xdt:Transform="Remove" xdt:Locator="Match(FieldName)" />
<Control FieldName="RippleRock.Scrum.Team" Type="FieldControl" Label="Team" LabelPosition="Left" EmptyText="<None>" xdt:Transform="Insert" />
</Column>
</Group>
</Column>
</Group>
</Layout>
</FORM>
</WORKITEMTYPE>
</witd:WITD>
This adds a field called RippleRock.Scrum.Team to the Work Item and then adds a Field Control at the end of the Status group on the Work Item form. I added an additional Remove transform for both elements so that if you run the script against an item that already has a Team field then it will be replaced.
Finally, we import all our definitions and we should be good to go.
# Import Global List
write-Verbose "Importing Global List"
& $witadmin importgloballist /collection:$CollectionUrl /f:"$ProjectFolder\GlobalList.xml"
# Import Work Item definitions
write-Verbose "Importing PBI definition"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\TypeDefinitions\ProductBacklogItem.xml"
write-Verbose "Importing Task definition"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\TypeDefinitions\Task.xml"
write-Verbose "Importing Bug definition"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\TypeDefinitions\Bug.xml"
write-Verbose "Importing Feature definition"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\TypeDefinitions\Feature.xml"
# Required if using TFS 2013 Update 3 or later
write-Verbose "Importing Test Plan definition"
& $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\TypeDefinitions\TestPlan.xml"
# Import Process Configuration
write-Verbose "Importing Process Configuration"
& $WitAdmin importprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:"$ProjectFolder\WorkItem Tracking\Process\ProcessConfiguration.xml"
Remember to follow the steps in the “Configure Team Settings” section of the Customize a team project to support team fields to alter how Work Items show up on the team backlogs.

Download the script and the transforms here.
I hope it saves you some time.
Cheers,
Richard
.