{"id":132,"date":"2019-01-17T20:24:50","date_gmt":"2019-01-17T20:24:50","guid":{"rendered":"https:\/\/www.atlanta247.com\/blog\/?p=132"},"modified":"2019-11-20T16:07:30","modified_gmt":"2019-11-20T16:07:30","slug":"powershell-to-create-tfs-backlog-items","status":"publish","type":"post","link":"https:\/\/www.atlanta247.com\/blog\/2019\/01\/17\/powershell-to-create-tfs-backlog-items\/","title":{"rendered":"Powershell to Create TFS Backlog Items"},"content":{"rendered":"\n<p>I work with Team foundation server &#8211; keeping track of projects, etc&#8230; and now that it&#8217;s January i had 100+ tasks to create.   I thought to myself&#8230; why do this manually?<br><br><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>####################################################################\n###\n###  Script to create TFS entries from CSV file\n###  by Jeremy Castleberry \n###  created 1-16-2019\n###  last update 1-17-2019\n###  Version 1\n###\n####################################################################\n\n#region Log Of Changes\n####################################################################\n###\n###  \n###  \n###\n###\n###\n###\n####################################################################\n#endregion Log of Changes\n####################################################################\n\n\n#region FUNCTIONS\n\n#############################################################################\n##\n## Function from Hey Scripting Guys!\n##  https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/09\/01\/hey-scripting-guy-can-i-open-a-file-dialog-box-with-windows-powershell\/\n##\n#############################################################################\n\nFunction Get-FileName($initialDirectory)\n\t{   \n \t[System.Reflection.Assembly]::LoadWithPartialName(\"System.windows.forms\") |\n \tOut-Null\n\t\n \t$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog\n \t$OpenFileDialog.initialDirectory = $initialDirectory\n \t$OpenFileDialog.filter = \"All files (*.*)| *.*\"\n \t$OpenFileDialog.ShowDialog() | Out-Null\n \t$OpenFileDialog.filename\n\t} \n#end function Get-FileName\n\n\n#endregion FUNCTIONS\n\n\n#region Get Input File\n#We need to prompt for the file. \n\n[string]$VARfilepath  = Get-FileName\n\n# or set it hardcoded\n#$VARfilepath = \"c:\\temp\\tasks.csv\"\n\n#EndRegion Get Input File\n####################################################################\n\n#region Modules\n# Import whichever modules we need\nImport-Module TfsCmdlets -Force\n\n#endregion Modules\n####################################################################\n\n#region Variables\n[string]$VARUrl = \"http:\/\/YOURSERVER:####\/tfs\/Projects\/\"\n[string]$VARTFSproject = \"TFSPROJECT\"\n[array]$ARRTFSItems = @()\n\n#endregion Variables\n####################################################################\n\n#region Connect to TFS components\n\n#First to the server\nConnect-TfsTeamProjectCollection $VARUrl\n\n# and now our project \nConnect-TfsTeamProject -Project $VARTFSproject\n$OBJtms = Get-TfsTeamProject -Project $VARTFSproject\n\n# If you need an Array of projects:\n#$ARRprojects = Get-TfsTeamProject\n\n# If you need an array of sprints:\n#$ARRIterations = Get-TfsIteration -Project TFSPROJECT\n\n#endregion Connect to TFS components\n####################################################################\n\n#Region BODY\n####################################################################\n###\n###  Body\n###\n####################################################################\n\n#############################\n## Get the Array of Tasks\n\n\n$ARRTFSItems = Import-Csv -Path $VARfilepath\n\n# List of columns expected in the CSV:\n# areaPath\n# iterationPath\n# assignee\n# title\n# type    #'Task' or 'Product Backlog Item'\n# description\n# parentItem\n# $effort\n# tags\n\n## Start working through each of our TFS items and Create them.\n\nForeach ($tfsitem in $ARRTFSItems)\n\t{\n\t####################################################################\n\t# Let's blank out the variables.  \n\t# if a property is \"empty\" in the array,  when looping the variable isn't replaced by setting the variable\n\t# to the property and so the previous use of that property for the pevious item in the loop is kept.  \n\t####################################################################\n\t\n\t$areaPath = $null\n\t$iterationPath = $null\n\t$assignee = $null\n\t$title = $null\n\t$type = $null     #'Task' or 'Product Backlog Item'\n\t$description = $null\n\t$parentItem = $null\n\t$effort = $null\n\t$tags = $null\n\t\n\t## now we set the variables to the data in our TFS item in the Array\n\t\n\t$areaPath = $tfsitem.areaPath\n\t$iterationPath = $tfsitem.iterationPath\n\t$assignee = $tfsitem.assignee\n\t$title = $tfsitem.title\n\t$type = $tfsitem.type\n\t$description = $tfsitem.description\n\t$effort = $tfsitem.effort\n\t$tags = $tfsitem.Tags\n\t$parentID = $null\n\t\n\t####################################################################\n\t# for the parent we need to do some custom work.\n\t# if the item Type is a Backlog Item, then the parent is a #number of a feature. \n\t# if the item type is a task - we need to get the backlog Item and it's number\n\t####################################################################\n\t\n\tIf ($type -eq \"Task\")\n\t\t{\n\t\t#ok. so it's a task.  We need to get the product backlog item from the specified title\n\t\t$parenttitle = $tfsitem.parentItem\n\t\t\t\t\n\t\t#we are going to look for the Title in TFS work items\n\t\t[array]$ARRparentworkitem = Get-TfsWorkItem -Text $parenttitle\n\t\t\t\t\n\t\t#we most likely will get back multiple so lets loop through and find just the backlog item\n\t\t\n\t\tForeach ($parentworkItem in $ARRparentworkitem)\n\t\t\t{\n\t\t\t$parentworkitemType = $parentworkitem.type.Name\n\t\t\t\n\t\t\tIf ($parentworkitemType -eq \"Product Backlog Item\")\n\t\t\t\t{\n\t\t\t\t\n\t\t\t\t$parentworkitemTitle = $parentworkitem.title\n\t\t\t\t# and lets see if the backlog item is an exact title match\n\t\t\t\t\tIf ($parentworkitemTitle -eq $parenttitle)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t#ok we have our match - so lets set the Parent\n\t\t\t\t\t\t[int]$parentID = $parentworkitem.Id\n\t\t\t\t\t\n\t\t\t\t\t\t#close the IF\n\t\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t#Close the IF\n\t\t\t\t}\n\t\t\t\t\n\t\t\t#close the ForEach\n\t\t\t}\n\t\t\n\t\t\n\t\t#close the IF\n\t\t}\n\t\n\tIf ($type -eq \"Product Backlog Item\")\n\t\t{\n\t\t#ok. so it's a Product Backlog Item - meaning we should have the Parent ID \n\t\n\t\t[int]$parentID = $tfsitem.parentItem\n\t\t}\n\t\t\t\n\t\t\n\t\n\n\n\t####################################################################\n\t#\n\t# Ok. Lets create the object now\n\t#\n\t####################################################################\n\t\n\t# we create an essentially blank new item\n\n\t$newTFSItem = New-TfsWorkItem -Title $title -Type $type -Project $VARTFSproject\n\t\t\n\t# so we need the ID of the newTFSItem\n\n\t[int]$Newid = $newTFSItem.Id\n\n\t####################################################################\n\t#\n\t# Lets build a hash table of the properties\n\t#\n\t####################################################################\n\t\n\t# we need on set for Backlog Items and another for Tasks\n\n\tIf ($type -eq \"Task\")\n\t\t{\n\t\t\n\t\t$HASHUpdateFields = @{\n\t\t\t'Description'=$description\n\t\t\t'Assigned To'=$assignee\n\t\t\t'Iteration Path'=$IterationPath\n\t\t\t'Area Path'=$areaPath\n\t\t\t'Remaining Work'=$effort\n\t\t\t'Tags'=$tags\n\t\t\t}\t\n\t\t\n\t\t#close IF\n\t\t}\n\t\t\n\tIf ($type -eq \"Product Backlog Item\")\n\t\t{\t\n\t\t$HASHUpdateFields = @{\n\t\t\t'Description'=$description\n\t\t\t'Assigned To'=$assignee\n\t\t\t'Iteration Path'=$IterationPath\n\t\t\t'Area Path'=$areaPath\n\t\t\t'Effort'=$effort\n\t\t\t'Tags'=$tags\n\t\t\t}\n\t\t\n\t\t#close IF\n\t\t}\n\n\t####################################################################\n\t#\n\t# Using the SET command we are going to set the hash table to the NewID\n\t#\n\t####################################################################\n\t\n\tSet-TfsWorkItem -WorkItem $Newid -Fields $HASHUpdateFields\n\n\n\t####################################################################\n\t#\n\t# And now we need to connect it to it's parent.\n\t# TARGET is the PARENT \n\t# SOURCE is the CHILD\n\t#\n\t####################################################################\n\t\n\t# lets make sure we have a parent before we link\n\t\n\tIf ($parentID -ne $null)\n\t\t{\n\t\tAdd-TfsWorkItemLink -SourceWorkItem $Newid -TargetWorkItem $parentID -EndLinkType Parent\t\n\t\t\n\t\t#Close IF\n\t\t}\n\t\n\t#close the ForEach\n\t}\t\n\n#endregion Body\n<\/code><\/pre>\n\n\n\n<p>A list of columns for the CSV Follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>areaPath <\/li><li>iterationPath<\/li><li>assignee<\/li><li>title<\/li><li>description<\/li><li>effort<\/li><li>tags<\/li><li>type <ul><li>Task<\/li><li>Product Backlog Item<\/li><\/ul><\/li><li>parentItem<ul><li>for Product Backlog Items it should be the # for the Parent Feature<\/li><li>for task put the name of the Product Backlog items &#8211; which hopefully are unique&#8230;. go make it unique<\/li><\/ul><\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\"><br><\/h1>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I work with Team foundation server &#8211; keeping track of projects, etc&#8230; and now that it&#8217;s January i had 100+ tasks to create. I thought to myself&#8230; why do this manually? A list of columns for the CSV Follows: areaPath iterationPath assignee title description effort tags type Task Product Backlog Item parentItem for Product Backlog &hellip; <a href=\"https:\/\/www.atlanta247.com\/blog\/2019\/01\/17\/powershell-to-create-tfs-backlog-items\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Powershell to Create TFS Backlog Items<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[8,27,7],"tags":[],"class_list":["post-132","post","type-post","status-publish","format-standard","hentry","category-powershell","category-tfs","category-work"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/posts\/132","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/comments?post=132"}],"version-history":[{"count":1,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/posts\/132\/revisions"}],"predecessor-version":[{"id":133,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/posts\/132\/revisions\/133"}],"wp:attachment":[{"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/media?parent=132"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/categories?post=132"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.atlanta247.com\/blog\/wp-json\/wp\/v2\/tags?post=132"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}