I work with Team foundation server – keeping track of projects, etc… and now that it’s January i had 100+ tasks to create. I thought to myself… why do this manually?
####################################################################
###
### Script to create TFS entries from CSV file
### by Jeremy Castleberry
### created 1-16-2019
### last update 1-17-2019
### Version 1
###
####################################################################
#region Log Of Changes
####################################################################
###
###
###
###
###
###
###
####################################################################
#endregion Log of Changes
####################################################################
#region FUNCTIONS
#############################################################################
##
## Function from Hey Scripting Guys!
## https://blogs.technet.microsoft.com/heyscriptingguy/2009/09/01/hey-scripting-guy-can-i-open-a-file-dialog-box-with-windows-powershell/
##
#############################################################################
Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
}
#end function Get-FileName
#endregion FUNCTIONS
#region Get Input File
#We need to prompt for the file.
[string]$VARfilepath = Get-FileName
# or set it hardcoded
#$VARfilepath = "c:\temp\tasks.csv"
#EndRegion Get Input File
####################################################################
#region Modules
# Import whichever modules we need
Import-Module TfsCmdlets -Force
#endregion Modules
####################################################################
#region Variables
[string]$VARUrl = "http://YOURSERVER:####/tfs/Projects/"
[string]$VARTFSproject = "TFSPROJECT"
[array]$ARRTFSItems = @()
#endregion Variables
####################################################################
#region Connect to TFS components
#First to the server
Connect-TfsTeamProjectCollection $VARUrl
# and now our project
Connect-TfsTeamProject -Project $VARTFSproject
$OBJtms = Get-TfsTeamProject -Project $VARTFSproject
# If you need an Array of projects:
#$ARRprojects = Get-TfsTeamProject
# If you need an array of sprints:
#$ARRIterations = Get-TfsIteration -Project TFSPROJECT
#endregion Connect to TFS components
####################################################################
#Region BODY
####################################################################
###
### Body
###
####################################################################
#############################
## Get the Array of Tasks
$ARRTFSItems = Import-Csv -Path $VARfilepath
# List of columns expected in the CSV:
# areaPath
# iterationPath
# assignee
# title
# type #'Task' or 'Product Backlog Item'
# description
# parentItem
# $effort
# tags
## Start working through each of our TFS items and Create them.
Foreach ($tfsitem in $ARRTFSItems)
{
####################################################################
# Let's blank out the variables.
# if a property is "empty" in the array, when looping the variable isn't replaced by setting the variable
# to the property and so the previous use of that property for the pevious item in the loop is kept.
####################################################################
$areaPath = $null
$iterationPath = $null
$assignee = $null
$title = $null
$type = $null #'Task' or 'Product Backlog Item'
$description = $null
$parentItem = $null
$effort = $null
$tags = $null
## now we set the variables to the data in our TFS item in the Array
$areaPath = $tfsitem.areaPath
$iterationPath = $tfsitem.iterationPath
$assignee = $tfsitem.assignee
$title = $tfsitem.title
$type = $tfsitem.type
$description = $tfsitem.description
$effort = $tfsitem.effort
$tags = $tfsitem.Tags
$parentID = $null
####################################################################
# for the parent we need to do some custom work.
# if the item Type is a Backlog Item, then the parent is a #number of a feature.
# if the item type is a task - we need to get the backlog Item and it's number
####################################################################
If ($type -eq "Task")
{
#ok. so it's a task. We need to get the product backlog item from the specified title
$parenttitle = $tfsitem.parentItem
#we are going to look for the Title in TFS work items
[array]$ARRparentworkitem = Get-TfsWorkItem -Text $parenttitle
#we most likely will get back multiple so lets loop through and find just the backlog item
Foreach ($parentworkItem in $ARRparentworkitem)
{
$parentworkitemType = $parentworkitem.type.Name
If ($parentworkitemType -eq "Product Backlog Item")
{
$parentworkitemTitle = $parentworkitem.title
# and lets see if the backlog item is an exact title match
If ($parentworkitemTitle -eq $parenttitle)
{
#ok we have our match - so lets set the Parent
[int]$parentID = $parentworkitem.Id
#close the IF
}
#Close the IF
}
#close the ForEach
}
#close the IF
}
If ($type -eq "Product Backlog Item")
{
#ok. so it's a Product Backlog Item - meaning we should have the Parent ID
[int]$parentID = $tfsitem.parentItem
}
####################################################################
#
# Ok. Lets create the object now
#
####################################################################
# we create an essentially blank new item
$newTFSItem = New-TfsWorkItem -Title $title -Type $type -Project $VARTFSproject
# so we need the ID of the newTFSItem
[int]$Newid = $newTFSItem.Id
####################################################################
#
# Lets build a hash table of the properties
#
####################################################################
# we need on set for Backlog Items and another for Tasks
If ($type -eq "Task")
{
$HASHUpdateFields = @{
'Description'=$description
'Assigned To'=$assignee
'Iteration Path'=$IterationPath
'Area Path'=$areaPath
'Remaining Work'=$effort
'Tags'=$tags
}
#close IF
}
If ($type -eq "Product Backlog Item")
{
$HASHUpdateFields = @{
'Description'=$description
'Assigned To'=$assignee
'Iteration Path'=$IterationPath
'Area Path'=$areaPath
'Effort'=$effort
'Tags'=$tags
}
#close IF
}
####################################################################
#
# Using the SET command we are going to set the hash table to the NewID
#
####################################################################
Set-TfsWorkItem -WorkItem $Newid -Fields $HASHUpdateFields
####################################################################
#
# And now we need to connect it to it's parent.
# TARGET is the PARENT
# SOURCE is the CHILD
#
####################################################################
# lets make sure we have a parent before we link
If ($parentID -ne $null)
{
Add-TfsWorkItemLink -SourceWorkItem $Newid -TargetWorkItem $parentID -EndLinkType Parent
#Close IF
}
#close the ForEach
}
#endregion Body
A list of columns for the CSV Follows:
- areaPath
- iterationPath
- assignee
- title
- description
- effort
- tags
- type
- Task
- Product Backlog Item
- parentItem
- for Product Backlog Items it should be the # for the Parent Feature
- for task put the name of the Product Backlog items – which hopefully are unique…. go make it unique