GlobalList/GlobalList.ps1
<#
.SYNOPSIS Exports the contents of one or more Global Lists to XML. .DESCRIPTION This cmdlets generates an XML containing one or more global lists and their respective items, in the same format used by witadmin. It is functionally equivalent to 'witadmin exportgloballist' .PARAMETER Name Specifies the name of the global list to be exported. Wildcards are supported; when used, they result in a single XML containing all the matching global lists. .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.TfsTeamProjectCollection System.String System.Uri .EXAMPLE Export-TfsGlobalList | Out-File 'gl.xml' Exports all global lists in the current project collection to a file called gl.xml. .EXAMPLE Export-TfsGlobalList -Name 'Builds - *' Exports all build-related global lists (with names starting with 'Build - ') and return the resulting XML document .NOTES To export or list global lists, you must be a member of the Project Collection Valid Users group or have your View collection-level information permission set to Allow. #> Function Export-TfsGlobalList { [CmdletBinding()] [OutputType('string')] Param ( [Parameter(Position=0)] [Alias('Name')] [SupportsWildcards()] [string] $GlobalList = "*", [Parameter(ValueFromPipeline=$true)] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { $tpc = Get-TfsTeamProjectCollection $Collection $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore') $xml = [xml] $store.ExportGlobalLists() $procInstr = $xml.CreateProcessingInstruction("xml", 'version="1.0"') [void] $xml.InsertBefore($procInstr, $xml.DocumentElement) $nodesToRemove = $xml.SelectNodes("//GLOBALLIST") foreach($node in $nodesToRemove) { if (([System.Xml.XmlElement]$node).GetAttribute("name") -notlike $GlobalList) { [void]$xml.DocumentElement.RemoveChild($node) } } return $xml.OuterXml } } <# .SYNOPSIS Gets the contents of one or more Global Lists. .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.TfsTeamProjectCollection System.String System.Uri #> Function Get-TfsGlobalList { [CmdletBinding()] [OutputType('PSCustomObject')] Param ( [Parameter()] [Alias('Name')] [SupportsWildcards()] [string] $GlobalList = "*", [Parameter(ValueFromPipeline=$true)] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { $xml = [xml](Export-TfsGlobalList @PSBoundParameters) foreach($listNode in $xml.SelectNodes("//GLOBALLIST")) { $list = [PSCustomObject] [ordered] @{ Name = $listNode.GetAttribute("name") Items = @() } foreach($itemNode in $listNode.SelectNodes("LISTITEM")) { $list.Items += $itemNode.GetAttribute("value") } $list } } } <# .SYNOPSIS Imports one or more Global Lists from an XML document .DESCRIPTION This cmdletsimports an XML containing one or more global lists and their respective items, in the same format used by witadmin. It is functionally equivalent to 'witadmin importgloballist' .PARAMETER InputObject XML document object containing one or more global list definitions .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 System.Xml.XmlDocument .EXAMPLE Get-Content gl.xml | Import-GlobalList Imports the contents of an XML document called gl.xml to the current project collection .NOTES To import global lists, you must be a member of the Project Collection Administrators security group #> Function Import-TfsGlobalList { [CmdletBinding(ConfirmImpact='Medium')] Param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [Alias("Xml")] [object] $InputObject, [Parameter()] [switch] $Force, [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { $tpc = Get-TfsTeamProjectCollection $Collection $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore') if ($InputObject -is [xml]) { $doc = $InputObject.OuterXml } else { $doc = $InputObject } if (-not $Force) { $existingLists = Get-TfsGlobalList -Collection $tpc $listsInXml = ([xml]($InputObject)).SelectNodes('//*/@name')."#text" foreach($list in $existingLists) { if ($list.Name -in $listsInXml) { Throw "Global List '$($list.Name)' already exists. To overwrite an existing list, use the -Force switch." } } } [void] $store.ImportGlobalLists($doc) } } <# .SYNOPSIS Creates a new Global List. .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 System.String / System.String[] #> Function New-TfsGlobalList { [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)] [OutputType('PSCustomObject')] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')] [Alias('Name')] [string] $GlobalList, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Items')] [string[]] $Items, [Parameter()] [switch] $Force, [Parameter()] [object] $Collection, [Parameter()] [switch] $Passthru ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { [xml] $xml = Export-TfsGlobalList -Collection $Collection # Checks whether the global list already exists $list = $xml.SelectSingleNode("//GLOBALLIST[@name='$GlobalList']") if ($null -ne $list) { if ($Force.IsPresent) { if ($PSCmdlet.ShouldProcess($GlobalList, 'Overwrite existing global list')) { [void] $list.ParentNode.RemoveChild($list) } } else { Throw "Global List $GlobalList already exists. To overwrite an existing list, use the -Force switch." } } if($PSCmdlet.ShouldProcess($GlobalList, 'Create global list')) { # Creates the new list XML element $list = $xml.CreateElement("GLOBALLIST") $list.SetAttribute("name", $GlobalList) # Adds the item elements to the list foreach($item in $Items) { $itemElement = $xml.CreateElement("LISTITEM") [void] $itemElement.SetAttribute("value", $item) [void]$list.AppendChild($itemElement) } # Appends the new list to the XML obj [void] $xml.DocumentElement.AppendChild($list) Import-TfsGlobalList -Xml $xml -Collection $Collection $list = Get-TfsGlobalList -Name $GlobalList -Collection $Collection if ($Passthru) { return $list } } } } <# .SYNOPSIS Deletes one or more Global Lists. .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 System.String #> Function Remove-TfsGlobalList { [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)] Param ( [Parameter(ValueFromPipelineByPropertyName='Name')] [Alias('Name')] [SupportsWildcards()] [string] $GlobalList = "*", [Parameter()] [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { $tpc = Get-TfsTeamProjectCollection $Collection $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore') $lists = Get-TfsGlobalList -Name $GlobalList -Collection $Collection $listsToRemove = @() foreach($list in $lists) { if ($PSCmdlet.ShouldProcess($list.Name, "Remove global list")) { $listsToRemove += $list } } if ($listsToRemove.Length -eq 0) { return } $xml = [xml] "<Package />" foreach($list in $listsToRemove) { $elem = $xml.CreateElement("DestroyGlobalList"); $elem.SetAttribute("ListName", "*" + $list.Name); $elem.SetAttribute("ForceDelete", "true"); [void]$xml.DocumentElement.AppendChild($elem); } $returnElem = $null $store.SendUpdatePackage($xml.DocumentElement, [ref] $returnElem, $false) } } <# .SYNOPSIS Changes the name or the contents of a Global List. .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 System.String #> Function Set-TfsGlobalList { [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')] [Alias('Name')] [string] $GlobalList, [Parameter(ParameterSetName="Edit list items")] [string[]] $Add, [Parameter(ParameterSetName="Edit list items")] [string[]] $Remove, [Parameter(ParameterSetName="Rename list", Mandatory=$true)] [string] $NewName, [Parameter(ParameterSetName="Edit list items")] [switch] $Force, [object] $Collection ) Begin { #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client' } Process { $xml = [xml] (Export-TfsGlobalList -Name $GlobalList -Collection $Collection) # Retrieves the list $list = $xml.SelectSingleNode("//GLOBALLIST") $newList = $false if ($null -eq $list) { if (-not $Force.IsPresent) { throw "Global list name $GlobalList is invalid or non-existent. Either check the name or use -Force to create a new list." } # Creates the new list XML element $list = $xml.CreateElement("GLOBALLIST") [void] $list.SetAttribute("name", $GlobalList) [void] $xml.DocumentElement.AppendChild($list) $newList = $true } if ($PSCmdlet.ParameterSetName -eq "Rename list") { if($PSCmdlet.ShouldProcess($GlobalList, "Rename global list to $NewName")) { $list.SetAttribute("name", $NewName) Import-TfsGlobalList -Xml $xml -Collection $Collection Remove-TfsGlobalList -Name $GlobalList -Collection $Collection -Confirm:$false } return Get-TfsGlobalList -Name $NewName -Collection $Collection } foreach($item in $Add) { if (-not $newList) { # Checks if the element exists (prevents duplicates) $existingItem = $list.SelectSingleNode("LISTITEM[@value='$item']") if ($null -ne $existingItem) { continue } } if($PSCmdlet.ShouldProcess($GlobalList, "Add item '$item' to global list")) { $isDirty = $true $itemElement = $xml.CreateElement("LISTITEM") [void] $itemElement.SetAttribute("value", $item) [void]$list.AppendChild($itemElement) } } if (-not $newList) { foreach($item in $Remove) { $existingItem = $list.SelectSingleNode("LISTITEM[@value='$item']") if ($existingItem -and $PSCmdlet.ShouldProcess($GlobalList, "Remove item '$item' from global list")) { $isDirty = $true [void]$list.RemoveChild($existingItem) } } } # Saves the list back to TFS if($isDirty) { Import-TfsGlobalList -Xml $xml -Collection $Collection -Force } return Get-TfsGlobalList -Name $GlobalList -Collection $Collection } } |