Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Upgrade/Publish TFS 2013 Process Templates with PowerShell

, 9 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
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 . When I first started doing customizations I used the TFS Power Tools to upload changes which is

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

Param(
      [<span style="color: #0000ff">string</span>] $CollectionUrlParam = $(Read-Host -prompt <span style="color: #006080">"Collection (enter to pick):"</span>), 
      [<span style="color: #0000ff">string</span>] $TeamProjectName = $(Read-Host -prompt <span style="color: #006080">"Team Project:"</span>),
      [<span style="color: #0000ff">string</span>] $ProcessTemplateRoot = $(Read-Host -prompt <span style="color: #006080">"Process Template Folder:"</span>)
      )

$TeamProjectName = <span style="color: #006080">"teamswithareas"</span>
$ProcessTemplateRoot = <span style="color: #006080">"C:\Users\mrhinsh\Desktop\TfsProcessTemplates\Microsoft Visual Studio Scrum 3.0 - Preview"</span>
$CollectionUrl = <span style="color: #006080">"http://kraken:8080/tfs/tfs01"</span>

$TFSConfig = <span style="color: #006080">"${env:ProgramFiles}\Microsoft Team Foundation Server 11.0\Tools\TFSConfig.exe"</span>
$WitAdmin = <span style="color: #006080">"${env:ProgramFiles(x86)}\Microsoft Visual Studio 12.0\Common7\IDE\witadmin.exe"</span>

witds = Get-ChildItem <span style="color: #006080">"$ProcessTemplateRoot\WorkItem TrackingType\Definitions"</span>

<span style="color: #0000ff">foreach</span> ($witd <span style="color: #0000ff">in</span> $witds)
{
   Write-Host <span style="color: #006080">"Importing $witd"</span>
   & $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$($witd.FullName)
}
$WitAdmin importcategories /collection:$CollectionUrl /p:$TeamProjectName /f:<span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\Categories.xml"</span>
$WitAdmin importprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:<span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\Process\ProcessConfiguration.xml"</span>

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

<span style="color: #cc6633">#if</span> there <span style="color: #0000ff">is</span> a file with the name GlobalLists-ForImport.xml import it <span style="color: #0000ff">as</span> Global List info <span style="color: #0000ff">for</span> the current collection
<span style="color: #0000ff">if</span> (Test-Path <span style="color: #006080">"$ProcessTemplateRoot\GlobalLists-ForImport.xml"</span>)
{
    Write-Host <span style="color: #006080">"Importing GlobalLists-ForImport.xml"</span>
    & $WitAdmin importgloballist /collection:$CollectionUrl /f:<span style="color: #006080">"$ProcessTemplateRoot\GlobalLists-ForImport.xml"</span>
}

and imported linked types

#import each Link Type <span style="color: #0000ff">for</span> the $CollectionName
<span style="color: #0000ff">foreach</span>($witd_LinkType <span style="color: #0000ff">in</span> $witd_LinkTypes)
{
    Write-Host <span style="color: #006080">"Importing $($witd_LinkType.Name)"</span>
    & $WitAdmin importlinktype /collection:$CollectionUrl /f:$($witd_LinkType.FullName)
}

ALM Rangers - vsarUpgradeGuide & vsarSAFe

vsarUpgradeGuide

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.

vsarSAFe

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

 image_thumb[3]

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:<span style="color: #008000">//opensource.org/licenses/ms-pl.html.)</span>
# 
#config
$server = <span style="color: #006080">"MyTfsServer"</span>
$port = 8080
$virtualDirectory = <span style="color: #006080">"tfs"</span>
$CollectionName = <span style="color: #006080">"DefaultCollection"</span>
$TeamProjectNames = @(<span style="color: #006080">"Team Project 1"</span>, <span style="color: #006080">"Team Project 2"</span>, <span style="color: #006080">"Team Project 7"</span>, <span style="color: #006080">"Sample Scrum Project 1"</span>)
$ProcessTemplateRoot = <span style="color: #006080">"C:\templates\Microsoft Visual Studio Scrum 2013.3"</span>

