Team/Team.ps1
<#
.SYNOPSIS Gets information about one or more teams. .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.WorkItemTracking.Client.Project System.String #> Function Get-TfsTeam { [CmdletBinding()] [OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')] param ( [Parameter(Position=0)] [Alias("Name")] [SupportsWildcards()] [object] $Team = '*', [Parameter()] [switch] $IncludeMembers, [Parameter()] [switch] $IncludeSettings, [Parameter(ValueFromPipeline=$true)] [object] $Project, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' } Process { if ($Team -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam]) { _Log "Input item is of type Microsoft.TeamFoundation.Core.WebApi.WebApiTeam; returning input item immediately, without further processing."; return $Team } $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.Core.WebApi.TeamHttpClient' -Collection $tpc $workClient = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' if($Team.ToString().Contains('*')) { _Log "Get all teams matching '$Team'" $teams = $client.GetTeamsAsync($tp.Name).Result | Where-Object Name -like $Team } else { _Log "Get team named '$Team'" if(_TestGuid $Team) { $Team = [guid]$Team } $teams = $client.GetTeamAsync($tp.Name, $Team).Result } foreach($t in $teams) { if ($IncludeMembers.IsPresent) { _Log "Retrieving team membership information for team '$($t.Name)'" $members = $client.GetTeamMembersWithExtendedPropertiesAsync($tp.Name, $t.Name).Result $t | Add-Member -Name 'Members' -MemberType NoteProperty -Value $members } else { $t | Add-Member -Name 'Members' -MemberType NoteProperty -Value @() } if ($IncludeSettings.IsPresent) { _Log "Retrieving team settings for team '$($t.Name)'" $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name $t | Add-Member -Name 'Settings' -MemberType NoteProperty -Value $workClient.GetTeamSettingsAsync($ctx).Result } else { $t | Add-Member -Name 'Settings' -MemberType NoteProperty -Value $null } } return $teams } } <# .SYNOPSIS Creates a new 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. .PARAMETER Passthru Returns the results of the command. By default, this cmdlet does not generate any output. .INPUTS System.String #> Function New-TfsTeam { [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)] [OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [Alias("Name")] [string] $Team, [Parameter()] [string] $Description, [Parameter()] [object] $Project, [Parameter()] [object] $Collection, [Parameter()] [switch] $Passthru ) Begin { } Process { if (-not $PSCmdlet.ShouldProcess($Project, "Create team $Team")) { return } $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.Core.WebApi.TeamHttpClient' $result = $client.CreateTeamAsync((New-Object 'Microsoft.TeamFoundation.Core.WebApi.WebApiTeam' -Property @{ Name = $Team Description = $Description }), $tp.Name).Result if ($Passthru) { return $result } } } <# .SYNOPSIS Deletes a 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.Client.TeamFoundationTeam System.String #> Function Remove-TfsTeam { [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')] [OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')] param ( [Parameter(Position=0, ValueFromPipeline=$true)] [Alias("Name")] [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])})] [SupportsWildcards()] [object] $Team = '*', [Parameter()] [object] $Project, [Parameter()] [object] $Collection ) Process { if($Team.ProjectName) {$Project = $Team.ProjectName}; $tpc = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tp = $tpc.Store.TeamProjectCollection $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection if (-not $PSCmdlet.ShouldProcess($t.Name, 'Delete team')) { return } $client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TeamHttpClient' $task = $client.DeleteTeamAsync($tp.Name, $t.Name) $result = $task.Result; if($task.IsFaulted) { throw 'Error deleting team' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } } } <# .SYNOPSIS Renames a 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.Client.TeamFoundationTeam System.String #> Function Rename-TfsTeam { [CmdletBinding(ConfirmImpact='Medium')] [OutputType('Microsoft.TeamFoundation.Client.TeamFoundationTeam')] param ( [Parameter(Position=0, ValueFromPipeline=$true)] [Alias("Name")] [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Client.TeamFoundationTeam])})] [SupportsWildcards()] [object] $Team = '*', [Parameter()] [string] $NewName, [Parameter()] [object] $Project, [Parameter()] [object] $Collection, [Parameter()] [switch] $Passthru ) Process { $result = Set-TfsTeam -Team $Team -NewName $NewName -Project $Project -Collection $Collection if ($Passthru) { return $result } } } <# .SYNOPSIS Changes the details of a 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 Set-TfsTeam { [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] [OutputType('Microsoft.TeamFoundation.Client.TeamFoundationTeam')] param ( [Parameter(Position=0, ValueFromPipeline=$true)] [Alias("Name")] [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])})] [SupportsWildcards()] [object] $Team = '*', [Parameter()] [switch] $Default, [Parameter()] [string] $NewName, [Parameter()] [string] $Description, [Parameter()] [Alias('TeamFieldValue')] [string] $DefaultAreaPath, [Parameter()] [hashtable] $AreaPaths, [Parameter()] [string] $BacklogIteration, [Parameter()] [object] $IterationPaths, # Default iteration macro [Parameter()] [string] $DefaultIterationMacro, #= '@CurrentIteration' # Working Days. Defaults to Monday thru Friday [Parameter()] [string[]] $WorkingDays, #= @("monday", "tuesday", "wednesday", "thursday", "friday"), # Bugs behavior [Parameter()] [ValidateSet('AsTasks', 'AsRequirements', 'Off')] [string] $BugsBehavior, [Parameter()] [hashtable] $BacklogVisibilities, [Parameter()] [object] $Project, [Parameter()] [object] $Collection, [Parameter()] [switch] $Passthru ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi' } Process { $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection if ($Project) { $tp = Get-TfsTeamProject -Project $Project -Collection $Collection $tpc = $tp.Store.TeamProjectCollection } else { $tpc = Get-TfsTeamProjectCollection -Collection $Collection } $teamService = $tpc.GetService([type]'Microsoft.TeamFoundation.Client.TfsTeamService') if ($NewName -and $PSCmdlet.ShouldProcess($Team, "Rename team to '$NewName'")) { $isDirty = $true $t.Name = $NewName } if ($PSBoundParameters.ContainsKey('Description') -and $PSCmdlet.ShouldProcess($Team, "Set team's description to '$Description'")) { $isDirty = $true $t.Description = $Description } if ($Default -and $PSCmdlet.ShouldProcess($Team, "Set team to project's default team")) { $teamService.SetDefaultTeam($t) } if($isDirty) { $teamService.UpdateTeam($t) } # Prepare for the second stage $client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc $ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList @($tp.Name, $t.Name) # Set Team Field and Area Path settings $patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValuesPatch' if($DefaultAreaPath -and $PSCmdlet.ShouldProcess($Team, "Set the team's default area path (team field value in TFS) to $DefaultAreaPath")) { if($tpc.IsHostedServer) { _Log "Conected to Azure DevOps Server. Treating Team Field Value as Area Path" $DefaultAreaPath = _NormalizeCssNodePath -Project $tp.Name -Path $DefaultAreaPath -IncludeTeamProject } if(-not $AreaPaths) { _Log "AreaPaths is empty. Adding DefaultAreaPath (TeamFieldValue) to AreaPaths as default value." $AreaPaths = @{ $DefaultAreaPath = $true } } _Log "Setting default area path (team field) to $DefaultAreaPath" $patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValuesPatch' -Property @{ DefaultValue = $DefaultAreaPath } $values = @() foreach($a in $AreaPaths.GetEnumerator()) { $values += New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValue' -Property @{ Value = _NormalizeCssNodePath -Project $tp.Name -Path $a.Key -IncludeTeamProject IncludeChildren = $a.Value } } $patch.Values = [Microsoft.TeamFoundation.Work.WebApi.TeamFieldValue[]] $values $task = $client.UpdateTeamFieldValuesAsync($patch, $ctx) $result = $task.Result; if($task.IsFaulted) { throw 'Error applying team field value and/or area path settings' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } } # Set backlog and iteration path settings $patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamSettingsPatch' $isDirty = $false if ($BacklogIteration -and $PSCmdlet.ShouldProcess($Team, "Set the team's backlog iteration to $BacklogIteration")) { _Log "Setting backlog iteration to $BacklogIteration" $iteration = Get-TfsIteration -Iteration $BacklogIteration -Project $Project -Collection $Collection $patch.BacklogIteration = [guid] $iteration.Id $patch.DefaultIteration = [guid] $iteration.Id $isDirty = $true } if ($DefaultIteration -and $PSCmdlet.ShouldProcess($Team, "Set the team's default iteration to $DefaultIteration")) { _Log "Setting default iteration to $DefaultIteration" $iteration = Get-TfsIteration -Iteration $BacklogIteration -Project $Project -Collection $Collection $patch.DefaultIteration = [guid] $iteration.Id $isDirty = $true } if ($BacklogVisibilities -and $PSCmdlet.ShouldProcess($Team, "Set the team's backlog visibilities to $(_DumpObj $BacklogVisibilities)")) { _Log "Setting backlog iteration to $BacklogVisibilities" $patch.BacklogVisibilities = _NewDictionary @([string], [bool]) $BacklogVisibilities $isDirty = $true } if ($DefaultIterationMacro -and $PSCmdlet.ShouldProcess($Team, "Set the team's default iteration macro to $DefaultIterationMacro")) { _Log "Setting default iteration macro to $DefaultIterationMacro" $patch.DefaultIterationMacro = $DefaultIterationMacro $isDirty = $true } if ($WorkingDays -and $PSCmdlet.ShouldProcess($Team, "Set the team's working days to $(_DumpObj $WorkingDays)")) { _Log "Setting working days to $($WorkingDays|ConvertTo=-Json -Compress)" $patch.WorkingDays = $WorkingDays $isDirty = $true } if($BugsBehavior -and $PSCmdlet.ShouldProcess($Team, "Set the team's bugs behavior to $(_DumpObj $BugsBehavior)")) { _Log "Setting bugs behavior to $(_DumpObj $BugsBehavior)" $patch.BugsBehavior = $BugsBehavior $isDirty = $true } if($isDirty) { $task = $client.UpdateTeamSettingsAsync($patch, $ctx) $result = $task.Result; if($task.IsFaulted) { throw 'Error applying iteration settings' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" } } if($Passthru.IsPresent) { return $t } } } |