PowerShell & TFS

There have been occasions where I've wanted to create work items in bulk.

For example: Every time you create a User Story your team has several standard Tasks that need to be created. Write Test Cases, Execute test cases, Deploy to QA, etc. I don't want to manually go through dozens or work items adding the same set of work items as children to each one over and over.

Excel is a pretty good option, certainly faster than doing it one at a time via Team Explorer or the Web interface. In the past I have written C# applications to do this through the TFS API. This works great and is very easy to code.

I am always trying to force myself to get better with PowerShell, so I started searching for examples of calling the TFS API from PowerShell. This helped me piece together the parts I needed to solve this problem with PowerShell.

These were my requirements:

  • There are N Stories in TFS each one represents an existing report that needs to go through several stages of work.
  • We want 6 new Stories created as children of each Report Story so the work can be assigned to different teams in the organization then the individual teams can create their own tasks.
  • We don't want the Child Stories to all have the same title. That is fine when you see them in context of their parent like this:
    • Report 1
      • Report Attributes
      • Data Lineage
      • Gap Analysis
    • Report 2
      • Report Attributes
      • Data Lineage
      • Gap Analysis
  • However when you see the Report Attributes Story on its own it means very little.
  • Therefore I want was something like this:
    • Report 1
      • Report Attributes for Report 1
      • Data Lineage for Report 1
      • Gap Analysis for Report 1
    • Report 2
      • Report Attributes for Report 2
      • Data Lineage for Report 2
      • Gap Analysis for Report 2
  • Plus each sub story needs to have the same Area, Team and other attributes as its Parent Story

As you can see a simple cut and paste in Excel won't do, because I would still have to edit each work item to add the report name to the title and populate the fields from the parent that I want brought over.

PowerShell to the rescue

if ( (Get-PSSnapin -Name Microsoft.TeamFoundation.PowerShell -ErrorAction SilentlyContinue) -eq $null )

{ Add-PSSnapin Microsoft.TeamFoundation.PowerShell }

 

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Common")

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.WorkItemTracking.Client")

 

#Get the TFS Collection

$tfsCollectionUrl = "http://Server:8080/tfs/CollectionName"

$teamProjectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsCollectionUrl)

 

#Get the WorkItemStore Service

$ws = $teamProjectCollection.GetService([type]"Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore")

 

#Get the Team Project

$proj = $ws.Projects["Team Project"]

 

Write-Host "Team Project Collection: "$teamProjectCollection

Write-Host "Project:" $proj.Name

Write-Host "---------------------"

 

#Write a query to get the parent work items

$ParentWorkItems = $ws.Query("SELECT [System.Id] FROM WorkItems WHERE [System.AssignedTo] = 'Dave Lloyd' ")

 

#the Sub Stories you want to create as Children

$ChildStoryTitles = @( "Report Attributes","Data Lineage","Gap Analysis","Impact Analysis","Remediation","Testing")

 

#For each Parent Work item

foreach ($WorkItemParent in $ParentWorkItems)

{

$counter=1

Write-Host "Parent workItem:" $WorkItemParent.ID "-" $WorkItemParent.Title

 

#For each Parent create 6 New User Stories

foreach ($childTitle in $ChildStoryTitles)

{

$story = $proj.WorkItemTypes["User Story"]

$workitemChild = $story.NewWorkItem()

#Append the Parent Title to the end of the Child Title

     #System fields like title can be referenced directly and show up in intelliSence

$workItemChild.Title = $childTitle + " for " + $WorkItemParent.Title

#There is an order so I used a counter to set the Stack Rank on the CHild Stories

#For non-system fields use the fields member the name of the field and the value property

$workItemChild.Fields["Stack Rank"].value = $counter

#take any fields from the parent that you want to bring down into the child

$workItemChild.AreaId = $WorkItemParent.AreaId

$workItemChild.Save()

 

Write-Host " Child workItem" $workitemChild.ID $WorkItemChild.Title

 

#Link the CHild work item to the Parent Work item

$linkType = $ws.WorkItemLinkTypes[[Microsoft.TeamFoundation.WorkItemTracking.Client.CoreLinkTypeReferenceNames]::Hierarchy]

$link = new-object Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLink($linkType.ReverseEnd, $workitemParent.ID)

$workitemChild.Links.Add($link)

$workItemChild.Save()

$counter++

}

 

}