Introduction
Administrating Team Foundation Server often involves
repeating the same tasks over and over with only slight variation in the
details. This is especially true if your team adheres to an Agile software
development methodology. Every few weeks a new Iteration begins, which
means inputting new Change Requests into Team Foundation Server along with
their associated Tasks*.
Repetition equals Automation equals PowerShell. If you have
to repeat the same task in Windows more than a few times, consider automating
it with PowerShell.
Microsoft has done an outstanding job equipping PowerShell to access a majority
of the functionary of their primary application; Team Foundation Server 2010
(TFS) is no exception.
Microsoft’s latest release of Team
Foundation Server Power Tools December 2011 includes Windows
PowerShell Cmdlets for Visual Studio Team System Team Foundation Server.
According to Microsoft, Power Tools are a set of enhancements, tools and
command-line utilities that increase productivity of Team Foundation Server
scenarios. Power Tool’s TFS PowerShell Cmdlets give you control of common
version control commands in TFS.
One gotcha with TFS Power Tools, it doesn’t
install PowerShell extras by default. If you
already have Power Tools installed, you must rerun the installer, select the
Modify Install option and add the PowerShell features. If you are installing
Power Tools for the first time, make sure to select the Custom install option
and add the PowerShell features.
*Tasks are a type of TFS Work Item. Work Item types can
also include Bugs, Defects, Test Cases, Risks, QoS Requirements, or whatever
your teams decides to define as Work Items. There is a comprehensive
explanation of Work Items in chapter 12 of Microsoft’s Patterns &
Practices, available to review on Codeplex.
Automating Task Creation
Working with different teams during my career that practice SCRUM, a variation
of Agile, we usually start a new Sprint (Iteration) ever four to six weeks with
an average Sprint Backlog of 15-25 items. Each item in the backlog translates
into individual CRs in TFS. Each CR has several boilerplate Tasks associated
with them. Many Tasks are common to all Change Requests (CR). Common Tasks
often include analysis, design, coding, unit testing, and administration.
Nothing is more mind-numbing as a Manager than having to input a hundred or
more Tasks into TFS every few weeks, with each Task requiring an average of ten
or more fields of data. In addition to the time requirement, there is the
opportunity for human error.
The following PowerShell script creates a series of five
different Tasks for a specific CR, which has been previously created in TFS.
Once the Tasks are created, I use a separate method to link the Tasks to the
CR. Every team’s development methodologies are different; ever team’s use of
TFS is different. Don’t get hung up on exactly which fields I've chosen to
populate. Your processes will undoubtedly require different fields.
There are many fields in a Work Item template that can be
populated with data, using PowerShell. Understanding each field’s definition –
name, data type, and rules for use (range of input values, required field,
etc.) is essential. To review the field definitions, in Visual Studio 2010,
select the Tools tab -> Process Editor -> Work Item Types -> Open WIT
from Server. Select your Work Item Template (WIT) from the list of available templates.
The template you chose will be the same template defined in the PowerShell
script, with the variable $workItemType
. To change the fields, you will need
the necessary TFS privileges.
Task WIT Data Fields
Avoiding Errors
When developing the script for this article, I was stuck for
a number of hours with a generic error (shown below) on some of the Tasks the
script tried to create – “…Work Item is not ready to save” I tried repeatedly
debugging and altering the script to resolve the error without luck. An end up
the error was not in the script, but in my lack of understanding of the Task
Work Item Template (WIT) and its field definitions.
Incorrect Task Input Error
By trial and error, I discovered this error usually means
that either the data being input into a field is invalid based on the field’s
definition, or that a required field failed to have data input for it. Both
were true in my case at different points in the development of the script.
First, I failed to include the Completed Time field, which was a required field
in our Task template. Secondly, I tried to set the Priority of the Tasks to a
number between 1 and 5. Unbeknownst to me, the existing Task template only allowed
values between 1 and 3. The best way to solve these types of errors is to
create a new Task in TFS, and try inputting the same data as you tried to
inject with the script. The cause of the error should quickly become clear.
The Script
For simplicity sake I have presented a simple PowerShell
script. The script could easily be optimized by wrapping the logic into a
function with input parameters, further automating the process. I've placed a
lot of comments in the script to explain what each part does, and help make
customization easier.The script explicitly declares all variables and adheres
to PowerShell’s Strict Mode (
Set-StrictMode
-Version 2.0
). I feel this makes the script easier to understand and reduces
the number of runtime errors.
#############################################################
#
# Description: Automatically creates (5) standard Task-type
# Work Items in TFS for a given Change Request.
#
# Author: Gary A. Stafford
# Created: 04/12/2012
# Modified: 08/14/2012
#
#############################################################
# Clear Output Pane
clear
# Loads Windows PowerShell snap-in if not already loaded
if ( (Get-PSSnapin -Name Microsoft.TeamFoundation.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSSnapin Microsoft.TeamFoundation.PowerShell
}
# Set Strict Mode - optional
Set-StrictMode -Version 2.0
# Usually changes for each Sprint - both specific to your environment
[string] $areaPath = "Development\PowerShell"
[string] $iterationPath = "PowerShell\TFS2010"
# Usually changes for each CR
[string] $changeRequestName = "Create Task Automation PowerShell Script"
[string] $assignee = "Stafford, Gary"
# Values represent units of work, often 'man-hours'
[decimal[]] $taskEstimateArray = @(2,3,10,3,.5)
# Remaining Time is usually set to Estimated time at start (optional use of this array)
[decimal[]] $taskRemainingArray = @(2,3,10,3,.5)
# Completed Time is usually set to zero at start (optional use of this array)
[decimal[]] $tasktaskCompletedArray = @(0,0,0,0,0,0)
# Usually remains constant
# TFS Server address - specific to your environment
[string] $tfsServerString = "http://[YourServerNameGoesHere]/[PathToCollection]"
# Work Item Type - specific to your environment
[string] $workItemType = "Development\Task"
[string[]] $taskNameArray = @("Analysis", "Design", "Coding", "Unit Testing", "Resolve Tasks")
[string[]] $taskDisciplineArray = @("Analysis", "Development", "Development", "Test", $null)
# Loop and create of eack of the (5) Tasks in prioritized order
[int] $i = 0
Write-Host `n`r**** Script started...`n`r
while ($i -le 4) {
# Concatenate name of task with CR name for Title and Description fields
$taskTitle = $taskNameArray[$i] + ": " + $changeRequestName
# Build string of field parameters (key/value pairs)
[string] $fields = "Title=$($taskTitle);Description=$($taskTitle);Assigned To=$($assignee);"
$fields += "Area Path=$($areaPath);Iteration Path=$($iterationPath);Discipline=$($taskDisciplineArray[$i]);Priority=$($i+1);"
$fields += "Estimate=$($taskEstimateArray[$i]);Remaining Work=$($taskRemainingArray[$i]);Completed Work=$($tasktaskCompletedArray[$i])"
#For debugging - optional console output
Write-Host $fields
# Create the Task (Work Item)
tfpt workitem /new $workItemType /collection:$tfsServerString /fields:$fields
$i++
}
Write-Host `n`r**** Script completed...
The script begins by setting up a series of variables. Some
variables will not change once they are set, such as the path to the TFS
server, unless you work with multiple TFS instances. Some variables will only
change at the beginning of each iteration (Sprint), such as the Iteration Path.
Other variables will change for each CR or for each Task. These include the CR
title and Estimated, Completed, and Remaining Time. Again, your process will
dictate different fields with different variables.
Once you set the
script’s variables to meet your requirements, and run it successfully, you should see output
similar to the following:
Successful Creation of Tasks
New Task in TFS, Created by PowerShell
Deleting Work Items
TFS Administrators know there is no Work Item delete button
in TFS. So, how do you delete the Tasks you may have created during developing
and testing this script? The quickest way is from the command line or from
PowerShell. You can also delete Work Items programmatically in .NET. To use the command line, perform the follow:
- Open
the Visual Studio 2010 Command Prompt.
- Change
the directory to the location of
witadmin.exe
. My default location is:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE. - Run
the following command, substituting the Task Id for the Task Id or Task
Ids, comma delimited without spaces, of the Tasks you want to delete:
witadmin destroywi /collection:[Your TFS Collection Path Here] /id:12930 /noprompt
Deleting Task from Command Line
Almost the same command can be run in PowerShell by
including the path to witadmin.exe
in the script. I found this method at Goshoom.NET Dev Blog. You
can read more, there. Be warned, there is no undoing the delete command. The /noprompt
is optional; using it speeds up the deletion of Tasks. However,
leaving out /noprompt
means you are given a chance to confirm the Task’s
deletion. Not a bad idea when you’re busy doing a dozen other things.
Conclusion
Creating Tasks with PowerShell, I save at least two hours of
time each Sprint cycle, and greatly reduce my chance for errors. Beyond Tasks,
there are many more mundane TFS chores that can be automated using PowerShell.
These chores include bulk import of CRs and Tasks from Excel or other Project
Management programs, creating and distributing Agile reports, and turnover and
release management automation, to name but a few. I’ll explore some of these
topics in future blog.
History
v1.0: 2012-08-14 - Original release of script.