$CollectionUrl = <span style="color: #006080">"http://$($server)$(if ($port -ne 80) { "</span>:$port<span style="color: #006080">" })$(if (![string]::IsNullOrEmpty($virtualDirectory)) { "</span>/$virtualDirectory<span style="color: #006080">" })/$($CollectionName)"</span>
$API_Version = <span style="color: #006080">"12.0"</span>

#----------------------------
# don't edit below <span style="color: #0000ff">this</span> line
#----------------------------

#get a reference to the witadmin executable path <span style="color: #0000ff">for</span> the current api version
$WitAdmin = <span style="color: #006080">"${env:ProgramFiles(x86)}\Microsoft Visual Studio $API_Version\Common7\IDE\witadmin.exe"</span>

<span style="color: #cc6633">#if</span> there <span style="color: #0000ff">is</span> a file with the name GlobalLists-ForImport.xml import it <span style="color: #0000ff">as</span> Global List info <span style="color: #0000ff">for</span> the current collection
<span style="color: #0000ff">if</span> (Test-Path <span style="color: #006080">"$ProcessTemplateRoot\GlobalLists-ForImport.xml"</span>)
{
    Write-Host <span style="color: #006080">"Importing GlobalLists-ForImport.xml"</span>
    & $WitAdmin importgloballist /collection:$CollectionUrl /f:<span style="color: #006080">"$ProcessTemplateRoot\GlobalLists-ForImport.xml"</span>
}

#get a reference to all work item type definitions
$wit_TypeDefinitions = Get-ChildItem <span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\TypeDefinitions\*.*"</span> -include <span style="color: #006080">"*.xml"</span>

#get a reference to all work item link types
$witd_LinkTypes = Get-ChildItem <span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\LinkTypes\*.*"</span> -include <span style="color: #006080">"*.xml"</span>

#import each Link Type <span style="color: #0000ff">for</span> the $CollectionName
<span style="color: #0000ff">foreach</span>($witd_LinkType <span style="color: #0000ff">in</span> $witd_LinkTypes)
{
    Write-Host <span style="color: #006080">"Importing $($witd_LinkType.Name)"</span>
    & $WitAdmin importlinktype /collection:$CollectionUrl /f:$($witd_LinkType.FullName)
}

<span style="color: #0000ff">foreach</span> ($TeamProjectName <span style="color: #0000ff">in</span> $TeamProjectNames)
{
    Write-Host <span style="color: #006080">"Upgrading $TeamProjectName."</span>

    #import each Type Definition <span style="color: #0000ff">for</span> the $TeamProjectName
    <span style="color: #0000ff">foreach</span>($wit_TypeDefinition <span style="color: #0000ff">in</span> $wit_TypeDefinitions)
    {
        Write-Host <span style="color: #006080">"Importing $($wit_TypeDefinition.Name)"</span>
        & $WitAdmin importwitd /collection:$CollectionUrl /p:$TeamProjectName /f:$($wit_TypeDefinition.FullName)
    }

    #import work item categories <span style="color: #0000ff">for</span> the $TeamProjectName
    & $WitAdmin importcategories /collection:$CollectionUrl /p:$TeamProjectName /f:<span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\Categories.xml"</span>

    #import work item process configuration <span style="color: #0000ff">for</span> the $TeamProjectName
    & $WitAdmin importprocessconfig /collection:$CollectionUrl /p:$TeamProjectName /f:<span style="color: #006080">"$ProcessTemplateRoot\WorkItem Tracking\Process\ProcessConfiguration.xml"</span>
}
Write-Host <span style="color: #006080">"Done upgrading team projects"</span>

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gordon W Beeming
Software Developer Derivco
South Africa South Africa
Gordon Beeming is a Software Developer at Derivco in the sunny city of Durban, South Africa. He spends most his time hacking away at the keyboard in Visual Studio or with his family relaxing. He is a Visual Studio ALM Rangers, Visual Studio ALM MVP and Friend of Red Gate. His blog is at 31og.com and you can follow him on Twitter at twitter.com/gordonbeeming
 
http://31og.com
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionSAFe script? PinmemberGreg Prosch5-Nov-14 9:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150327.1 | Last Updated 9 Aug 2014
Article Copyright 2014 by Gordon W Beeming
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid