Work/Work.ps1
<#
.SYNOPSIS Gets information about one or more backlogs of the given team. .PARAMETER Project Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any). For more details, see the Get-TfsTeamProject cmdlet. .PARAMETER Collection Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object. When using a URL, it must be fully qualified. The format of this string is as follows: http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName> Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS. To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet. For more details, see the Get-TfsTeamProjectCollection cmdlet. .INPUTS Microsoft.TeamFoundation.Core.WebApi.WebApiTeam System.String #> Function Get-TfsTeamBacklog { [CmdletBinding()] [OutputType('Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration')] param ( [Parameter(Position=0)] [Alias("Name")] [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration])})] [SupportsWildcards()] [object] $Backlog = '*', [Parameter(ValueFromPipeline=$true)] [object] $Team, [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Begin { # #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' # #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi' } Process { if ($Backlog -is [Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration]) { _Log "Input item is of type Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration; returning input item immediately, without further processing."; return $Backlog } $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection $client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList @($tp.Name, $t.Name) if (-not $Backlog.ToString().Contains('*')) { _Log "Get backlog '$Backlog'" $task = $client.GetBacklogAsync($ctx, $Backlog) $result = $task.Result; if($task.IsFaulted) { throw "Error getting backlog '$Backlog'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } } else { _Log "Get all backlogs matching '$Backlog'" $task = $client.GetBacklogsAsync($ctx) $result = $task.Result; if($task.IsFaulted) { throw 'Error enumerating backlogs' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } $result = $result | Where-Object Name -like $Backlog } return $result } } Function Get-TfsTeamBoard { [CmdletBinding()] [OutputType('Microsoft.TeamFoundation.Work.WebApi.Board')] Param ( # Specifies the board name(s). Wildcards accepted [Parameter(Position=0)] [SupportsWildcards()] [Alias('Name')] [object] $Board = '*', [Parameter()] [switch] $SkipDetails, [Parameter(ValueFromPipeline=$true)] [object] $Team, [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' } Process { if ($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board]) { _Log "Input item is of type Microsoft.TeamFoundation.Work.WebApi.Board; returning input item immediately, without further processing."; return $Board } $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection $client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name _Log "Getting boards matching '$Board' in team '$($t.Name)'" $task = $client.GetBoardsAsync($ctx); $result = $task.Result; if($task.IsFaulted) { throw 'Error retrieving team boards' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } $boardRefs = $result | Where-Object Name -like $Board _Log "Found $($boardRefs.Count) boards matching '$Board' in team '$($t.Name)'" if($SkipDetails.IsPresent) { _Log "SkipDetails switch is present. Returning board references without details" return $boardRefs } foreach($b in $boardRefs) { _Log "Fetching details for board '$($b.Name)'" $task = $client.GetBoardAsync($ctx, $b.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error fetching board data" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } Write-Output $result } } } Function Get-TfsTeamBoardCardRuleSettings { [CmdletBinding()] [OutputType('Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings')] Param ( [Parameter()] [SupportsWildcards()] [object] $Board = '*', [Parameter(ValueFromPipeline=$true)] [object] $Team, [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' } Process { if($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board]) { $boards = @($Board.Name) $Team = ([uri] $b.Links.Links.team.Href).Segments[-1] $Project = ([uri] $b.Links.Links.project.Href).Segments[-1] _Log "Getting card rules for board $($Board.Name) in team $Team" } elseif ($Board.ToString().Contains('*')) { _Log "Getting card rules for boards matching '$Board' in team $Team" $boards = (Get-TfsTeamBoard -Board $Board -SkipDetails -Team $Team -Project $Project -Collection $Collection).Name _Log "$($boards.Count) board(s) found matching '$Board'" } else { _Log "Getting card rules for board $($Board.Name) in team $Team" $boards = @($Board) } $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection $client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc foreach($boardName in $boards) { $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name _Log "Fetching card rule settings for board $boardName" $task = $client.GetBoardCardRuleSettingsAsync($ctx,$boardName); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving card rule settings for board '$Board'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } Write-Output $result ` | Add-Member -Name 'Team' -MemberType NoteProperty -Value $t.Name -PassThru ` | Add-Member -Name 'Project' -MemberType NoteProperty -Value $tp.Name -PassThru } } } Function Set-TfsTeamBoardCardRuleSettings { [CmdletBinding()] [OutputType('Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings')] Param ( [Parameter()] [object] $Board, [Parameter(ParameterSetName="Bulk set")] [Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings] $Rules, [Parameter(ParameterSetName="Set individual rules")] [string] $CardStyleRuleName, [Parameter(ParameterSetName="Set individual rules")] [string] $CardStyleRuleFilter, [Parameter(ParameterSetName="Set individual rules")] [hashtable] $CardStyleRuleSettings, [Parameter(ParameterSetName="Set individual rules")] [string] $TagStyleRuleName, [Parameter(ParameterSetName="Set individual rules")] [string] $TagStyleRuleFilter, [Parameter(ParameterSetName="Set individual rules")] [hashtable] $TagStyleRuleSettings, [Parameter(ValueFromPipeline=$true)] [object] $Team, [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' } Process { Write-Verbose "Getting card rules for team $Team" if($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board]) { $boards = @($Board.Name) $Team = ([uri] $b.Links.Links.team.Href).Segments[-1] $Project = ([uri] $b.Links.Links.project.Href).Segments[-1] } elseif ($Board.ToString().Contains('*')) { $boards = (Get-TfsTeamBoard -Board $Board -Team $Team -Project $Project -Collection $Collection).Name } else { $boards = @($Board) } $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection $client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc foreach($boardName in $boards) { $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name $task = $client.GetBoardCardRuleSettingsAsync($ctx,$boardName); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving card rule settings for board '$Board'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } Write-Output $result ` | Add-Member -Name 'Team' -MemberType NoteProperty -Value $t.Name -PassThru ` | Add-Member -Name 'Project' -MemberType NoteProperty -Value $tp.Name -PassThru } } } Function Set-TfsWorkItemBoardStatus { [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)] [OutputType('Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItem')] Param ( [Parameter(ValueFromPipeline=$true, Position=0)] [Alias("id")] [ValidateNotNull()] [object] $WorkItem, [Parameter()] [object] $Board, [Parameter()] [object] $Column, [Parameter()] [object] $Lane, [Parameter()] [ValidateSet('Doing', 'Done')] [string] $ColumnStage, [Parameter()] [object] $Team, [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi' } Process { if ((-not $Column) -and (-not $ColumnStage) -and (-not $Lane)) { throw 'Supply a value to at least one of the following arguments: Column, ColumnStage, Lane' } if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem]) { $tp = $WorkItem.Project $tpc = $WorkItem.Store.TeamProjectCollection } else { $tp = Get-TfsTeamProject -Project $Project -Collection $Collection $tpc = $tp.Store.TeamProjectCollection $WorkItem = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection } $t = Get-TfsTeam -Team $Team -Project $tp -Collection $tpc $id = [int] $WorkItem.Id $rev = $WorkItem.Revision # Get the Kanban board column/lane field info $b = Get-TfsBoard -Board $Board -Team $t -Project $tp -Collection $tpc if (-not $b) { throw "Invalid or non-existent board '$Board' in team '$Team'" } $processMessages = @() $ops = @( @{ Operation = 'Test'; Path = '/rev'; Value = $rev.ToString() } ) if ($Column) { $ops += @{ Operation = 'Add'; Path = "/fields/$($b.Fields.ColumnField.ReferenceName)"; Value = $Column } $processMessages += "Board Column='$Column'" } if ($Lane) { $ops += @{ Operation = 'Add'; Path = "/fields/$($b.Fields.RowField.ReferenceName)"; Value = $Lane } $processMessages += "Board Lane='$Lane'" } if ($ColumnStage) { $ops += @{ Operation = 'Add'; Path = "/fields/$($b.Fields.DoneField.ReferenceName)"; Value = ($ColumnStage -eq 'Done') } $processMessages += "Board Stage (Doing/Done)='$ColumnStage'" } if ($PSCmdlet.ShouldProcess("$($WorkItem.WorkItemType) $id ('$($WorkItem.Title)')", "Set work item board status: $($processMessages -join ', ')")) { $patch = _GetJsonPatchDocument $ops $client = _GetRestClient 'Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItemTrackingHttpClient' -Collection $tpc $wi = $client.UpdateWorkItemAsync($patch, $id).Result return $wi } } } |