Unpacking Software Livestream

Join our monthly Unpacking Software livestream to hear about the latest news, chat and opinion on packaging, software deployment and lifecycle management!

Learn More

Chocolatey Product Spotlight

Join the Chocolatey Team on our regular monthly stream where we put a spotlight on the most recent Chocolatey product releases. You'll have a chance to have your questions answered in a live Ask Me Anything format.

Learn More

Chocolatey Coding Livestream

Join us for the Chocolatey Coding Livestream, where members of our team dive into the heart of open source development by coding live on various Chocolatey projects. Tune in to witness real-time coding, ask questions, and gain insights into the world of package management. Don't miss this opportunity to engage with our team and contribute to the future of Chocolatey!

Learn More

Calling All Chocolatiers! Whipping Up Windows Automation with Chocolatey Central Management

Webinar from
Wednesday, 17 January 2024

We are delighted to announce the release of Chocolatey Central Management v0.12.0, featuring seamless Deployment Plan creation, time-saving duplications, insightful Group Details, an upgraded Dashboard, bug fixes, user interface polishing, and refined documentation. As an added bonus we'll have members of our Solutions Engineering team on-hand to dive into some interesting ways you can leverage the new features available!

Watch On-Demand
Chocolatey Community Coffee Break

Join the Chocolatey Team as we discuss all things Community, what we do, how you can get involved and answer your Chocolatey questions.

Watch The Replays
Chocolatey and Intune Overview

Webinar Replay from
Wednesday, 30 March 2022

At Chocolatey Software we strive for simple, and teaching others. Let us teach you just how simple it could be to keep your 3rd party applications updated across your devices, all with Intune!

Watch On-Demand
Chocolatey For Business. In Azure. In One Click.

Livestream from
Thursday, 9 June 2022

Join James and Josh to show you how you can get the Chocolatey For Business recommended infrastructure and workflow, created, in Azure, in around 20 minutes.

Watch On-Demand
The Future of Chocolatey CLI

Livestream from
Thursday, 04 August 2022

Join Paul and Gary to hear more about the plans for the Chocolatey CLI in the not so distant future. We'll talk about some cool new features, long term asks from Customers and Community and how you can get involved!

Watch On-Demand
Hacktoberfest Tuesdays 2022

Livestreams from
October 2022

For Hacktoberfest, Chocolatey ran a livestream every Tuesday! Re-watch Cory, James, Gary, and Rain as they share knowledge on how to contribute to open-source projects such as Chocolatey CLI.

Watch On-Demand

Downloads:

5,021

Downloads of v 2.0.0-beta0004:

119

Last Update:

29 Aug 2019

Package Maintainer(s):

Software Author(s):

  • Igor Abade V. Leite

Tags:

tfscmdlets tfs vsts powershell azure azuredevops devops alm teamfoundationserver

TfsCmdlets

This is a prerelease version of TfsCmdlets.

  • 1
  • 2
  • 3

2.0.0-beta0004 | Updated: 29 Aug 2019

Downloads:

5,021

Downloads of v 2.0.0-beta0004:

119

Maintainer(s):

Software Author(s):

  • Igor Abade V. Leite

TfsCmdlets 2.0.0-beta0004

This is a prerelease version of TfsCmdlets.

Legal Disclaimer: Neither this package nor Chocolatey Software, Inc. are affiliated with or endorsed by Igor Abade V. Leite. The inclusion of Igor Abade V. Leite trademark(s), if any, upon this webpage is solely to identify Igor Abade V. Leite goods or services and not for commercial purposes.

  • 1
  • 2
  • 3

Some Checks Have Failed or Are Not Yet Complete

Not All Tests Have Passed


Validation Testing Failed


Verification Testing Passed

Details

Scan Testing Successful:

No detections found in any package files

Details
Learn More

Deployment Method: Individual Install, Upgrade, & Uninstall

To install TfsCmdlets, run the following command from the command line or from PowerShell:

>

To upgrade TfsCmdlets, run the following command from the command line or from PowerShell:

>

To uninstall TfsCmdlets, run the following command from the command line or from PowerShell:

>

Deployment Method:

NOTE

This applies to both open source and commercial editions of Chocolatey.

1. Enter Your Internal Repository Url

(this should look similar to https://community.chocolatey.org/api/v2/)


2. Setup Your Environment

1. Ensure you are set for organizational deployment

Please see the organizational deployment guide

2. Get the package into your environment

  • Open Source or Commercial:
    • Proxy Repository - Create a proxy nuget repository on Nexus, Artifactory Pro, or a proxy Chocolatey repository on ProGet. Point your upstream to https://community.chocolatey.org/api/v2/. Packages cache on first access automatically. Make sure your choco clients are using your proxy repository as a source and NOT the default community repository. See source command for more information.
    • You can also just download the package and push it to a repository Download

3. Copy Your Script

choco upgrade tfscmdlets -y --source="'INTERNAL REPO URL'" --version="'2.0.0-beta0004'" --prerelease [other options]

See options you can pass to upgrade.

See best practices for scripting.

Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.

If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:


choco upgrade tfscmdlets -y --source="'INTERNAL REPO URL'" --version="'2.0.0-beta0004'" --prerelease
$exitCode = $LASTEXITCODE

Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
  Exit 0
}

Exit $exitCode

- name: Install tfscmdlets
  win_chocolatey:
    name: tfscmdlets
    version: '2.0.0-beta0004'
    source: INTERNAL REPO URL
    state: present
    allow_prerelease: yes

See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.


chocolatey_package 'tfscmdlets' do
  action    :install
  source   'INTERNAL REPO URL'
  version  '2.0.0-beta0004'
  options  '--prerelease'
end

See docs at https://docs.chef.io/resource_chocolatey_package.html.


cChocoPackageInstaller tfscmdlets
{
    Name        = "tfscmdlets"
    Version     = "2.0.0-beta0004"
    Source      = "INTERNAL REPO URL"
    chocoParams = "--prerelease"
}

Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.


package { 'tfscmdlets':
  ensure          => '2.0.0-beta0004',
  install_options => ['--prerelease'],
  provider        => 'chocolatey',
  source          => 'INTERNAL REPO URL',
}

Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.


4. If applicable - Chocolatey configuration/installation

See infrastructure management matrix for Chocolatey configuration elements and examples.

WARNING

This package is exempt from moderation. While it is likely safe for you, there is more risk involved.

Description

PowerShell Cmdlets for Azure DevOps and Team Foundation Server


tools\TfsCmdlets\Admin\Admin.ps1
<#
.SYNOPSIS
Gets the installation path of a given Team Foundation Server component.

.DESCRIPTION
Many times a Team Foundation Server admin needs to retrieve the location where TFS is actually installed. That can be useful, for instance, to locate tools like TfsSecurity or TfsServiceControl. That information is recorded at setup time, in a well-known location in the Windows Registry of the server where TFS is installed.

.PARAMETER ComputerName
The machine name of the server where the TFS component is installed. It must be properly configured for PowerShell Remoting in case it's a remote machine. Optionally, a System.Management.Automation.Runspaces.PSSession object pointing to a previously opened PowerShell Remote session can be provided instead.
When omitted, defaults to the local machine where the script is being run

.PARAMETER Component
Indicates the TFS component whose installation path is being searched for. For the main TFS installation directory, use BaseInstallation.
When omitted, defaults to BaseInstallation.

.PARAMETER Version
The TFS version number, in the format '##.#'. For TFS 2015, use '14.0'

.PARAMETER Credential
The user credentials to be used to access a remote machine. Those credentials must have the required permission to execute a PowerShell Remote session on that computer and also the permission to access the Windows Registry.

.EXAMPLE
Get-TfsInstallationPath -Version 15.0
Gets the root folder (the BaseInstallationPath) of TFS in the local server where the cmdlet is being run

.EXAMPLE
Get-TfsInstallationPath -Computer SPTFSSRV -Version 14.0 -Component SharepointExtensions -Credentials (Get-Credentials)
Gets the location where the SharePoint Extensions have been installed in the remote server SPTFSSRV, prompting for admin credentials to be used for establishing a PS Remoting session to the server
#>
Function Get-TfsInstallationPath
{
	[CmdletBinding()]
	[OutputType('string')]
	Param
	(
		[Parameter()]
		[object]
		[Alias('Session')]
		$ComputerName,

		[Parameter()]
		[ValidateSet('BaseInstallation', 'ApplicationTier', 'SharePointExtensions', 'TeamBuild', 'Tools', 'VersionControlProxy')]
		[string]
		$Component = 'BaseInstallation',

		[Parameter(Mandatory=$true)]
		[ValidateSet('11.0','12.0','14.0','15.0')]
		[string]
		$Version,

		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)

	Process
	{
		$scriptBlock = _NewScriptBlock -EntryPoint '_GetInstallationPath' -Dependency '_TestRegistryValue', '_GetRegistryValue'

		return _InvokeScriptBlock -ScriptBlock $scriptBlock -Computer $Computer -Credential $Credential -ArgumentList $Version, $Component
	}
}
<#
.SYNOPSIS
Gets information about a configuration server.

.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object. 

When using a URL, it must be fully qualified. The format of this string is as follows: 

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/] 

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.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.

.PARAMETER Current
Returns the configuration server specified in the last call to Connect-TfsConfigurationServer (i.e. the "current" configuration server)

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Start-TfsIdentitySync
{
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[CmdletBinding()]
	Param
	(
		[Parameter(Position=0,ValueFromPipeline=$true)]
		[object] 
		$Server,

		[Parameter()]
		[switch]
		$Wait,

		[Parameter()]
		[object]
		$Credential
	)

	Process
	{
		$srv = Get-TfsConfigurationServer -Server $Server -Credential $Credential

		if($srv.Count -ne 1)
		{
			throw "Invalid or non-existent configuration server $Server"
		}

		$jobSvc = $srv.GetService([type]'Microsoft.TeamFoundation.Framework.Client.ITeamFoundationJobService')
		$syncJobId = [guid]'544dd581-f72a-45a9-8de0-8cd3a5f29dfe'
		$syncJobDef = $jobSvc.QueryJobs() | Where-Object { $_.JobId -eq $syncJobId }

		if ($syncJobDef)
		{
			_Log "Queuing job '$($syncJobDef.Name)' with high priority now"

			$success = ([bool] $jobSvc.QueueJobNow($syncJobDef, $true))

			if (-not $success)
			{
				throw "Failed to queue synchronization job"
			}

			if($Wait.IsPresent)
			{
				do
				{
					_Log "Waiting for the job to complete"
					Start-Sleep -Seconds 5

					$status = $jobSvc.QueryLatestJobHistory($syncJobId)
					_Log "Current job status: $($status.Result)"
				} while($status.Result -eq 'None')

				return $result
			}
		}
		else
		{
			throw "Could not find Periodic Identity Synchronization job definition (id $syncJobId). Unable to start synchronization process."
		}
	}
}
Function _GetInstallationPath($Version, $Component)
{
	$rootKeyPath = "HKLM:\Software\Microsoft\TeamFoundationServer\$Version"

	if ($Component -eq 'BaseInstallation')
	{
		$componentPath = $rootKeyPath
	}
	else
	{
		$componentPath = "$rootKeyPath\InstalledComponents\$Component"
	}

	if (-not (_TestRegistryValue -Path $rootKeyPath -Value 'InstallPath'))
	{
		throw "Team Foundation Server is not installed in computer $env:COMPUTERNAME"
	}

	if (-not (_TestRegistryValue -Path $componentPath -Value 'InstallPath'))
	{
		throw "Team Foundation Server component '$Component' is not installed in computer $env:COMPUTERNAME"
	}

	return _GetRegistryValue -Path $componentPath -Value 'InstallPath'
}
tools\TfsCmdlets\Admin\Admin.psd1
@{
    Description = 'This module contains advanced administration cmdlets to support remote administration of some features of Team Foundation Server that, otherwise, would require an administrator to be logged in to a TFS Application Tier console'

    ModuleVersion = '0.0.0'

    RootModule = 'Admin.psm1'

    PrivateData = @{ 
        FriendlyName = 'Administration'
    }
}
tools\TfsCmdlets\AreaIteration\Area\AreaIteration_Area.ps1
<#
.SYNOPSIS
Gets one or more Work Item Areas from a given Team Project.

.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.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

.EXAMPLE
Get-TfsArea
Returns all area paths in the currently connected Team Project (as defined by a previous call to Connect-TfsTeamProject)

.EXAMPLE
Get-TfsArea 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
Returns information on an area path called 'Fabrikam Web Team' in a team project called 'Fabrikam Fiber'

.EXAMPLE
Get-TfsArea '\**\Support' -Project Tailspin
Performs a recursive search and returns all area paths named 'Support' that may exist in a team project called Tailspin
#>
Function Get-TfsArea
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Position=0)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [SupportsWildcards()]
        [object]
        $Area = '\**',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        return _GetCssNodes -Node $Area -Scope Area -Project $Project -Collection $Collection
    }
}
<#
.SYNOPSIS
    Moves a Work Item Area from its parent area to another one in the same Team Project.

.PARAMETER Area
    Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.PARAMETER Destination
    Specifies the name, URI or path of an Area Path that will become the new parent of the given source area

.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.Server.NodeInfo
    System.String
    System.Uri
#>
Function Move-TfsArea
{
    [CmdletBinding(ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [object]
        $Area,

        [Parameter(Position=1l)]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [object]
        $Destination,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $node = Get-TfsArea -Area $Area -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent area $Area"
        }

        $destinationNode = Get-TfsArea -Area $Destination -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent destination area $Destination"
        }

        $cssService = _GetCssService -Project $Project -Collection $Collection
        $cssService.MoveBranch($node.Uri, $destinationNode.Uri)
        $node = $cssService.GetNode($node.Uri)

        if ($Passthru)
        {
            return $node
        }
    }
}
<#
.SYNOPSIS
    Creates a new Work Item Area in the given Team Project.

.PARAMETER Area
    Specifies the path of the new Area. When supplying a path, use a backslash ("\") between the path segments. Leading and trailing backslashes are optional. The last segment in the path will be the area name.

.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
    System.String
#>
Function New-TfsArea
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [string]
        $Area,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        if($PSCmdlet.ShouldProcess($Area, 'Create Area Path'))
        {
            $node = _NewCssNode -Path $Area -Scope Area -Project $Project -Collection $Collection

            if ($Passthru)
            {
                return $node
            }
        }
    }
}
<#
.SYNOPSIS
    Deletes one or more Work Item Areas.

.PARAMETER Area
    Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.PARAMETER MoveTo
    Specifies the new area path for the work items currently assigned to the area being deleted, if any. When omitted, defaults to the root area

.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 Remove-TfsArea
{
    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [object]
        $Area,

        [Parameter(Position=1)]
        [Alias("NewPath")]
        [ValidateScript({ ($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo]) })] 
        [object]
        $MoveTo = '\',

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $areas = Get-TfsArea -Area $Area -Project $Project -Collection $Collection | Sort-Object -Property Path -Descending

        foreach($item in $areas)
        {
            $projectName = $item.Path.Split("\")[1]

            if (-not ($PSCmdlet.ShouldProcess($projectName, "Delete Area '$($item.RelativePath)' and move orphaned work items to area '$MoveTo'")))
            {
                continue
            }

            _DeleteCssNode -Node $item -MoveToNode $MoveTo -Scope Area -Project $projectName -Collection $Collection
        }
    }
}
<#
.SYNOPSIS
    Renames a Work Item Area.

.PARAMETER Area
    Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.PARAMETER NewName
    Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Area parameter, Rename-TfsArea generates an error. To rename and move an item, use the Move-TfsArea cmdlet.

.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 Rename-TfsArea
{
    [CmdletBinding(ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [Alias("Path")]
        [object]
        $Area,

        [Parameter(Position=1)]
        [string]
        $NewName,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $result = Set-TfsArea -Area $Area -NewName $NewName -Project $Project -Collection $Collection

        if ($Passthru)
        {
            return $result
        }
    }
}
<#
.SYNOPSIS
Modifies the name and/or the position of a Work Item Area.

.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.PARAMETER NewName
Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-Tfsarea generates an error. To rename and move an item, use the Move-Tfsarea cmdlet.

.PARAMETER MoveBy
Reorders an area by moving it either up or down inside its parent. A positive value moves an area down, whereas a negative one moves it up.

.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 Set-TfsArea
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [Alias("Path")]
        [object]
        $Area,

        [Parameter()]
        [string]
        $NewName,

        [Parameter()]
        [int]
        $MoveBy,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $node = Get-TfsArea -Area $Area -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent area $Area"
        }

        $cssService = _GetCssService -Project $Project -Collection $Collection

        if ($NewName)
        {
            if ($PSCmdlet.ShouldProcess($Area, "Rename area to $NewName"))
            {
                $cssService.RenameNode($node.Uri, $NewName)
            }
        }

        if ($MoveBy)
        {
            if ($PSCmdlet.ShouldProcess($Area, "Reorder area by moving it $MoveBy positions (negative is up, positive is down)"))
            {
                $cssService.ReorderNode($node.Uri, $MoveBy)
            }
        }

        return $cssService.GetNode($node.Uri)
    }
}
<#
.SYNOPSIS
Determines whether the specified Areas Paths exist.

.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.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

.EXAMPLE
Test-TfsArea 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
Returns $true if an area path called 'Fabrikam Web Team' exists in a team project called 'Fabrikam Fiber'

#>
Function Test-TfsArea
{
    [CmdletBinding()]
    [OutputType('bool')]
    Param
    (
        [Parameter(Position=0)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [SupportsWildcards()]
        [object]
        $Area = '\**',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        try
        {
            return [bool] (_GetCssNodes -Node $Area -Scope Area -Project $Project -Collection $Collection)
        }
        catch
        {
            Write-Warning "Error testing path: $_"
            return $false
        }
    }
}
tools\TfsCmdlets\AreaIteration\AreaIteration.ps1
Function _GetCssNodes($Node, $Scope, $Project, $Collection)
{
    Process
	{
		if ($Node -is [Microsoft.TeamFoundation.Server.NodeInfo])
		{
			_Log "Input item is of type NodeInfo; returning input item immediately, without further processing."

			return $Node
		}

		$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

		$projectName = $tp.Name
		$cssService = _GetCssService -Collection $tpc
        
		if ($node -is [uri])
		{
			_Log "Getting node by URL [$node]"
			return $cssService.GetNode($node)
		}

		$rootPath = _NormalizeCssNodePath -Project $projectName -Scope $Scope -Path '' -IncludeTeamProject -IncludeScope
		$rootNodeUri = $cssService.GetNodeFromPath("$rootPath").Uri

		_Log "Retrieving Nodes XML from root path [$rootPath]"

		$rootElement = $cssService.GetNodesXml(@($rootNodeUri), $true)
		$nodePaths = $rootElement.SelectNodes('//@Path') | Select-Object -ExpandProperty '#text'

		$fullPath = _NormalizeCssNodePath  -Project $projectName -Scope $Scope -Path $Node -IncludeScope -IncludeTeamProject -IncludeLeadingBackslash
		$matchingPaths = $nodePaths | Where-Object { _Log "Evaluating '$_' against pattern '$fullPath' == $($_ -like $fullPath)" -Caller (_GetLogCallStack); $_ -like $fullPath }

        return $matchingPaths | Foreach-Object { _Log "Returning node from path [$_]" -Caller (_GetLogCallStack); $cssService.GetNodeFromPath($_) }
    }
}

Function _DeleteCssNode($Node, $Scope, $MoveToNode, $Project, $Collection)
{
	$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

	$newNode = _GetCssNodes -Node $MoveToNode -Scope $Scope -Project $Project -Collection $Collection

	_Log "Moving work items from deleted node [$($Node.Path)] to node [$($newNode.Path)]"

	$cssService = _GetCssService -Collection $tpc

	$cssService.DeleteBranches($Node.Uri, $newNode.Uri)        
}

Function _NewCssNode ($Project, $Path, $Scope, $Collection, $StartDate, $FinishDate)
{
	Process
	{
		$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

		$projectName = $tp.Name

		_Log "Creating $Scope node [$Path] in project $projectName"

		$cssService = _GetCssService -Collection $tpc

        try
        {
			$fullPath = _NormalizeCssNodePath -Project $projectName -Scope $Scope -Path $Path -IncludeTeamProject -IncludeScope
			$parentPath = Split-Path $fullPath -Parent
			$nodeName = Split-Path $fullPath -Leaf
            $parentNode = $cssService.GetNodeFromPath($parentPath)
        }
        catch
        {
			_Log "Parent node [$parentPath] does not exist. Creating recursively..."

            $parentNode = _NewCssNode -Project $Project -Path $parentPath -Scope $Scope -Collection $Collection
        }

		if ($StartDate -or $FinishDate)
		{
			_Log "Iteration date(s) were provided as Start = [$StartDate], Finish = [$FinishDate]. Creating iteration with supplied dates"
			$cssService = _GetCssService -Collection $tpc -Version 4
			$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri, $StartDate, $FinishDate)
		}
		else
		{
			if($Scope -eq 'Iteration')
			{
				_Log "Iteration date(s) were not provided. Creating iteration without dates"
			}
			
			$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri)
		}

        return $cssService.GetNode($nodeUri)
    }
}

Function _NormalizeCssNodePath
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[string]
		$Project, 

		[ValidateSet('Area', 'Iteration')]
		[string]
		$Scope, 

		[Parameter(Mandatory=$true)]
		[AllowEmptyString()]
		[string]
		$Path, 

		[switch]
		$IncludeScope,

		[switch]
		$ExcludePath,

		[switch]
		$IncludeLeadingBackslash,

		[switch]
		$IncludeTrailingBackslash,

		[switch]
		$IncludeTeamProject
	)

	_Log "Normalizing path '$Path' with arguments $(_DumpObj $PSBoundParameters)"

	$newPath = ''

	if ($IncludeLeadingBackslash) { $newPath += '\' }
	if ($IncludeTeamProject) { $newPath += $Project + '\' }
	if ($IncludeScope) { $newPath += $Scope + '\' }

	if(-not $ExcludePath.IsPresent)
	{
		$Path = $Path.Trim(' ', '\')

		if ($Path -like "$Project\$Scope\*")
		{
			$Path = $Path.Substring("$Project\$Scope\".Length)
		}
		if ($Path -like "$Project\*")
		{
			$Path = $Path.Substring($Path.IndexOf('\'))
		}
		elseif ($Path -eq $Project)
		{
			$Path = ''
		}

		$newPath += $Path
	}

	if ($newPath.EndsWith('\') -and (-not $IncludeTrailingBackslash.IsPresent))
	{ 
		$newPath = $newPath.TrimEnd('\')
	}

	_Log "Normalized path: $newPath"

	return $newPath -replace '\\{2,}', '\'
}

Function _GetCssService($Collection, $Version)
{
	$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}

    return $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService$Version")
}
tools\TfsCmdlets\AreaIteration\AreaIteration.psd1
@{
    Description = 'This module contains cmdlets to mantain Areas and Iterations, hierarchical fields in TFS used to classify work items and to enable Backlogs and Boards'

    ModuleVersion = '0.0.0'

    RootModule = 'AreaIteration.psm1'

    PrivateData = @{ 
        FriendlyName = 'Areas and Iterations'
    }
}
tools\TfsCmdlets\AreaIteration\Iteration\AreaIteration_Iteration.ps1
<#
.SYNOPSIS
    Gets one or more Work Item Iterations from a given Team Project.

.PARAMETER Iteration
    Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.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-TfsIteration
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Position=0)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [SupportsWildcards()]
        [object]
        $Iteration = '\**',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        return _GetCssNodes -Node $Iteration -Scope Iteration -Project $Project -Collection $Collection
    }
}
<#
.SYNOPSIS
    Moves a Work Item Iteration from its parent iteration to another one in the same Team Project.

.PARAMETER Iteration
    Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.PARAMETER Destination
    Specifies the name, URI or path of an Iteration Path that will become the new parent of the given source iteration

.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.Server.NodeInfo
    System.String
    System.Uri
#>
Function Move-TfsIteration
{
    [CmdletBinding(ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [object]
        $Iteration,

        [Parameter(Position=1)]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [object]
        $Destination,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $node = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent iteration $Iteration"
        }

        $destinationNode = Get-TfsIteration -Iteration $Destination -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent destination iteration $Destination"
        }

        $cssService = _GetCssService -Project $Project -Collection $Collection
        $cssService.MoveBranch($node.Uri, $destinationNode.Uri)
        $node = $cssService.GetNode($node.Uri)

        if ($Passthru)
        {
            return $node
        }
    }
}
<#
.SYNOPSIS
    Creates a new Work Item Iteration in the given Team Project.

.PARAMETER Iteration
    Specifies the path of the new Iteration. When supplying a path, use a backslash ("\") between the path segments. Leading and trailing backslashes are optional. The last segment in the path will be the iteration name.

.PARAMETER StartDate
    Specifies the start of a timed iteration, such as a sprint. Enter a string that represents the date and time, such as "12/01/2015" or a DateTime object, such as one from a Get-Date command. When omitted, no start date is set.

.PARAMETER FinishDate
    Specifies the end of a timed iteration, such as a sprint. Enter a string that represents the date and time, such as "12/01/2015" or a DateTime object, such as one from a Get-Date command. When omitted, no finish date is set.

.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
    System.String
#>
Function New-TfsIteration
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [string]
        $Iteration,

        [Parameter()]
        [DateTime]
        $StartDate,
    
        [Parameter()]
        [DateTime]
        $FinishDate,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        if($PSCmdlet.ShouldProcess($Iteration, 'Create iteration path'))
        {
            $node = _NewCssNode -Path $Iteration -Scope Iteration -Project $Project -Collection $Collection -StartDate $StartDate -FinishDate $FinishDate

            if ($Passthru)
            {
                return $node
            }
        }
    }
}
<#
.SYNOPSIS
Deletes one or more Work Item Iterations.

.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.PARAMETER MoveTo
Specifies the new iteration path for the work items currently assigned to the iteration being deleted, if any. When omitted, defaults to the root iteration

.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 Remove-TfsIteration
{
    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [object]
        $Iteration,

        [Parameter(Position=1)]
        [Alias("NewPath")]
        [ValidateScript({ ($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo]) })] 
        [object]
        $MoveTo = '\',

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $iterations = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection | Sort-Object -Property Path -Descending

        foreach($i in $iterations)
        {
            $projectName = $i.Path.Split("\")[1]

            if (-not ($PSCmdlet.ShouldProcess($projectName, "Delete Iteration '$($i.RelativePath)' and move orphaned work items to iteration '$MoveTo'")))
            {
                continue
            }

            _DeleteCssNode -Node $i -MoveToNode $MoveTo -Scope Iteration -Project $projectName -Collection $Collection
        }
    }
}
<#
.SYNOPSIS
    Renames a Work Item Iteration.

.PARAMETER Iteration
    Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.PARAMETER NewName
    Specifies the new name of the iteration. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Iteration parameter, Rename-TfsIteration generates an error. To rename and move an item, use the Move-TfsIteration cmdlet.

.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 Rename-TfsIteration
{
    [CmdletBinding(ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [Alias("Path")]
        [object]
        $Iteration,

        [Parameter(Position=1)]
        [string]
        $NewName,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $result = Set-TfsIteration -Iteration $Iteration -NewName $NewName -Project $Project -Collection $Collection

        if ($Passthru)
        {
            return $result
        }
    }
}
<#
.SYNOPSIS
    Modifies the name, position and/or the dates of a Work Item Iteration.

.PARAMETER Iteration
    Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.PARAMETER NewName
    Specifies the new name of the iteration. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Iteration parameter, Rename-TfsIteration generates an error. To rename and move an item, use the Move-TfsIteration cmdlet.

.PARAMETER MoveBy
    Reorders an iteration by moving it either up or down inside its parent. A positive value moves an iteration down, whereas a negative one moves it up.

.PARAMETER StartDate
    Sets the start date of the iteration. To clear the start date, set it to $null. Note that when clearing a date, both must be cleared at the same time (i.e. setting both StartDate and FinishDate to $null)

.PARAMETER FinishDate
    Sets the finish date of the iteration. To clear the finish date, set it to $null. Note that when clearing a date, both must be cleared at the same time (i.e. setting both StartDate and FinishDate to $null)

.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 Set-TfsIteration
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [SupportsWildcards()]
        [object]
        $Iteration,

        [Parameter()]
        [string]
        $NewName,

        [Parameter()]
        [int]
        $MoveBy,

        [Parameter()]
        [Nullable[DateTime]]
        $StartDate,
    
        [Parameter()]
        [Nullable[DateTime]]
        $FinishDate,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $node = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection

        if (-not $node)
        {
            throw "Invalid or non-existent iteration $Iteration"
        }

        $cssService = _GetCssService -Project $Project -Collection $Collection
        $cssService4 = _GetCssService -Project $Project -Collection $Collection -Version 4

        if ($NewName)
        {
            if ($PSCmdlet.ShouldProcess($Iteration, "Rename iteration to $NewName"))
            {
                $cssService.RenameNode($node.Uri, $NewName)
            }
        }

        if ($MoveBy)
        {
            if ($PSCmdlet.ShouldProcess($Area, "Reorder iteration by moving it $MoveBy positions (negative is up, positive is down)"))
            {
                $cssService.ReorderNode($node.Uri, $MoveBy)
            }
        }

        if ($StartDate -or $FinishDate)
        {
            if (-not $PSBoundParameters.ContainsKey("StartDate"))
            {
                $StartDate = $node.StartDate
            }

            if (-not $PSBoundParameters.ContainsKey("FinishDate"))
            {
                $FinishDate = $node.FinishDate
            }

            if ($PSCmdlet.ShouldProcess($Area, "Set iteration start and finish dates to $StartDate and $FinishDate, respectively"))
            {
                [void]$cssService4.SetIterationDates($node.Uri, $StartDate, $FinishDate)
            }
        }

        return $cssService.GetNode($node.Uri)
    }
}
<#
.SYNOPSIS
    Determines whether the specified Iterations Paths exist.

.PARAMETER Iteration
    Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).

.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

.EXAMPLE
    Test-TfsIteration 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
    Returns $true if an iteration path called 'Fabrikam Web Team' exists in a team project called 'Fabrikam Fiber'

#>
Function Test-TfsIteration
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
    Param
    (
        [Parameter(Position=0)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
        [SupportsWildcards()]
        [object]
        $Iteration = '\**',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        try
        {
            return [bool] (_GetCssNodes -Node $Iteration -Scope Iteration -Project $Project -Collection $Collection)
        }
        catch
        {
            Write-Warning "Error testing path: $_"
            return $false
        }
    }
}
tools\TfsCmdlets\chocolateyInstall.ps1
$InstallPath = Join-Path $($env:ChocolateyInstall) 'lib\TfsCmdlets'
$ToolsDir = Join-Path $InstallPath 'Tools'

if ($env:PSModulePath -notlike "*$ToolsDir*")
{
    Write-Output "TfsCmdlets: Adding installation directory to PSModulePath environment variable"
    SETX @('PSModulePath', "$env:PSModulePath;$ToolsDir", '/M')
}

$ShortcutTargetDir = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs"
$ShortcutName = 'Azure DevOps Shell'
$ShortcutFilePath = "$ShortcutTargetDir\$ShortcutName.lnk"
$ShortcutExecutable = "$Env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
$ShortcutArguments = '-noexit -command "Import-Module TfsCmdlets"'
$ShortcutIconLocation = "$ToolsDir\TfsCmdlets\TfsCmdletsShell.ico"

if (-not (Test-Path $ShortcutFilePath))
{
    Write-Output "TfsCmdlets: Adding Start Menu shortcut file"
	Install-ChocolateyShortcut -ShortcutFilePath $ShortcutFilePath -TargetPath $ShortcutExecutable -Arguments $ShortcutArguments -IconLocation $ShortcutIconLocation
}
tools\TfsCmdlets\chocolateyUninstall.ps1
$InstallPath = Join-Path $($env:ChocolateyInstall) 'lib\TfsCmdlets'
$ToolsDir = Join-Path $InstallPath 'Tools'

if ($env:PSModulePath -like "*$ToolsDir*")
{
    Write-Output "TfsCmdlets: Removing installation directory from PSModulePath environment variable"
    $NewModulePath = $Env:PSModulePath.Replace($ToolsDir, '').Replace(';;', ';')
    SETX @('PSModulePath', $NewModulePath, '/M')
}

$ShortcutTargetDir = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs"
$ShortcutName = 'Azure DevOps Shell'
$ShortcutFilePath = "$ShortcutTargetDir\$ShortcutName.lnk"

if (Test-Path $ShortcutFilePath)
{
    Write-Output "TfsCmdlets: Removing Start Menu shortcut file"
    Remove-Item $ShortcutFilePath
}
tools\TfsCmdlets\ConfigServer\ConfigServer.ps1
<#
.SYNOPSIS
Gets information about a configuration server.

.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object. 

When using a URL, it must be fully qualified. The format of this string is as follows: 

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/] 

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.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.

.PARAMETER Current
Returns the configuration server specified in the last call to Connect-TfsConfigurationServer (i.e. the "current" configuration server)

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Get-TfsConfigurationServer
{
	[CmdletBinding(DefaultParameterSetName='Get by server')]
	[OutputType('Microsoft.TeamFoundation.Client.TfsConfigurationServer')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	Param
	(
		[Parameter(Position=0, ParameterSetName='Get by server', Mandatory=$true)]
		[AllowNull()]
		[object] 
		$Server,
	
		[Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

		[Parameter(Position=1, ParameterSetName='Get by server')]
		[object]
		$Credential
	)

	Process
	{
		if ($Current.IsPresent -or (-not $Server))
		{
			return $script:TfsServerConnection
        }

		if ($Server -is [Microsoft.TeamFoundation.Client.TfsConfigurationServer])
		{
			return $Server
		}

		$cred = Get-TfsCredential -Credential $Credential

		if (($Server -is [Uri]) -or ([Uri]::IsWellFormedUriString($Server, [UriKind]::Absolute)))
		{
			return New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList ([Uri] $Server), $cred
		}

		if ($Server -is [string] -and (-not [string]::IsNullOrWhiteSpace($Server)))
		{
			$serverNames = Get-TfsRegisteredConfigurationServer -Server $Server
			
			foreach($s in $serverNames)
			{
				Write-Output (New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList $s.Uri,  $cred)
			}

			return
		}

		throw 'No TFS connection information available. Either supply a valid -Server argument or use Connect-TfsConfigurationServer prior to invoking this cmdlet.'
	}
}
<#
.SYNOPSIS
    Gets the configuration server database connection string.

.PARAMETER Computer
    Specifies the name of a Team Foundation Server application tier from which to retrieve the connection string

.PARAMETER Version
    Specifies the version of the Team Foundation Server being queried. Valid values are '12.0' (TFS 2013), '14.0' (TFS 2015), '15.0' (TFS 2017)

.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
#>
Function Get-TfsConfigurationServerConnectionString
{
	[CmdletBinding()]
	[OutputType('string')]
	Param
	(
		[Parameter()]
		[string]
		[Alias('Session')]
		$Computer,

		[Parameter()]
		[ValidateSet('12.0', '14.0', '15.0')]
		[string]
		$Version,

		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)

	Process
	{

		$scriptBlock = _NewScriptBlock -EntryPoint '_GetConnectionString' -Dependency 'Get-InstallationPath', '_TestRegistryValue', '_GetRegistryValue'

		return _InvokeScriptBlock -ScriptBlock $scriptBlock -Computer $Computer -Credential $Credential -ArgumentList $Version
	}
}

Function _GetConnectionString($Version)
{
	$path = Get-InstallationPath -Version $Version -Component ApplicationTier
	$webConfigPath = Join-Path $path 'Web Services/Web.config'
	$webConfig = [xml] (Get-Content $webConfigPath)

	return (Select-Xml -Xml $webConfig -XPath '/configuration/appSettings/add[@key="applicationDatabase"]/@value').Node.Value
}
<#
.SYNOPSIS
    Gets one or more Team Foundation Server addresses registered in the current computer.

.PARAMETER Name
    Specifies the name of a registered server. When omitted, all registered servers are returned. Wildcards are permitted.

.INPUTS
    System.String
#>
Function Get-TfsRegisteredConfigurationServer
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Client.RegisteredConfigurationServer' )]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [Alias('Name')]
        [string]
        $Server = "*"
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
    }

    Process
    {
        if(($Server -eq "localhost") -or ($Server -eq "."))
        {
            $Server = $env:COMPUTERNAME
        }

        return [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetConfigurationServers() | Where-Object Name -Like $Server
    }
}
tools\TfsCmdlets\ConfigServer\ConfigServer.psd1
@{
    Description = 'This module contains cmdlets to administer server-wide features of Team Foundation Server'

    ModuleVersion = '0.0.0'

    RootModule = 'ConfigServer.psm1'

    PrivateData = @{ 
        FriendlyName = 'Configuration Server'
    }
}
tools\TfsCmdlets\Connection\Connection.ps1
<#
.SYNOPSIS
Connects to a configuration server.

.PARAMETER Server
#Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object. 

When using a URL, it must be fully qualified. The format of this string is as follows: 

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/] 

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.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).

.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output. 

.DESCRIPTION
The Connect-TfsConfigurationServer function connects to a TFS configuration server. Functions that operate on a server level (as opposed to those operation on a team project collection level) will use by default a connection opened by this function.

.NOTES
A TFS Configuration Server represents the server that is running Team Foundation Server. On a database level, it is represented by the Tfs_Configuration database. Operations that should be performed on a server level (such as setting server-level permissions) require a connection to a TFS configuration server. Internally, this connection is represented by an instance of the Microsoft.TeamFoundation.Client.TfsConfigurationServer class and is kept in a PowerShell global variable caled TfsServerConnection.

.EXAMPLE
Connect-TfsConfigurationServer -Server http://vsalm:8080/tfs
Connects to the TFS server specified by the URL in the Server argument

.EXAMPLE
Connect-TfsConfigurationServer -Server vsalm
Connects to a previously registered TFS server by its user-defined name "vsalm". For more information, see Get-TfsRegisteredConfigurationServer

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri

.LINK
Microsoft.TeamFoundation.Client.TfsConfigurationServer

.LINK
https://blogs.msdn.microsoft.com/taylaf/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes/
#>
Function Connect-TfsConfigurationServer
{
	[CmdletBinding(DefaultParameterSetName="Explicit credentials")]
	[OutputType('Microsoft.TeamFoundation.Client.TfsConfigurationServer')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Server,
	
		[Parameter(ParameterSetName="Explicit credentials")]
		[object]
		$Credential,

		[Parameter(ParameterSetName="Prompt for credentials", Mandatory=$true)]
		[switch]
		$Interactive,

		[Parameter()]
		[switch]
		$Passthru
	)

	Process
	{
		if ($PSCmdlet.ParameterSetName -eq 'Prompt for credentials')
		{
			$Credential = (Get-TfsCredential -Interactive)
		}

		$configServer = Get-TfsConfigurationServer -Server $Server -Credential $Credential

		if (-not $configServer)
		{
			throw "Error connecting to TFS"
		}

		$script:TfsTeamConnection = $null
		$script:TfsProjectConnection = $null
		$script:TfsTpcConnection = $null
		$script:TfsServerConnection = $configServer

		if ($Passthru)
		{
			return $configServer
		}
	}
}
<#
.SYNOPSIS
Connects to a team project.

.DESCRIPTION
The Connect-TfsTeamProject cmdlet "connects" (initializes a Microsoft.TeamFoundation.WorkItemTracking.Client.Project object) to a TFS Team Project. That connection is subsequently kept in a global variable to be later reused until it's closed by a call to Disconnect-TfsTeamProject.
Cmdlets in the TfsCmdlets module that require a team project object to be provided via their -Project argument in order to access a TFS project will use the connection opened by this cmdlet as their "default project". In other words, TFS cmdlets (e.g. New-TfsArea) that have a -Project argument will use the connection provided by Connect-TfsTeamProject by default.

.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 Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).

.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output. 

.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String

.EXAMPLE
Connect-TfsTeamProject -Project FabrikamFiber
Connects to a project called FabrikamFiber in the current team project collection (as specified in a previous call to Connect-TfsTeamProjectCollection)

.EXAMPLE
Connect-TfsTeamProject -Project FabrikamFiber -Collection http://vsalm:8080/tfs/FabrikamFiberCollection
Connects to a project called FabrikamFiber in the team project collection specified in the given URL
#>
Function Connect-TfsTeamProject
{
	[CmdletBinding(DefaultParameterSetName="Explicit credentials")]
	[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Project,
	
		[Parameter()]
		[object] 
		$Collection,
	
		[Parameter(ParameterSetName="Explicit credentials")]
		[object]
		$Credential,

		[Parameter(ParameterSetName="Prompt for credentials", Mandatory=$true)]
		[switch]
		$Interactive,

		[Parameter()]
		[switch]
		$Passthru
	)

	Process
	{
		if ($Interactive.IsPresent)
		{
			$Credential = (Get-TfsCredential -Interactive)
		}

		$tp = (Get-TfsTeamProject -Project $Project -Collection $Collection -Credential $Credential | Select-Object -First 1)

		if (-not $tp)
		{
			throw "Error connecting to team project $Project"
		}

		$script:TfsTeamConnection = $null
		$script:TfsProjectConnection = $tp
		$script:TfsTpcConnection = $tp.Store.TeamProjectCollection
		$script:TfsServerConnection = $script:TfsTpcConnection.ConfigurationServer

		if ($Passthru)
		{
			return $tp
		}
	}
}
<#
.SYNOPSIS
Connects to a team project collection. 

.DESCRIPTION
The Connect-TfsTeamProjectCollection cmdlet "connects" (initializes a Microsoft.TeamFoundation.Client.TfsTeamProjectCollection object) to a TFS Team Project Collection. That connection is subsequently kept in a global variable to be later reused until it's closed by a call to Disconnect-TfsTeamProjectCollection.
Most cmdlets in the TfsCmdlets module require a TfsTeamProjectCollection object to be provided via their -Collection argument in order to access a TFS instance. Those cmdlets will use the connection opened by Connect-TfsTeamProjectCollection as their "default connection". In other words, TFS cmdlets (e.g. New-TfsWorkItem) that have a -Collection argument will use the connection provided by Connect-TfsTeamProjectCollection by default.

.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 Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object. 

When using a URL, it must be fully qualified. The format of this string is as follows: 

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/] 

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.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).

.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output. 

.EXAMPLE
Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection
Connects to a collection called "DefaultCollection" in a TF server called "tfs" using the cached credentials of the logged-on user

.EXAMPLE
Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection -Interactive
Connects to a collection called "DefaultCollection" in a Team Foundation server called "tfs", firstly prompting the user for credentials (it ignores the cached credentials for the currently logged-in user). It's equivalent to the command:

PS> Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection -Credential (Get-TfsCredential -Interactive)

.LINK
Get-TfsTeamProjectCollection

.LINK
https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsteamprojectcollection.aspx

.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Connect-TfsTeamProjectCollection
{
	[CmdletBinding(DefaultParameterSetName="Cached credentials")]
	[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Collection,
	
        [Parameter(ParameterSetName="Cached credentials")]
        [switch]
        $Cached,

        [Parameter(ParameterSetName="User name and password", Mandatory=$true, Position=1)]
        [string]
        $UserName,

        [Parameter(ParameterSetName="User name and password", Position=2)]
        [securestring]
        $Password,

        [Parameter(ParameterSetName="Credential object", Mandatory=$true)]
        [ValidateNotNull]
		[object]
        $Credential,

        [Parameter(ParameterSetName="Personal Access Token", Mandatory=$true)]
        [Alias('Pat')]
        [string]
        $PersonalAccessToken,

        [Parameter(ParameterSetName="Prompt for credential", Mandatory=$true)]
        [switch]
        $Interactive,

		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[switch]
		$Passthru
	)

	Begin
	{
		if ($PSVersionTable.PSEdition -ne 'Desktop') { throw "This cmdlet requires does not work in PowerShell Core. It uses TFS Client Object Model, which only works in Windows PowerShell" }
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
	}

	Process
	{
		$tpc = $null

		if ($Collection -is [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])
		{
			_Log "Collection argument is of type TfsTeamProjectCollection. Reusing object."
			$tpc = $Collection
		}
		else
		{
			_Log "Connecting with $($PSCmdlet.ParameterSetName)"

			if ($PSBoundParameters.ContainsKey('Collection')) { [void] $PSBoundParameters.Remove('Collection') }
			if ($PSBoundParameters.ContainsKey('Server')) { [void] $PSBoundParameters.Remove('Server') }
			if ($PSBoundParameters.ContainsKey('Passthru')) { [void] $PSBoundParameters.Remove('Passthru') }

			$creds = Get-TfsCredential @PSBoundParameters
			$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Creds

			if (-not $tpc -or ($tpc.Count -ne 1))
			{
				throw "Invalid or non-existent team project collection $Collection"
			}

			try
			{
				_Log "Calling TfsTeamProjectCollection.EnsureAuthenticated()"
				$tpc.EnsureAuthenticated()
			}
			catch
			{
				throw "Error connecting to team project collection $Collection ($_)"
			}
		}

		$script:TfsTeamConnection = $null
		$script:TfsProjectConnection = $null
		$script:TfsTpcConnection = $tpc
		$script:TfsServerConnection = $tpc.ConfigurationServer

		$script:AzDevTeamConnection = $null
		$script:AzDevProjectConnection = $null

		_Log "Connected to $($tpc.Uri)"

		if ($Passthru)
		{
			return $tpc
		}
	}
}
<#
.SYNOPSIS
Disconnects from the currently connected configuration server.

.DESCRIPTION
The Disconnect-TfsConfigurationServer cmdlet removes the global variable set by Connect-TfsConfigurationServer. Therefore, cmdlets relying on a "default server" as provided by "Get-TfsConfigurationServer -Current" will no longer work after a call to this cmdlet, unless their -Server argument is provided or a new call to Connect-TfsConfigurationServer is made.

.EXAMPLE
Disconnect-TfsConfigurationServer
Disconnects from the currently connected TFS configuration server

#>
Function Disconnect-TfsConfigurationServer
{
    [CmdletBinding()]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
    Param
    (
    )
	Process
	{
        Disconnect-TfsTeamProjectCollection

		if ($script:TfsServerConnection)
        {
		    Remove-Variable -Name TfsServerConnection -Scope Script
		}
	}
}
<#
.SYNOPSIS
Disconnects from the currently connected team project.

.DESCRIPTION
The Disconnect-TfsTeamProject cmdlet removes the global variable set by Connect-TfsTeamProject . Therefore, cmdlets relying on a "default project" as provided by "Get-TfsTeamProject -Current" will no longer work after a call to this cmdlet, unless their -Project argument is provided or a new call to Connect-TfsTeamProject is made.

.EXAMPLE
Disconnect-TfsTeamProject
Disconnects from the currently connected TFS team project

#>
Function Disconnect-TfsTeamProject
{
    [CmdletBinding()]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
    Param
    (
    )
    Process
    {
        if ($script:TfsProjectConnection)
        {
            Remove-Variable -Name TfsProjectConnection -Scope Script
        }
    }
}
<#
.SYNOPSIS
Disconnects from the currently connected team project collection.

.DESCRIPTION
The Disconnect-TfsTeamProjectCollection cmdlet removes the global variable set by Connect-TfsTeamProjectCollection. Therefore, cmdlets relying on a "default collection" as provided by "Get-TfsTeamProjectCollection -Current" will no longer work after a call to this cmdlet, unless their -Collection argument is provided or a new call to Connect-TfsTeamProjectCollection is made.

.EXAMPLE
Disconnect-TfsTeamProjectCollection
Disconnects from the currently connected TFS team project collection

#>
Function Disconnect-TfsTeamProjectCollection
{
    [CmdletBinding()]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
    Param
    (
    )
	Process
	{
        Disconnect-TfsTeamProject

        if ($script:TfsTpcConnection)
        {
		    Remove-Variable -Name TfsTpcConnection -Scope Script
		}
	}
}
<#
.SYNOPSIS
    Provides credentials to use when you connect to a Team Foundation Server or Visual Studio Team Services account.

.DESCRIPTION

.NOTES

.INPUTS
   
#>
Function Get-TfsCredential
{
    [CmdletBinding(DefaultParameterSetName="Cached credentials")]
    [OutputType('Microsoft.TeamFoundation.Client.TfsClientCredentials')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
    Param
    (
        [Parameter(ParameterSetName="Cached credentials")]
        [switch]
        $Cached,

        [Parameter(ParameterSetName="User name and password", Mandatory=$true, Position=1)]
        [string]
        $UserName,

        [Parameter(ParameterSetName="User name and password", Position=2)]
        [securestring]
        $Password,

        [Parameter(ParameterSetName="Credential object", Mandatory=$true)]
        [AllowNull()]
		[object]
        $Credential,

        [Parameter(ParameterSetName="Personal Access Token", Mandatory=$true)]
        [Alias('Pat')]
        [string]
        $PersonalAccessToken,

        [Parameter(ParameterSetName="Prompt for credential", Mandatory=$true)]
        [switch]
        $Interactive
    )

    Process
    {
        $parameterSetName = $PSCmdlet.ParameterSetName
        
        if (($parameterSetName -eq 'Credential object') -and (-not $Credential))
        {
            $parameterSetName = 'Cached Credentials'
        }

        $allowInteractive = $false

        switch($parameterSetName)
        {
            'Cached Credentials' {
                $fedCred = New-Object 'Microsoft.TeamFoundation.Client.CookieCredential' -ArgumentList $true
                $winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $true
            }

            'User name and password' {
                $netCred = New-Object 'System.Net.NetworkCredential' -ArgumentList $UserName, $Password
                $fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
                $winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
            }

            'Credential object' {
                if ($Credential -is [Microsoft.TeamFoundation.Client.TfsClientCredentials])
                {
                    return $Credential
                }

                if($Credential -is [pscredential])
                {
                    $netCred = $Credential.GetNetworkCredential()
                }
                elseif ($Credential -is [System.Net.NetworkCredential])
                {
                    $netCred = $Credential
                }
                else
                {
                    throw "Invalid argument Credential. Supply either a PowerShell credential (PSCredential object) or a System.Net.NetworkCredential object."    
                }

                $fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
                $winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
            }

            'Personal Access Token' {
                $netCred = New-Object 'System.Net.NetworkCredential' -ArgumentList 'dummy-pat-user', $PersonalAccessToken
                $fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
                $winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
            }

            'Prompt for credential' {
                $fedCred = New-Object 'Microsoft.TeamFoundation.Client.CookieCredential' -ArgumentList $false
                $winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $false
                $allowInteractive = $true
            }

            else {
                throw "Invalid parameter set $($PSCmdlet.ParameterSetName)"
            }
        }

        return New-Object 'Microsoft.TeamFoundation.Client.TfsClientCredentials' -ArgumentList $winCred, $fedCred, $allowInteractive
    }
}
tools\TfsCmdlets\Connection\Connection.psd1
@{
    Description = 'This module contains cmdlets used to connect to and disconnect from Team Foundation Server objects (servers, collections and projects)'

    ModuleVersion = '0.0.0'

    RootModule = 'Connection.psm1'

    PrivateData = @{ 
        FriendlyName = 'Connection'
    }
}
tools\TfsCmdlets\Git\Branch\Git_Branch.ps1
<#
.SYNOPSIS
    Gets information from one or more branches in a Git repository.

.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-TfsGitBranch
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitBranchStats')]
    Param
    (
        [Parameter()]
        [Alias('RefName')]
        [SupportsWildcards()]
        [object] 
        $Branch = '*',

        [Parameter(ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [object] 
        $Repository,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
    }

    Process
    {
        if((-not $Repository) -and $Project)
        {
            $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
            $Repository = $tp.Name
        }

        $repos = Get-TfsGitRepository -Repository $Repository -Project $Project -Collection $Collection

        $tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}

        $client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc
        
        foreach($repo in $repos)
        {
            if($repo.Size -eq 0)
            {
                Write-Verbose "Repository $($repo.Name) is empty. Skipping."
                continue
            }

            $task = $client.GetBranchesAsync($tp.Name,$repo.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving branches from repository '$($repo.Name)'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

            Write-Output $result | Where-Object name -Like $Branch | `
                Add-Member -Name  'Project' -MemberType NoteProperty -Value $repo.ProjectReference.Name -PassThru | `
                Add-Member -Name  'Repository' -MemberType NoteProperty -Value $repo.Name -PassThru | `
                Sort-Object Project, Repository
        }
    }
}
tools\TfsCmdlets\Git\Policy\Git_Policy.ps1
<#
.SYNOPSIS
    Gets information from one or more Git repositories in a team project.

.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-TfsGitBranchPolicy
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Policy.WebApi.PolicyConfiguration')]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [object] 
        $Repository = '*',

        [Parameter()]
        [Alias('RefName')]
        [AllowNull()]
        [object] 
        $Branch = 'master',

        [Parameter()]
        [object] 
        $PolicyType,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
    }

    Process
    {
        if($Repository.ProjectReference.Name) {$Project = $Repository.ProjectReference.Name}; $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.SourceControl.WebApi.GitHttpClient' -Collection $tpc
        
        if($Branch -and ($Branch -notlike 'refs/*'))
        {
            $Branch = "refs/heads/$Branch"
        }

        $policyTypeId = $null

        if($PolicyType)
        {
            $policy = Get-TfsPolicyType -Type $PolicyType -Project $tp -Collection $tpc

            if(-not $policy)
            {
                throw "Invalid or non-existent policy type '$PolicyType'"
            }
            
            $policyTypeId = $PolicyType.Id
        }

        $repos = Get-TfsGitRepository -Repository $Repository -Project $tp -Collection $tpc

        foreach($repo in $repos)
        {
            $task = $client.GetPolicyConfigurationsAsync($tp.Name, $repo.Id, $Branch, $policyTypeId); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving branch policy configurations for repository '$($repo.Name)'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        }
        
        return $result.PolicyConfigurations
    }
}
tools\TfsCmdlets\Git\Repository\Git.psd1
@{
    Description = 'This module contains cmdlets used to administer Git repositories in Team Foundation Server'

    ModuleVersion = '0.0.0'

    RootModule = 'Git.psm1'

    PrivateData = @{ 
        FriendlyName = 'Git Repositories'
    }
}
tools\TfsCmdlets\Git\Repository\Git_Repository.ps1
<#
.SYNOPSIS
    Gets information from one or more Git repositories in a team project.

.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-TfsGitRepository
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias('Name')]
        [object] 
        $Repository = '*',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
    }

    Process
    {
        if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository]) { _Log "Input item is of type Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository; returning input item immediately, without further processing."; return $Repository }
        
        if(_TestGuid($Repository))
        {
            $tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
            
            $client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc

            $task = $client.GetRepositoryAsync($guid); $result = $task.Result; if($task.IsFaulted) { throw "Error getting repository with ID $guid" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

            return $result
        }

        $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.SourceControl.WebApi.GitHttpClient' -Collection $tpc

        $task = $client.GetRepositoriesAsync($tp.Name); $result = $task.Result; if($task.IsFaulted) { throw  "Error getting repository '$Repository'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        
        return $result | Where-Object Name -Like $Repository
    }
}
<#
.SYNOPSIS
Creates a new Git repository in a team project.

.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
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function New-TfsGitRepository
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
    Param
    (
        [Parameter(Mandatory=$true)]
        [Alias('Name')]
        [string] 
        $Repository,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Begin
    {
        Add-Type -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
        Add-Type -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
        Add-Type -AssemblyName 'Microsoft.TeamFoundation.Common'
    }

    Process
    {
        if($PSCmdlet.ShouldProcess($Repository, 'Create Git repository'))
        {
            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
            #$tpc = $tp.Store.TeamProjectCollection

            $gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'
            $tpRef = [Microsoft.TeamFoundation.Core.WebApi.TeamProjectReference] @{Id = $tp.Guid; Name = $tp.Name}
            $repoToCreate = [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository] @{Name = $Repository; ProjectReference = $tpRef}
            $task = $gitClient.CreateRepositoryAsync($repoToCreate, $tp.Name)

            $result = $task.Result
            
            if ($Passthru)
            {
                return $result
            }
        }
    }
}
<#
.SYNOPSIS
Deletes one or more Git repositories from a team project.

.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.SourceControl.WebApi.GitRepository
System.String
#>
Function Remove-TfsGitRepository
{
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [Alias('Name')]
        [object] 
        $Repository,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        Add-Type -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
        Add-Type -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
    }

    Process
    {
        if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
        {
            $Project = $Repository.ProjectReference.Name
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        #$tpc = $tp.Store.TeamProjectCollection

        $gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'

        if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
        {
            $reposToDelete = @($Repository)
        }
        else
        {
            $reposToDelete = Get-TfsGitRepository -Name $Repository -Project $Project -Collection $Collection
        }

        foreach($repo in $reposToDelete)
        {
            if ($PSCmdlet.ShouldProcess($repo.Name, "Delete Git repository from Team Project $($tp.Name)"))
            {
                $gitClient.DeleteRepositoryAsync($repo.Id).Wait()
            }
        }
    }
}

<#
.SYNOPSIS
Renames a Git repository in a team project.

.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
Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository
System.String
#>
Function Rename-TfsGitRepository
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
        [object] 
        $Repository,

        [Parameter(Mandatory=$true, Position=1)]
        [string] 
        $NewName,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
    }

    Process
    {
        if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
        {
            $Project = $Repository.ProjectReference.Name
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        #$tpc = $tp.Store.TeamProjectCollection

        $gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'

        if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
        {
            $reposToRename = @($Repository)
        }
        else
        {
            $reposToRename = Get-TfsGitRepository -Name $Repository -Project $Project -Collection $Collection
        }

        foreach($repo in $reposToRename)
        {
            if ($PSCmdlet.ShouldProcess($repo.Name, "Rename Git repository in Team Project $($tp.Name) to $NewName"))
            {
                $task = $gitClient.RenameRepositoryAsync($repo, $NewName)
                $task.Wait()

                if ($Passthru)
                {
                    return $task.Result
                }
            }
        }
    }
}

tools\TfsCmdlets\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
    }
}
tools\TfsCmdlets\GlobalList\GlobalList.psd1
@{
    Description = 'This module contains cmdlets to mantain Team Foundation Server global lists'

    ModuleVersion = '0.0.0'

    RootModule = 'GlobalList.psm1'

    PrivateData = @{ 
        FriendlyName = 'Global Lists'
    }
}
tools\TfsCmdlets\Helpers\Helpers.ps1
Function Get-TfsRestClient
{
    [CmdletBinding()]
    [OutputType('Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $Type,

        [Parameter()]
        [object] 
        $Collection
    )

    Process
    {
        return _GetRestClient @PSBoundParameters
    }
}
<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    PS C:> <example usage>
    Explanation of what the example does
.INPUTS
    Inputs (if any)
.OUTPUTS
    Output (if any)
.NOTES
    General notes
#>
Function Invoke-TfsRestApi
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Library call")]
        [Alias("Name")]
        [Alias("API")]
        [string]
        $Operation,

        [Parameter(ParameterSetName="Library call")]
        [Alias("Client")]
        [Alias("Type")]
        [string]
        $ClientType,

        [Parameter(ParameterSetName="Library call")]
        [object[]]
        $ArgumentList,

        [Parameter(ParameterSetName="Library call")]
        [string]
        $ErrorMessage,

        [Parameter(ParameterSetName="Library call")]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $AsTask
    )

    End
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}

        $client = _GetRestClient $ClientType -Collection $tpc

        $task = $client.$Operation.Invoke($ArgumentList)

        if ($AsTask)
        {
            return $task
        }

        $result = $task.Result; if($task.IsFaulted) { throw $Message + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

        return $result
    }
}
tools\TfsCmdlets\Identity\Identity.ps1
<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    PS C:> <example usage>
    Explanation of what the example does
.INPUTS
    Inputs (if any)
.OUTPUTS
    Output (if any)
.NOTES
    General notes
#>
Function Get-TfsIdentity
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0,Mandatory=$true)]
        [object]
        $Identity,

        [Parameter()]
        [switch]
        $QueryMembership,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    Process
    {
        if ($Identity -is [Microsoft.VisualStudio.Services.Identity.Identity]) { _Log "Input item is of type Microsoft.VisualStudio.Services.Identity.Identity; returning input item immediately, without further processing."; return $Identity }

        $tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
        
        $client = _GetRestClient 'Microsoft.VisualStudio.Services.Identity.Client.IdentityHttpClient' -Collection $tpc

        if($QueryMembership.IsPresent)
        {
            $qm = [Microsoft.VisualStudio.Services.Identity.QueryMembership]::Direct
        }
        else
        {
            $qm = [Microsoft.VisualStudio.Services.Identity.QueryMembership]::None
        }

        if(_TestGuid $Identity)
        {
            _Log "Finding identity with ID [$Identity] and QueryMembership=$qm"
            $task = $client.ReadIdentityAsync([guid]$Identity); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving information from identity [$Identity]" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        }
        else
        {
            _Log "Finding identity with account name [$Identity] and QueryMembership=$qm"
            $task = $client.ReadIdentitiesAsync([Microsoft.VisualStudio.Services.Identity.IdentitySearchFilter]::AccountName, [string]$Identity, 'None', $qm); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving information from identity [$Identity]" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        }

        return $result
    }
}
tools\TfsCmdlets\Lib\Ben.Demystifier.dll
md5: 80519367A8151440E8B3C4CD2D8BF9C8 | sha1: 8904E8F7755DB5DF07894C4A2DBB9028901BD0D2 | sha256: 5DFA652B6F95F1BB2FCD1388666E16D5E34290BE5903839708055AEAC76DBC3A | sha512: 31C7C535CD9BFB23553EAD5C566D51F34481A6AC53D4AE5924049D7899CADF239665B997B71D05BACE574B21FDC12A3306B4E559C5F004FC8D9AFE21CB79FFFD
tools\TfsCmdlets\Lib\HtmlAgilityPack.dll
md5: 3507317B404C0C4DED63BE80019AEF7E | sha1: 9491D0F9E622268052AE6FEF2639B995162FA068 | sha256: A5113FA6F67582631C8203DAF164CCCE5BC842597209DDBD9BBF0E54D94A0A37 | sha512: BC8A1778234DE2A865D879F2412B33A68671BC536811A9801ECCCEDBD8CD2E1092C084CC249D72C30BCFD3206E69901B5B0A163FEC976B312ECB2028A8BC5877
tools\TfsCmdlets\Lib\Microsoft.Azure.DevOps.Comments.WebApi.dll
md5: 543B3770272713C3C988DAA6FB35BD98 | sha1: 7BAADC8182FB3922A0696773D2D0748FE46EA795 | sha256: 3E0F866D1B62981222E7FCCFB90F34DAFDD65B348BD51410729923BB497AFF3C | sha512: D2559BBC7CCA7E3FD808EA7CF6A51CD38541C41E6F5150B04A373E30F3CC6EE336951F634B9AA3D10B49A6658C1670C465950024762BE240EA0356CAAC9215F5
tools\TfsCmdlets\Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
md5: A173BD8F903DF4C0622FCA18590F2EEA | sha1: F55504B1655BF1244878ECE7C0D3781D6E717B01 | sha256: A9B91AF8552ECF30785E46A782FDC9E87D7367C817BCFD9F45886A8CA7D80A12 | sha512: 96E81DA1A2E95D0492439658CA425C03B60A13C09A3418E6439D9CC6DA7FE1D97EF9EDE4F11106487873CBE3D027F9ADE42005167D6BD2438308A399FAD4C00F
tools\TfsCmdlets\Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll
md5: 562F424F78331CDEBF4B8A986AE90108 | sha1: 77CCDFEC42295E53EE40C00BBADF4D132F4F8ECB | sha256: 48F7BFEC411E09D89239694CCDDF719F8D58E7FF419C2970AE2E949C2008D3B3 | sha512: 465D1DAB773CDBB1028DFA2B236CC3E151EB74AB2C27BF2E2705A5D95D40F5D2373F73F0C8614A76E49F3D03AFDCB3CED0EE3F33798964CA9F76FBA951249D70
tools\TfsCmdlets\Lib\Microsoft.IdentityModel.JsonWebTokens.dll
md5: D9067C9A7D93E30C31DF6254E6B4F919 | sha1: 8DECDFC6972A452C7660079A05E19DB75FCB776E | sha256: 47F008C0A3B7B0027E718B3F1D9E9C1219CE917A4DAD86558098F92C66B20640 | sha512: F28E9995CE52B4F12F881DE8266361C47F50342B8330A58F5D7511833FA5D75FB6D3A7E9B51490EB513FC5EC1D3B65A1A443B93CC104A6DA5FD13C9A404525A7
tools\TfsCmdlets\Lib\Microsoft.IdentityModel.Logging.dll
md5: FE7F68B3A4D8ABEED004E42EAD6161C3 | sha1: 101CC0073E98C4A0C1C63DEE0F96503C8227CC84 | sha256: 8A2FED0AA975857CFA03A2E06B649CE2ABA0521660A300D0347A2FCC51E606BB | sha512: 1C28CD6E582AE6E60A99110173B88EB00B55408C70E21B627DD4A2BD128E624EC480DC0D455D69778E4C0957F65241BA0C26B1B5AC6144CDC4C02982CD17D2F5
tools\TfsCmdlets\Lib\Microsoft.IdentityModel.Tokens.dll
md5: 66DA4352F325FEA060BDA3F2C48BF5B1 | sha1: C893DE76B0E9B6BA2F341476B2DEAAEE21228D48 | sha256: C2CCE56EDF47414348C8FD76798931270BD754ECD01CE22B5DF8BA7841712169 | sha512: E5539BA7524851C15CC9386D041D75D67C9DBA579FA5B80DACE52B14C069AFF7718210CE161A5AEF45C0D953AFD99607AB3AC9336025194A14970FF754C8AAA8
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Build.Client.dll
md5: 095B76522ACF39C9DA549D8E627A843E | sha1: 4C2FA0FA69CF9D81E8FF951C8D471119A416FD10 | sha256: E6A39A0BE0CF95F73FDE2147D0631231C5D38FB3B3AC8E48DC94DD81F28C6E60 | sha512: 6D7FE767B06AAEB7118F3DD4CBD167BFCAFFD1290D57A9C908726E38DA6B6F08A500505D9A9F41750E7F523843BBBDB91DC8746332FF6D9259984A3447A76FBB
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Build.Common.dll
md5: 4E21226CAC9B627A0E8D0A625284229D | sha1: E39D333BA2F2875DF18E7727F03E8B984960A247 | sha256: 131C56E9B41CA6E30F7BE36A10E9C6A928C3F9110F19C7F71E596FC165EB7AE2 | sha512: C98AC2C2281035005CA43C8760F16A4129BB556874155F3A6834F0B0C56166A50F6D9C3CBDE527AA1FDF8E8A368920EE4735FEA860C912238A3B5AEA4BCB7D8B
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Build2.WebApi.dll
md5: B1DF64773785BF3F479F022D329BA571 | sha1: 9C9B9B61B7CCDE94A5CEA3250CFF02C3563D6743 | sha256: AAA14E60FD885C582CDDF2E238DBE65515B7C3CA048B7178833E2941FF69481D | sha512: AB8BDFEB9DC2D4E08403841891392E020E0836F5C946D8537912B5AC64F89A10BB51393443785D2F8E5DFF59D78AA55A84FE2D0DBEEB2ABC06FFC9C02B54C8C5
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Client.dll
md5: C4D3C7723CBCE3C62FEFC04BB401C7F3 | sha1: 239B1DAC5C215448EECB9D294557EF133EE93EBF | sha256: 51B8DB50ABE8B89A8595B8FE6C87EA4EAD04918FAF3EAAE93C5E513659DF4C2A | sha512: 39FCC1AA703873B2FB64D06D92D62637A6ABA5034E43B83E655B25A6DDA1CEF62E06C916655EFCA7768CE41DE39425533342387B1453E6C3BAD93F447F75240A
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Common.dll
md5: D58B7340CE76EBAFE80DF1FEFD36C7ED | sha1: 6AFF4A8E7A5F896C0DBCD8FD839426ECE10D32E5 | sha256: 343AC0E5B3F4701E30A49F1D276574311AF3A363E2803B05277CEB92A7EDD8FB | sha512: 193F7D5E8B832EFB61BB364F34BCB12D3330A8923ED37C3CEFBA1FF9FFDF9B7EE7BB38DA518C8AED4E3FFE0FC03EEBEB26503D78159EE9665388A3B55AEA28C4
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Core.WebApi.dll
md5: 8535A0FFDFEE910AC269FC1131E76470 | sha1: BFBDB6D1F65F2FA83A161A3EE8A718CCFE769FA8 | sha256: 10CB0CE7D190062C5C7AFA605DE2965AFFEA9DAF74096AE15D4C47C6EC5CD605 | sha512: C6398D30C74C75C0DF9FDF632506B66AD894E40D583654D61F715D3FA37C8B3479C6A359A6473BBE99D2F1FACB058A78A723BB57BA5188842A0C9150B0AFE150
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Dashboards.WebApi.dll
md5: 12CAEAD48009B54B27BEC9B88A9113F9 | sha1: 86DFB53623D5D80B60C1BE8D029C6919D03B9DEC | sha256: 1E7AB5626DA6EE3D9A0276DD4FAC1C0AE7E11092799913A78F8255B37C172C64 | sha512: F07FC9962D3E792141CF5846034817719FDF1E2DEB1E42DBF5EE5F9A3F060A7266A6118F8CE4294DA3CB4A518B988333896A1181E38377A562D0BCF9D83777E4
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.DeleteTeamProject.dll
md5: 5FE03F8DF08BF8119CAA0C83D5065945 | sha1: 6F133D5369246C33424527727FB1BEA4930C8C84 | sha256: 1D97D8A5B162C1017BE29E945761F1685E3615D8306A7784BB49047622DA15D7 | sha512: FA873719B7C158A66063BB94F2F29EC6BB6F5DDDB1ACBB5C3A91ACA3C0E1A5DAF131F4F6224288A1E84B4124E9A5F22EC00FFBABDE7E60EAAD923BDB3A97986F
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Diff.dll
md5: 3DD62C06A2E00BDD34D2BF362E033174 | sha1: A15BB001D3E69B1570C96FE012B6D97DDBD26755 | sha256: DCDD58F859EEF9A1B8FFEE256821C6FA93F287E20B0D3F1E23AD0DE69F74E89F | sha512: C9935B84489533A940C1F1FBC78F65339EF56C85CE12B879D2FF9901AB658402A369576E6B9EEFCA03EC1672DA9F0AE0162D6019810C67BF2FBC4E6186E43E01
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Discussion.Client.dll
md5: EA55F17ACC26BDCCB2A4F0C9300C351E | sha1: 4020BBA6697EAEF8CDE19351BF575424B358EF3F | sha256: C664CB4827753C76072C951BB608A4E40EC199858795CE06A60C2FDCA7860385 | sha512: E75F763A87C72F09D6D7F565E9B5BCC367C5F2EE0B5D2A9D067C6B6EC9EC90195A5BED5C73A0DC020153C9E67CBAA2A07B1A6755C0A1619DD5431F24A5958F31
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.DistributedTask.Common.Contracts.dll
md5: 56CFAF2018EB8CAA6BBDAD375700B0FA | sha1: 5FAC6807C0B0E3C22D638D18C62AACE60DDB8806 | sha256: 753449134A0654BC6F95C35F50E8551E2F68FC28E32C4732857CB04EE221C177 | sha512: 26884AF8A76254AD132AEDF67EECF2A752A04848B65104E09D905C08F3017623347C97F3623ED3B2290CE69F4A48456F525302F745EF70A9D6B108E24E5BC2FA
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Git.Client.dll
md5: A6E5235F655B83653E434EB2D747128E | sha1: C662B3B9974203314B8186CB582E75C631316A20 | sha256: E9853776715297F98AF365668CE0E2538FEB5B3BF2D727F1FBCE9A9FF64AA17B | sha512: F131F3D37CAF82B636C919015D05536A901E13639C2709BD4F268B16354A930CA0B7BD1D4A986261E6A11D0DDCF9BB09C081B43AD74AB49315F74ABAC19EE285
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Lab.Client.dll
md5: E5665D7BFD5E4F3A4B3CF17DB2B84C00 | sha1: 4F07DF25EDA37E8EA60EAE75FB4B2EC841795CAB | sha256: 6605E485608FFEA842E622AFD2D98D44E687C883EF21BC739EEE30323F689BA9 | sha512: 4ACA5329A0FE09C81CCF372D1410B4D3DD3E27CD7140FD0BD4CD2A745765E77BBCBA9F7E86C1F77BB6D201DEDCBBCEAF16791737A372202FCCDB4290E2BF84EE
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Lab.Common.dll
md5: A8003F17A8C286B3E12EA3956A56DF65 | sha1: 560B502C603814FF14BB72355BD89C4CDA21A529 | sha256: D8E0421A9B52D973A55508B3FD147D431CE9687B0AFFD038E525F107D5D6FA4B | sha512: 5CD9709463E311AF2645F98D16F59C6A08C91A831F5D4A7F251517DE7A6D65D1AA5D1269CB90F34B3EAD46B31411C0BDB8BA8DBABEF18631BA3CFF26BBE0DDF0
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Lab.TestIntegration.Client.dll
md5: 4958632531AF3B043539CC631FAD1C50 | sha1: EA8A82BFE9CB7A0F12EF02929B9AFC2C3A77C87B | sha256: D414BDF5DF71725D3078AEA3E2E442224E384B0651C7860F0E98FC66CCD3DBB7 | sha512: 57A4CA2287F368F49A21F8BCD923B96E42389B0F546C82EE119AF7B19D1F522955B7E9CE735D16CBFE6CF11FF01FB7008F949F45EC87EEDF222025A25618273E
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.dll
md5: C260C2E9096F70DD79C1D10F6EDBBFC3 | sha1: 6A742B457774804E647E59DA5052DCD6525D14DA | sha256: 249D53BB9B74A4E704A1E62A461781A8567C7B2E10C788DB8F65700FEB30C7FF | sha512: 05E4B10F0C0A119A5A2A830AC6A806F7B7286A3B39C9B978F0AEC4A8C0AD92C39A4FF94410E25E7439EA83574E5FD6389A7B504AC61C77E64AF4D0F3ABF4168B
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Policy.WebApi.dll
md5: 2A34B9781B549F83599DE5807E3CC03B | sha1: DF64DB107072BC6D6670ED9065908903F26E1ED6 | sha256: 474AE277BC240A0675B34C9E61C917EB311AA9F2B301DC96A386FA750C5F6C20 | sha512: 461AB388B0A48B895411F39D174F0FFF52D052507F85F0162D14D93B4AA6895E7739B3AE814547E0BB4048CBF89BDB68FE93962F57B58635B58BFCA76A9BB3FA
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.ProjectManagement.dll
md5: B500999BF0C3381ECBD533E030AED27F | sha1: C3722E01AD3C34FCE2D553A2112AA2E93CF530A4 | sha256: A2CC011BD17E27CFA9A03649AA0A8019E002AB9371CD43C05B7F0F2A979702EE | sha512: B20B94248C8DA79DE4F163E5484ECB4167FFA6BFA774B97E6A064F2D4E1A693CA7392B41821D7922099856B32169C60A25298A26B725B3B07BBE6B23EA868CCB
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.SharePointReporting.Integration.dll
md5: C28983921FA421350D468731324F18F0 | sha1: 3E0D9FD991979DA599D939FD11F149725262E1C6 | sha256: 7361F75C9E274AA6D1B4744A02136A504E248D18FA1F4DBE9F6645A3FC1373F3 | sha512: A0D9A5BF002154253E6CEB190626CEFD57035DDCB45607CE21CB13E2B6F3DB273A39EBD0782E203FB6D1376C472F9D0E0BC9A2D73E790806A679B3E12863C6A8
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.SourceControl.WebApi.dll
md5: 47E7FD547105D705CAAB4CE252DF0D01 | sha1: 85AA71CB35E232B98FA3A223F73AB9E7C30DB467 | sha256: F791789F10F76A163A7ABC104D9557CDCADFD69D688F6443306EECC7B86E9672 | sha512: 66A4C73586C52000349F0445DF07FAA658161011AC3D15199C705DA17A6FAEED34DD24D18120399097DE560F868E083A70CEF414ADF0DF4A0FCFCE368E20730B
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Test.WebApi.dll
md5: E3D34258E0DEABC4BD1D3C941081F28D | sha1: 4011F02D2F1893A767CDDA0B289779A51D42978E | sha256: 4E5B4A78C30AA75BB65E5AF40FD9404619B73C5E38585D4D89D65A5446929F71 | sha512: 2FD2EC5D19C3E3EFEE36D04FCB9FA2A3A3727C802BD81A70EA57E473ECE8171DE31A0D8184CAE7BF8445075924CBA6C22EE80F355EB475915D4358C877D9BFB3
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.TestImpact.Client.dll
md5: 7F5D108617BB011E76A8788E33A50D7F | sha1: BD7B1C120C2DFFCC45C5261562DB833AAB8C0802 | sha256: 4BE42F34898BEB8ABB0488E804535A92331567EE3ACC7194CFF6D1F81B43C06F | sha512: C827AF4CA46F9F802CBEDFADDFFD81453AA6FE74618AB12174200FBEB67F21232B7D0B9F04BDAAC7BBC760B6CE1E27DAD8C4878E78630D62DA5D66071B135542
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.TestManagement.Client.dll
md5: 1F71DDD0D210EB53DA2B6B35017FBA44 | sha1: 8BEDE858EA907FE81EE45E9CE91AE3F0965345A4 | sha256: 592CDC736AAD1B2DAD796358B829666408770741BF526C1C644AE008E5428CB1 | sha512: FA7FF1CE999EEC57F40DD234EA9F488950D054E52712DC6BB1DCC5473A4F05F00E07D63A2BD046F7B824DF80E05026844454A9E2B096570B1AABD44EE848F81E
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.TestManagement.Common.dll
md5: A413E40D9B8C0422EBD97453EB451564 | sha1: 7F0C9CA4EBEBF9E7EA2A81AE575A17569EB71F50 | sha256: B6F882985010BBE9BC12D421A04090E4400B884938447B4609F56FA90A1D58E8 | sha512: 626683C1CA7DE788F7E97E329CA701CF82F643FBD7FFA05D6E6301C6784FEFB03F9762D3F8353D3DE3B980FDBCDE093E65F771FEF11D02E5D255647CBE482EF8
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.TestManagement.WebApi.dll
md5: DC3A490D3B3B810F92778268FC6D0663 | sha1: A61B0742E9A6789BA37E5832438E562758FFB964 | sha256: A9CE50D30A21D9D77F18BE47BB44B6BE3BEC3127ABA0F4F2165AAF8CC1A46227 | sha512: E5F28D274DA40D245B81968A4083E5CD5C30F9FA25782407C93A2691E2C6F0E10A4CAF53C259A9EDF7EB8EAA30E53974D91C9368B7F3236ACADD44FC6CA52BB4
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.VersionControl.Client.dll
md5: 50C3E618A6E345C69FDF030853FCF146 | sha1: 0E781EF00EFF8FC0C524266CB81C31C44251681B | sha256: 293E446B58D577EAFB6304B04D499CF6B0ED15677124D67F56F388CABD22352B | sha512: D5954DBDC791ECE790332F81F805913BC8DEE461635D477EB1215F4A11A83958C5616FCEA194083C01B9BEE646D88CFD2CD68DCD7D27A2D111DF65610574AFF2
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.VersionControl.Common.dll
md5: 819E40858E0F4E5EF2D1BC77571691D4 | sha1: 09515D7BA79F32A33F858BA3DD269B8CB6582953 | sha256: 96E9A23BF3A2DE299884B8986FA1D2C5CD642CBE1B417CCA7E77C1FDB3D9C2C6 | sha512: 12CE656FE6C0F198365B8D29EFE7AE42681151D125C9F1A0B931A7D31347E04F9E3B159530044AEBF7316959E9172B86667EC45175772360FC2C6F67C977EB04
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.VersionControl.Common.Integration.dll
md5: 2D8B3EEEFA6B6BABF1A4C8BC268A9039 | sha1: 2FBAE46D4BC388C77B79977D351CC23F9F4662CC | sha256: B786D641283B1A3F39EFDEF1C7C11DCD5AEA52B0A404F4322B70EF66B5F7D700 | sha512: A7A074C4555C9E13749D1F9842FAA17B5E88C6646D5D5CD84A1F6D6DD3E29B7D76C060401ED2169843F3F8E95CE591292DE32B9B373690D5F0D51C21018FD329
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Wiki.WebApi.dll
md5: 8B704F35928C9EABA9790D18A422DB12 | sha1: 730F04CB2A8B26E38362FD469E4765E862CFA3B3 | sha256: 43AAD918447FD770B01C59FD59B53128EDD2C5A1E5E6EF96B1834C294F62131B | sha512: 8B95F5D3DF4EFC207C808C8047D907A994D1CF1C37C52016E8C526E980033F4863FA830610745177E2689E0FC16DB497FEB52073793B800F663C6F6CB29F3590
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.Work.WebApi.dll
md5: B8CDC0A685A53786503D79F62451BFD3 | sha1: 689C58646C87DAAFDBD3EF8867BB3DE884ABEB83 | sha256: E02F5894CBF05B426E3FA565822CB16F35BE471CE896DE9DF94B2AF71D4ADB72 | sha512: 0B5BD9C0A6BD60B113AECA5CAC866302F169764FADE771A0ABA0705EB3C7591FDC94C571979460EEBB70744D212787BFA4232EAA9A157CE2186527F99E359C13
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
md5: EFDD6854814D24CDCDA4F630C9FED31A | sha1: BC8377AF3302428C9391147F5B2D76E691F0C0DF | sha256: 3F4C00FF172F3B02C9A5ADD74E09B73A6230BC5543D1ED2C7FC9CA35CDA4746E | sha512: 4AF804EAE8D46460E988670C9BAD2B04AED833C42079BE7EE7DF0E227F9F0D146217B788D92C0C7AA18EE48A7648DD0D6552297889FD430C8073D4106665EB39
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
md5: EAF42C31094DEB3C47FD4A7C94ED8D89 | sha1: 02D25D4ABBF3F4A4B41B9910EFB903BB5590349A | sha256: DCDDB0CA878BB4C9C131C2CAAD1862125CDB55E2E3629562FDA5A601D372B094 | sha512: 2142BE69942FC220ECFF0B4C3C64CADF14B4C86E3CD22396ACFB151FB0A0E2D0CDB75850F448804B89E8AF8DD81D3D8BBC5B7139B1CD51871E4223091BFB4D17
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll
md5: 10207B37C4BAAAF4A07B578AB75C5DD8 | sha1: 547E8E21E246AF890953521C7403015F6D211B49 | sha256: 1FE5BD860623C44FA0204FE5A99073125BF55FC6AC9C94AA12A3FB67DBA8F00D | sha512: 463263C8D542AED5FB234E9D0AD1B3DF184E3EB6B236985B8482105FD783116E4A2414F6AFD5A6FE38474F1F613536080BAEFA2654DBDBF0CD3B02C94B1ABA0B
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Common.dll
md5: 81908C18C1CFBDF7BA064718BF5D674B | sha1: C70DF1CAFA171899797434DB5E4442ADEFFC0CA3 | sha256: 0F886E8F3F1F3327083534C3260E4C4728EC7F3D7F325E572F63EC0F61D17320 | sha512: 45667994FA7AC1AD9426EF932094EC2AD58CFDD462BBCB3F275DA783874E61D33B546BB7991013B7778BE5D5F510B42BF9712DACB3529D027C5B87FD308A5055
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Process.WebApi.dll
md5: 5A2F3EEF15F3517AA970A2F43976AC60 | sha1: D3837B2882637689910A9766A387AB8F39B9E7A3 | sha256: 90B28CCEA30A95C99164C15C27FCA223921D45D72778459D74D72DAC7C2A5B56 | sha512: 3E696F527033CD542307A811B699D209257E40623B023836BAB7B298F5632EC5C1A7ABA38EC7AFF55FBCEA177F10B47A0B6B47D8B14A45F7A6F553F3EAF28CF5
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll
md5: BA37627CDFDBDCC442F48AFDCAA6811A | sha1: 4F44326C57B4A84B90D4E6E57A863BED0221ED69 | sha256: 88291AF7D1B54B4231FDEB403DAAA9A32391A673C043B81AC6F867C1B1AE352B | sha512: 7B18EAF7B75B8E2679DDC4F109E3BCDD0167E1ECBA9652EA656FD0C0EBD0F6A8531F0F22404C1FB201FC82B4CF49E0B926C5A1B7A56A18041650712F866B147C
tools\TfsCmdlets\Lib\Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll
md5: 1598B6C5386F0F26DCF64A07A8A1D2B7 | sha1: EDEBE946D24244D3CED0753C03B78384B2524599 | sha256: A9591361304E8889698D28280E8AA2F5AF2DED77C7FCA69E8E24AA14E98DB223 | sha512: 6ED0D3961117D951BC572D06024AAEF96A1A0678FB8A2C82E6E2151FC09DCCBD11A5E56003B6BA771C2F1359C689DEEECA7EC9508D3E59DB0B5581B658C6C9B9
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.Client.Interactive.dll
md5: E2B61A5EACA36367B20926D360297AD9 | sha1: E3460011A507FD1953CC68FBB42A99191ED41AE1 | sha256: 823A9AFB6B1647A292E96A24805EE19C4FBC34759CC8911861C86FC04E33EA80 | sha512: 8A8FBC70F8F77FDD5B77B2D2B318A2D9C6B505DA2B20D5391E83F05CCF8BEAFD95E0D6991833715D1A16F376F7041CB2F8683644EE2BDAD7DAD695CFE42E0D4C
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.Common.dll
md5: FCA4B1CE2724A487025705355ABF74A7 | sha1: C536E919E0BD6529FBD0D9E3B24A0B1F453CC88E | sha256: AE2147DE3864B337767711772C8B15D33B4EDF5A8970FE64816DD8322710C347 | sha512: F33058F0EB12557DDF02C3A2D3329A93E8DD654B1100DBD8127E5D4A6AE8F1F7B926C9C93E013B0B3BA0BB846A1F75F6B759575DB106B9C10CB0CB02CC39A930
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.ServiceHooks.WebApi.dll
md5: F860586F9DC1D1CD6D02437B618E2FDF | sha1: FCFE18AB9B7E22BD3B55E551C49B89390C39EA54 | sha256: 4C4699D90FA72FCBEC2A6F4B5DC0352EE3363892996ADD1980ECEFAEB08187A8 | sha512: D0EE9F8FF3D7C58AFBB92A52461B05A42D5DB2BF7FECABFF5A41FEAC6ADDAAF92112B89DE4818DC781631FC611C958831CB5245691C47E51D7C0919072734DED
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.dll
md5: 07BDB928520AF4D376A35E9AC8A92A93 | sha1: B3A0BBB7CEA3259F33FC87A7A741FBB932F2F491 | sha256: 3588873756C2CABF5009FA571DB47DE1D69932890CEE903FA785378CE56B14A1 | sha512: A1CF5D0F1744D9BA6F7F7BECC16C3FFBC6AAE93B1C5ECAB97F0913F2D2B6571640237FD54223BA8F204EA826240D3DD4EFD6262E997C4309AE78272C43DBD192
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.TestResults.WebApi.dll
md5: 16F7009B2417C3FCE6A37F3D000EB9B2 | sha1: CF5456CDBA015327D9A993C9C6BAD05A89C3DF42 | sha256: 385970F99134535EE05A514D864B09E106A93BEC19F1F0C7BFD820D6066F8EF3 | sha512: B0AD52B3327ED0AD76201EC09A100C8B13DBA4205B6431F28823CE2B983BAD20CA425010A5E6E852340E8975B16CFCB24E4DCE3AC6C74A7678C40E8B52D4F47D
tools\TfsCmdlets\Lib\Microsoft.VisualStudio.Services.WebApi.dll
md5: 7E96A7E1D9ECCD2A9029AC6150D1BD39 | sha1: 31EEE0BD3AF6C94320BC84DE1112D17EDA69E1FF | sha256: A92EB9BC07F920BFC4841EBC16D19E2FAA45FB340C516ECB86D7E6A2652A6674 | sha512: C80A57F3DDC13EA0E0757911B00AE3155CC671E92ACE4E23B8CD6FCE14623E069AAD6CD0D82A529B82953406A4AB6165FFA489D95C7B430CE6B4DB613EE53831
tools\TfsCmdlets\Lib\Microsoft.WITDataStore32.dll
md5: 3AE1AE10726CD0102C4A85B07030D3B7 | sha1: AC72F6283FB5683F98D30CD6174F162BEF04ECEA | sha256: 6283B6D507880481193CF64028747AA6731598D11B15E4AAE1A794961A5CCA5B | sha512: E2D6C3359872CFE6480F7BD226E2368AE27A24A1F01A98F2B78B29A6815E9C80C2AC790823CA292438C8E959177989968A41ACF9DDF200C9888065F1ACE1C14F
tools\TfsCmdlets\Lib\Microsoft.WITDataStore64.dll
md5: D0A00CC544F89F271D2A48ED9B94F38A | sha1: 5D595582FA73166FEC1658D65D7991629B54820B | sha256: DE94137B22330F0575731BA771EB49CE60655B515C839C78A92E9BCDC0C98F52 | sha512: 69250F1A85C1A1FB4055779DD9EBB6848D76F30BB510D775C9BB5BD43F931393400BE8D6BFDCD795DEAEFAAD1E561CEBF7C7D6FE300FC420C31B096718D5A04B
tools\TfsCmdlets\Lib\Newtonsoft.Json.dll
md5: 07E04FD870CEE6F9994921B5AF243B7F | sha1: 0EA4611EEEE3736963CB718132099624BFEBF460 | sha256: 52CC6DDF77990FBAAAE4DB593F655610652133CEEADB32262C122D8C9EEA1BAD | sha512: 4639A7F77F7A9CAFA38C632332DD5085355623F3D84475374241A64BD110569F504086B479B519E90DDBD471D4A5034239418EBC03277424212E0E6698E64418
tools\TfsCmdlets\Lib\System.IdentityModel.Tokens.Jwt.dll
md5: 7D9196611D99181E8290484222F62E2C | sha1: 63ABE53F6591F475A06A03DE88E5D190C5FB1C8C | sha256: 6024102A8A0CF02357CDD0AC5F574069EE335A19E9467B3E1DE0F47348CE8354 | sha512: CC5E8467C5B387C0D2420EB5D60279DD93682DD7CA4B594BF5C9FF8136AE7F935AB9EE85AC6CBD832243FC65AA36D7725720C9CF3B3CEE19312D220DB7F95059
tools\TfsCmdlets\Lib\System.Net.Http.Formatting.dll
md5: 589E1B764C0DC53BF645054960626AB1 | sha1: A5616537CA4E4AD5EB0BEB48863AE65E9EA91080 | sha256: 1C7FA94DE5E727852934387B6B0094ABC16F660C6C91B38FB3F5BC580CFBDC1F | sha512: DFD6924DD7BAF7EB1B8D3CC862FD7FB4A311818EE5684C7A85E3106EAD0F3DAE2A79956AAD9B5404C88A1D2607CAD627D0EFD729E9A9C1C1425B907884FBD1D7
tools\TfsCmdlets\Lib\System.Web.Http.dll
md5: 1982B5586DE16B532074211AB7DA1CA6 | sha1: ED3E73BA41910D32618EBBB5E82BF9E74B51B062 | sha256: A47387C4A098DF3A57B967F1FF8604C7578F75B1481B2B969DF68DCEEF83ADFA | sha512: CBFFC5946773805EC1AE610C222EC8ABC65E39D561BD7E8CC98DC86655C218B5BD0CC15896D1F63FB061E493D7E5B88F26CF41FB5FAA24C4C754ADDE3792FC2B
tools\TfsCmdlets\Lib\System.Web.Http.WebHost.dll
md5: C3138D9BC26BCD3D225F551ED8C41792 | sha1: 60E5E95F4D0B06978636760F3375D6E23B28530B | sha256: ACEE4E07C74C6E0E10CFD25111D1E2E6A213EF6DB97449551C0E665250C5C3E9 | sha512: 3B8F4974E8755D4875DA125F2F04B7916C4B1F555E033E02A566F6037AC9A642CFFA4F5F36C83310223C41E1F1F44156C1763F241E7167D3E8CAB6F1A84D3177
tools\TfsCmdlets\Lib\TfsCmdletsLib.dll
md5: CA5D421B2E6F5220026702A1AFB7D6B0 | sha1: 3439213DA9870DBCEF63EFAF9F565DC20C6E5F98 | sha256: 36CCF5CF12AC7DB2EE8AAEEC7954C0B3527A9999A24BDDC998CB185033ECCEDC | sha512: EC8D537031FA4D427D6F6EE34CF54E5166CEB337185CAF446A9121903C47532DE483CDCAD8A992F4551B6358C5A836ED36108533B5861804DB5C8929B3B6BFD3
tools\TfsCmdlets\Organization\Organization.ps1
Function Get-AzDevOrganization
{
	[CmdletBinding(DefaultParameterSetName='Get by collection')]
	[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	Param
	(
		[Parameter(Position=0, ParameterSetName="Get by organization")]
		[object] 
		$Organization,
	
		[Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

		[Parameter(ParameterSetName="Get by collection")]
		[object]
		$Credential
	)

	Begin
	{
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi'
	}

	Process
	{
        if ($Current)
        {
            return $script:AzDevOrganizationConnection
        }
    }
}
tools\TfsCmdlets\Policy\Policy.ps1
<#
.SYNOPSIS
    Gets information from one or more Git repositories in a team project.

.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-TfsPolicyType
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Policy.WebApi.PolicyType')]
    Param
    (
        [Parameter()]
        [SupportsWildcards()]
        [Alias("Name")]
        [object] 
        $Type = '*',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
    }

    Process
    {
        if ($Type -is [Microsoft.TeamFoundation.Policy.WebApi.PolicyType]) { _Log "Input item is of type Microsoft.TeamFoundation.Policy.WebApi.PolicyType; returning input item immediately, without further processing."; return $Type }

        $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.Policy.WebApi.PolicyHttpClient' -Collection $tpc

        $task = $client.GetPolicyTypesAsync($tp.Name); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving policy types" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        
        return $result | Where-Object Display -Like $PolicyType
    }
}
tools\TfsCmdlets\ProcessTemplate\ProcessTemplate.ps1
<#
.SYNOPSIS
Exports a process template definition to disk.

.DESCRIPTION
This cmdlet offers a functional replacement to the "Export Process Template" feature found in Team Explorer. All files pertaining to the specified process template (work item defininitons, reports, saved queries, process configuration and so on) are downloaded from the given Team Project Collection and saved in a local directory, preserving the directory structure required to later re-import it. This is specially handy to do small changes to a process template or to create a new process template based on an existing one.

.PARAMETER Process
Name of the process template to be exported. Wildcards supported.

.PARAMETER DestinationPath
Path to the target directory where the exported process template (and related files) will be saved.

.PARAMETER NewName
Saves the exported process template with a new name. Useful when exporting a base template which will be used as a basis for a new process template.

.PARAMETER NewDescription
Saves the exported process template with a new description. Useful when exporting a base template which will be used as a basis for a new process template.

.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.

.EXAMPLE
Export-TfsProcessTemplate -Process 'Scrum' -DestinationPath C:\PT -Collection http://vsalm:8080/tfs/DefaultCollection
Exports the Scrum process template from the DefaultCollection project collection in the VSALM server, saving the template files to the C:\PT\Scrum directory in the local computer.

.EXAMPLE
Export-TfsProcessTemplate -Process 'Scrum' -DestinationPath C:\PT -Collection http://vsalm:8080/tfs/DefaultCollection -NewName 'MyScrum' -NewDescription 'A customized version of the Scrum process template'
Exports the Scrum process template from the DefaultCollection project collection in the VSALM server, saving the template files to the C:\PT\MyScrum directory in the local computer. Notice that the process template is being renamed from Scrum to MyScrum, so that it can be later reimported as a new process template instead of overwriting the original one.


.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Export-TfsProcessTemplate
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [object]
        $Process = "*",

        [Parameter(Mandatory=$true)]
        [string]
        $DestinationPath,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $NewName,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $NewDescription,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection $Collection
        $processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")

        if ($Process -is [Microsoft.TeamFoundation.Server.TemplateHeader])
        {
            $templates = @($Process)
        }
        else
        {
            $templates = Get-TfsProcessTemplate $Process -Collection $Collection
        }

        if ($NewName -or $NewDescription)
        {
            $templates = $templates | Select-Object -First 1
        }

        foreach($template in $templates)
        {
            if ($NewName)
            {
                $templateName = $NewName
            }
            else
            {
                $templateName = $template.Name
            }

            $tempFile = $processTemplateSvc.GetTemplateData($template.TemplateId)
            $zipFile = "$tempFile.zip"
            Rename-Item -Path $tempFile -NewName (Split-Path $zipFile -Leaf)

            $outDir = Join-Path $DestinationPath $templateName
            New-Item $outDir -ItemType Directory -Force | Out-Null

            Expand-Archive -Path $zipFile -DestinationPath $outDir

            if ($NewName -or $NewDescription)
            {
                $ptFile = (Join-Path $outDir "ProcessTemplate.xml")
                $ptXml = [xml] (Get-Content $ptFile)

                if ($NewName)
                {
                    $ptXml.ProcessTemplate.metadata.name = $NewName
                }

                if ($NewDescription)
                {
                    $ptXml.ProcessTemplate.metadata.description = $NewDescription
                }

                $ptXml.Save($ptFile)
            }

            Remove-Item $zipFile
        }
    }
}
<#

.SYNOPSIS
    Gets information from one or more process templates.

.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-TfsProcessTemplate
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Server.TemplateHeader')]
    Param
    (
        [Parameter(Position=0)]
        [Alias('Name')]
        [SupportsWildcards()]
        [string]
        $ProcessTemplate = "*",

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection $Collection
        $processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")
        $templateHeaders = $processTemplateSvc.TemplateHeaders() | Where-Object Name -Like $ProcessTemplate

        foreach($templateHeader in $templateHeaders)
        {
            $templateHeader | Add-Member Collection $tpc.DisplayName -PassThru
        }
    }
}
<#

.SYNOPSIS
    Imports a process template definition from disk.
    
.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 Import-TfsProcessTemplate
{
    [CmdletBinding(ConfirmImpact='Medium')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [ValidateScript({Test-Path $_  -PathType Container})]
        [string]
        $SourcePath,

        [Parameter()]
        [ValidateSet("Visible")]
        [string]
        $State = "Visible",

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if (-Not (Test-Path (Join-Path $SourcePath "ProcessTemplate.xml")))
        {
            throw "Invalid path. Source path ""$SourcePath"" must be a directory and must contain a file named ProcessTemplate.xml."
        }

        $tpc = Get-TfsTeamProjectCollection $Collection
        $processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")

        $tempFile = New-TemporaryFile
        $zipFile = "$tempFile.zip"
        Rename-Item $tempFile -NewName (Split-Path $zipFile -Leaf)

        Compress-Archive -Path "$SourcePath/**" -DestinationPath $zipFile -Force

        $ptFile = (Join-Path $SourcePath "ProcessTemplate.xml")
        $ptXml = [xml] (Get-Content $ptFile)

        $name = $ptXml.ProcessTemplate.metadata.name
        $description = $ptXml.ProcessTemplate.metadata.description
        $metadata = $ptXml.ProcessTemplate.metadata.OuterXml

        $processTemplateSvc.AddUpdateTemplate($name, $description, $metadata, $State, $zipFile);

        Remove-Item $zipFile
    }
}
tools\TfsCmdlets\ProcessTemplate\ProcessTemplate.psd1
@{
    Description = 'This module contains cmdlets to support administration of Team Foundation Server process templates'

    ModuleVersion = '0.0.0'

    RootModule = 'ProcessTemplate.psm1'

    PrivateData = @{ 
        FriendlyName = 'Process Templates'
    }
}
tools\TfsCmdlets\Prompt.ps1
Function Prompt
{
    Process
    {
        $promptPrefix = 'AzDev'
        $tfsPrompt = ''

        if ($script:TfsServerConnection)
        {
            $tfsPrompt = $script:TfsServerConnection.Name

            if ($tfsPrompt -like '*.visualstudio.com')
            {
                $promptPrefix = 'AzDev Services'
                $tfsPrompt = $tfsPrompt.SubString(0, $tfsPrompt.IndexOf('.'))
            }
            elseif ($tfsPrompt -like 'dev.azure.com/*')
            {
                $promptPrefix = 'AzDev Services'
                $tfsPrompt = $tfsPrompt.SubString($tfsPrompt.IndexOf('/'))
            }
            else
            {
                $promptPrefix = 'AzDev Server'

                if ($script:TfsTpcConnection)
                {
                    $tfsPrompt += "/$($script:TfsTpcConnection.Name)"
                }

                if ($script:TfsProjectConnection)
                {
                    $tfsPrompt += "/$($script:TfsProjectConnection.Name)"
                }

                if ($script:TfsTeamConnection)
                {
                    $tfsPrompt += "/$($script:TfsTeamConnection.Name)"
                }
            }

            $tfsPrompt = "[$tfsPrompt] "
        }

        "$promptPrefix $($tfsPrompt)$($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
    }
}
tools\TfsCmdlets\ServiceHook\ServiceHook.ps1
Function Get-TfsServiceHookConsumer
{
    [Cmdletbinding()]
    [OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Consumer')]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias('Name')]
        [Alias('Id')]
        [string]
        $Consumer = '*',

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection
        $client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc

        $client.GetConsumersAsync().Result | Where-Object {($_Name -Like $Consumer) -or ($_.Id -Like $Consumer)}
    }
}
Function Get-TfsServiceHookNotificationHistory
{
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true, Mandatory=$true)]
        [object]
        $Subscription,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection
        $client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc

        if ($Subscription -is [Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Subscription])
        {
            $Subscription = $Subscription.Id
        }

        $client.GetNotifications([guid] $Subscription, $null, $null, $null, $null) | Select-Object -ExpandProperty Result
    }
}
Function Get-TfsServiceHookPublisher
{
    [Cmdletbinding()]
    [OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Publisher')]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias('Name')]
        [Alias('Id')]
        [string]
        $Publisher = '*',

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection
        $client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc

        $client.GetPublishersAsync().Result | Where-Object {($_Name -Like $Publisher) -or ($_.Id -Like $Publisher)}
    }
}
Function Get-TfsServiceHookSubscription
{
    [Cmdletbinding()]
    [OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Subscription')]
    Param
    (
        [Parameter(Position=0)]
        [Alias('Name')]
        [string]
        $Subscription = '*',

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection
        $client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc

        $client.QuerySubscriptionsAsync().Result
    }
}
tools\TfsCmdlets\Startup.ps1
# Initialize Shell

if ($Host.UI.RawUI.WindowTitle -match "(Azure DevOps Shell*)|(Team Foundation Server Shell*)")
{
    # SetConsoleColors
    $Host.UI.RawUI.BackgroundColor = "DarkMagenta"
    $Host.UI.RawUI.ForegroundColor = "White"
    Clear-Host

    # ShowBanner
    $module = Test-ModuleManifest -Path (Join-Path $PSScriptRoot 'TfsCmdlets.psd1')
    Write-Host "TfsCmdlets: $($module.Description)"
    Write-Host "Version $($module.PrivateData.Build)"
    Write-Host ""

    . (Join-Path $PSScriptRoot 'Prompt.ps1')
}
tools\TfsCmdlets\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
        }
    }
}
tools\TfsCmdlets\Team\Team.psd1
@{
    Description = 'This module contains cmdlets to maintain Teams'

    ModuleVersion = '0.0.0'

    RootModule = 'Team.psm1'

    PrivateData = @{ 
        FriendlyName = 'Teams'
    }
}
tools\TfsCmdlets\Team\TeamAdmin\Team_TeamAdmin.ps1
Function Add-TfsTeamAdmin
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
    [OutputType('TfsCmdlets.TeamAdmins')]
    Param
    (
        # Specifies the board name(s). Wildcards accepted
        [Parameter(Position=0)]
        [Alias('Name')]
        [Alias('User')]
        [object]
        $Identity,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Team,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $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

        $id = Get-TfsIdentity -Identity $Identity -Collection $rpc

        $client = _GetRestClient 'TfsCmdlets.TeamAdminHttpClient' -Collection $tpc

        _Log "Adding $($id.IdentityType) '$($id.DisplayName) ($($id.Properties['Account']))' to team '$($t.Name)'"

        if(-not $PSCmdlet.ShouldProcess($t.Name, "Add administrator '$($id.DisplayName) ($($id.Properties['Account']))'"))
        {
            return
        }

        return $client.AddTeamAdmin($tp.Name, $t.Id, $id.Id)
    }
}
Function Get-TfsTeamAdmin
{
    [CmdletBinding()]
    [OutputType('Microsoft.VisualStudio.Services.Identity.Identity')]
    Param
    (
        # Specifies the board name(s). Wildcards accepted
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [object]
        $Identity = '*',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Team,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if($Team -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])
        {
            $Project = $Team.ProjectId
        }

        $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection -IncludeMembers

        $tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}

        _Log "Returning team admins from team '$($t.Name)'"

        foreach($member in $t.Members)
        {
            if(-not $member.IsTeamAdmin)
            {
            continue
            }

            $i = Get-TfsIdentity -Identity $member.Identity.Id -Collection $Collection

            if (($i.DisplayName -like $Identity) -or ($i.Properties['Account'] -like $Identity))
            {
                Write-Output $i | `
                    Add-Member -Name TeamId -MemberType NoteProperty -Value $t.Id -PassThru | `
                    Add-Member -Name ProjectId -MemberType NoteProperty -Value $t.ProjectId -PassThru
            }
        }
    }
}
Function Remove-TfsTeamAdmin
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
    [OutputType('TfsCmdlets.TeamAdmins')]
    Param
    (
        # Specifies the board name(s). Wildcards accepted
        [Parameter(Position=0,ValueFromPipeline=$true)]
        [Alias('Name')]
        [Alias('User')]
        [object]
        $Identity,

        [Parameter()]
        [object]
        $Team,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if($Identity.TeamId -and $Identity.ProjectId)
        {
            $Project = $Identity.ProjectId 
            $t = Get-TfsTeam -Team $Identity.TeamId -Project $Project -Collection $Collection
            
            $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
        }
        else
        {
            $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
        }

        $id = Get-TfsIdentity -Identity $Identity -Collection $rpc

        $client = _GetRestClient 'TfsCmdlets.TeamAdminHttpClient' -Collection $tpc

        _Log "Removing $($id.IdentityType) '$($id.DisplayName) ($($id.Properties['Account']))' from team '$($t.Name)'"

        if(-not $PSCmdlet.ShouldProcess($t.Name, "Remove administrator '$($id.DisplayName) ($($id.Properties['Account']))'"))
        {
            return
        }

        if(-not ([bool] $client.RemoveTeamAdmin($tp.Name, $t.Id, $id.Id).success))
        {
            throw 'Error removing team administrator'
        }
    }
}
tools\TfsCmdlets\TeamProject\TeamProject.ps1
<#
.SYNOPSIS
Gets information about one or more team projects. 

.DESCRIPTION
The Get-TfsTeamProject cmdlets gets one or more Team Project objects (an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.Project) from the supplied Team Project Collection.

.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.

.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 Server
Specifies either a URL or the name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.
For more details, see the -Server argument in the Get-TfsTeamProjectCollection cmdlet.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri

.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.

#>
Function Get-TfsTeamProject
{
    [CmdletBinding(DefaultParameterSetName='Get by project')]
	[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
    Param
    (
        [Parameter(Position=0, ParameterSetName='Get by project')]
        [object] 
        $Project = '*',

        [Parameter(ValueFromPipeline=$true, Position=1, ParameterSetName='Get by project')]
        [object]
        $Collection,

		[Parameter(Mandatory=$true, ParameterSetName="Get current")]
        [switch]
        $Current,

		[Parameter(ParameterSetName='Get by project')]
		[object]
		$Credential
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
    }

    Process
    {
        if ($Current)
        {
            return $script:TfsProjectConnection
        }

		if ($Project -is [Microsoft.TeamFoundation.WorkItemTracking.Client.Project]) { _Log "Input item is of type Microsoft.TeamFoundation.WorkItemTracking.Client.Project; returning input item immediately, without further processing."; return $Project }

        $tpc = Get-TfsTeamProjectCollection $Collection -Credential $Credential

        if(_TestGuid $Project)
        {
            $Project = [uri] "vstfs:///Classification/TeamProject/$Project"
        }

        if (($Project -is [uri]) -or ([System.Uri]::IsWellFormedUriString($Project, [System.UriKind]::Absolute)))
        {
            $css = $tpc.GetService([type]'Microsoft.TeamFoundation.Server.ICommonStructureService')
            $projInfo = $css.GetProject([string] $Project)
            $Project = $projInfo.Name
        }

		if ($Project -is [string])
		{
            $wiStore = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
                        
            if($Project.IndexOf('*') -ge 0)
            {
                return _GetAllProjects $tpc | Where-Object Name -Like $Project | Foreach-Object { $wiStore.Projects[$_.Name] }
            }

            return $wiStore.Projects[$Project]
		}

		if ($null -eq $Project)
		{
			if ($script:TfsProjectConnection)
			{
				return $script:TfsProjectConnection
			}
		}

		throw "No TFS team project information available. Either supply a valid -Project argument or use Connect-TfsTeamProject prior to invoking this cmdlet."
    }
}

Function _GetAllProjects
{
    param ($tpc)

    $css = $tpc.GetService([type]'Microsoft.TeamFoundation.Server.ICommonStructureService')

    return $css.ListAllProjects() | Where-Object Status -eq WellFormed
}
<#
.SYNOPSIS
Creates a new team project. 

#>
Function New-TfsTeamProject
{
    [CmdletBinding(DefaultParameterSetName='Get by project',ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true)]
        [string] 
        $Project,

        [Parameter(ValueFromPipeline=$true, Position=1)]
        [object]
        $Collection,

        [string]
        $Description,

        [string]
        [ValidateSet('Git', 'TFVC')]
        $SourceControl,

        [object]
        $ProcessTemplate,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        if($PSCmdlet.ShouldProcess($Project, 'Create team project'))
        {
            $tpc = Get-TfsTeamProjectCollection $Collection
            $template = Get-TfsProcessTemplate -Collection $tpc -Name $ProcessTemplate
            $client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient' -Collection $tpc

            $tpInfo = New-Object 'Microsoft.TeamFoundation.Core.WebApi.TeamProject'
            $tpInfo.Name = $Project
            $tpInfo.Description = $Description
            $tpInfo.Capabilities = New-Object 'System.Collections.Generic.Dictionary[[string],System.Collections.Generic.Dictionary[[string],[string]]]'

            $tpInfo.Capabilities.Add('versioncontrol', (New-Object 'System.Collections.Generic.Dictionary[[string],[string]]'))
            $tpInfo.Capabilities['versioncontrol'].Add('sourceControlType', $SourceControl)

            $tpInfo.Capabilities.Add('processTemplate', (New-Object 'System.Collections.Generic.Dictionary[[string],[string]]'))
            $tpInfo.Capabilities['processTemplate'].Add('templateTypeId', ([xml]$template.Metadata).metadata.version.type)

            # Trigger the project creation

            $token = $client.QueueCreateProject($tpInfo).Result

            if (-not $token)
            {
                throw "Error queueing team project creation: $($client.LastResponseContext.Exception.Message)"
            }

            # Wait for the operation to complete

            $operationsClient = _GetRestClient 'Microsoft.VisualStudio.Services.Operations.OperationsHttpClient' -Collection $tpc

            $opsToken = $operationsClient.GetOperation($token.Id).Result

            while (
                ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded) -and
                ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Failed) -and 
                ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Cancelled))
            {
                Start-Sleep -Seconds 2
                $opsToken = $operationsClient.GetOperation($token.Id).Result
            }

            if ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded)
            {
                throw "Error creating team project $Project"
            }

            # Force a metadata cache refresh prior to retrieving the newly created project

            $wiStore = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
            $wiStore.RefreshCache()

            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection

            if ($Passthru)
            {
                return $tp
            }
        }
    }
}
<#
.SYNOPSIS
Deletes one or more team projects. 

.DESCRIPTION

.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.

.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 Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri

.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.

#>
Function Remove-TfsTeamProject
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
    Param
    (
        [Parameter(Position=0,ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [object] 
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Hard,

        [Parameter()]
        [switch]
        $Force
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
    }

    Process
    {
        $tps = Get-TfsTeamProject -Project $Project -Collection $Collection

        if(-not $tps)
        {
            return
        }

        foreach($tp in $tps)
        {
            $tpc = $tp.TeamProjectCollection
            $client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient' -Collection $tpc

            if($PSCmdlet.ShouldProcess($tp.Name, 'Delete team project'))
            {
                if((-not $Hard.IsPresent) -or ($Force.IsPresent -or ($PSCmdlet.ShouldContinue('The team project deletion is IRREVERSIBLE and may cause DATA LOSS. Are you sure you want to proceed?'))))
                {
                    $method = (&{if($Hard.IsPresent) {'Hard'} else {'Soft'}})

                    _Log "$method-deleting team project $($tp.Name)"

                    $token = $client.QueueDeleteProject($tp.Guid, $Hard.IsPresent).Result

                    if (-not $token)
                    {
                        throw "Error queueing team project deletion: $($client.LastResponseContext.Exception.Message)"
                    }
        
                    # Wait for the operation to complete
        
                    $operationsClient = _GetRestClient 'Microsoft.VisualStudio.Services.Operations.OperationsHttpClient' -Collection $tpc
        
                    $opsToken = $operationsClient.GetOperation($token.Id).Result
        
                    while (
                        ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded) -and
                        ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Failed) -and 
                        ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Cancelled))
                    {
                        _Log "Waiting for the queued operation to finish (current status: $($opsToken.Status))"

                        Start-Sleep -Seconds 1
                        $opsToken = $operationsClient.GetOperation($token.Id).Result
                    }
        
                    if ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded)
                    {
                        _Log "Queued operation finished with status $($opsToken.Status)"

                        throw "Error deleting team project ${Project}: $($opsToken.DetailedMessage)"
                    }
                }
            }
        }
    }
}
tools\TfsCmdlets\TeamProject\TeamProject.psd1
�@{
    Description = 'This module contains cmdlets to maintain and administer Team Projects'

    ModuleVersion = '0.0.0'

    RootModule = 'TeamProject.psm1'

    PrivateData = @{ 
        FriendlyName = 'Team Projects'
    }
}
tools\TfsCmdlets\TeamProjectCollection\TeamProjectCollection.ps1
<#
.SYNOPSIS
Detaches a team project collection database from a Team Foundation Server installation

.DESCRIPTION
Before you move a collection, you must first detach it from the deployment of TFS on which it is running. It's very important that you not skip this step. When you detach a collection, all jobs and services are stopped, and then the collection database is stopped. In addition, the detach process copies over the collection-specific data from the configuration database and saves it as part of the team project collection database. This configuration data is what allows the collection database to be attached to a different deployment of TFS. If that data is not present, you cannot attach the collection to any deployment of TFS except the one from which it originated.
If detachment succeeds, the original database connection string is returned. It is required to re-attach the collection to TFS.

.PARAMETER Reason
Speficies a Servicing Message (optional), to provide a message for users who might try to connect to projects in this collection

.PARAMETER Timeout
The maximum period of time this cmdlet should wait for the detach procedure to complete. By default, it waits indefinitely until the collection servicing completes

.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 Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object. 

When using a URL, it must be fully qualified. The format of this string is as follows: 

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/] 

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.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri

.EXAMPLE
Dismount-TfsTeamProjectCollection -Collection http://vsalm:8080/tfs/DefaultCollection -Reason 'Collection DefaultCollecton is down for maintenance'
Detaches the project collection specified by the URL provided in the Collection argument, defining a Maintenance Message to be shown to users when they try to connect to that collection while it is detached

.LINK
https://www.visualstudio.com/en-us/docs/setup-admin/tfs/admin/move-project-collection#1-detach-the-collection

.NOTES
Detaching a collection prevents users from accessing any projects in that collection
#>
Function Dismount-TfsTeamProjectCollection
{
	[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
	[OutputType('string')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[object] 
		$Collection,

		[Parameter(ValueFromPipeline=$true)]
		[object] 
		$Server,
	
		[Parameter()]
		[string]
		$Reason,
	
		[Parameter()]
		[timespan]
		$Timeout = [timespan]::MaxValue,

		[Parameter()]
		[object]
		$Credential
	)

	Process
	{
		$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Credential

		if ($PSCmdlet.ShouldProcess($tpc.Name, "Detach Project Collection"))
		{
			$configServer = $tpc.ConfigurationServer
			$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
			$collectionInfo = $tpcService.GetCollection($tpc.InstanceId)
			$connectionString = $null

			$tpcJob = $tpcService.QueueDetachCollection($collectionInfo, $null, $Reason, [ref] $connectionString)
			$collectionInfo = $tpcService.WaitForCollectionServicingToComplete($tpcJob, $Timeout)

			return $connectionString
		}
	}
}
<#
.SYNOPSIS
    Gets one or more Team Project Collection addresses registered in the current computer.

.PARAMETER Name
    Specifies the name of a registered collection. When omitted, all registered collections are returned. Wildcards are permitted.

.INPUTS
    System.String
#>
Function Get-TfsRegisteredTeamProjectCollection
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Client.RegisteredProjectCollection[]')]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [Alias('Name')]
        [SupportsWildcards()]
        [string]
        $Collection = "*"
    )

    Process
    {
        $registeredCollections = [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetProjectCollections() 
        
        foreach($tpc in $registeredCollections)
        {
            $tpcName = ([uri]$tpc.Uri).Segments[-1]

            if($tpcName -like $Collection)
            {
                Write-Output $tpc
            }
        }
    }
}
<#
.SYNOPSIS
Gets information about one or more team project collections.

.DESCRIPTION
The Get-TfsTeamProjectCollection cmdlets gets one or more Team Project Collection objects (an instance of Microsoft.TeamFoundation.Client.TfsTeamProjectCollection) from a TFS instance. 
Team Project Collection objects can either be obtained by providing a fully-qualified URL to the collection or by collection name (in which case a TFS Configuration Server object is required).

.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 Server
Specifies either a URL/name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.

.PARAMETER Current
Returns the team project collection specified in the last call to Connect-TfsTeamProjectCollection (i.e. the "current" project collection)

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx

.EXAMPLE
Get-TfsTeamProjectCollection http://

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri

.NOTES
Cmdlets in the TfsCmdlets module that operate on a collection level require a TfsConfigurationServer object to be provided via the -Server argument. If absent, it will default to the connection opened by Connect-TfsConfigurationServer.
#>
Function Get-TfsTeamProjectCollection
{
	[CmdletBinding(DefaultParameterSetName='Get by collection')]
	[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
	[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
	Param
	(
		[Parameter(Position=0, ParameterSetName="Get by collection")]
        [SupportsWildcards()]
		[object] 
		$Collection = "*",
	
		[Parameter(ValueFromPipeline=$true, ParameterSetName="Get by collection")]
		[object] 
		$Server,
	
		[Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

		[Parameter(ParameterSetName="Get by collection")]
		[object]
		$Credential
	)

	Begin
	{
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
	}

	Process
	{
		if (($Current.IsPresent -or (-not $Collection)) -and ($script:TfsTpcConnection))
        {
            return $script:TfsTpcConnection
		}
		
		if ($Collection -is [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])
		{
			return $Collection
		}

		$cred = Get-TfsCredential -Credential $Credential

		if ($Collection -is [Uri] -or ([Uri]::IsWellFormedUriString($Collection, [UriKind]::Absolute)))
		{
			return New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList ([uri]$Collection), $cred
		}

		if ($Collection -is [string])
		{
			$configServer = Get-TfsConfigurationServer -Server $Server -Credential $cred

			if($configServer)
			{
				$filter = [Guid[]] @([Microsoft.TeamFoundation.Framework.Common.CatalogResourceTypes]::ProjectCollection)
				$collections = $configServer.CatalogNode.QueryChildren($filter, $false, [Microsoft.TeamFoundation.Framework.Common.CatalogQueryOptions]::None) 
				$collections = $collections | Select-Object -ExpandProperty Resource | Where-Object DisplayName -like $Collection

				foreach ($tpc in $collections)
				{
					$collectionId = $tpc.Properties["InstanceId"]
					Write-Output $configServer.GetTeamProjectCollection($collectionId)
				}
			}

			$registeredCollection = Get-TfsRegisteredTeamProjectCollection $Collection

			if($registeredCollection.Count)
			{
				foreach($tpc in $registeredCollection)
				{
					Write-Output (New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList ([uri]$tpc.Uri), $cred)
				}

				return
			}
		}
	}
}
<#
.SYNOPSIS
Attaches a team project collection database to a Team Foundation Server installation.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Mount-TfsTeamProjectCollection
{
    [CmdletBinding(ConfirmImpact='Medium')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[Alias('Name')]
		[string]
		$Collection,

		[Parameter()]
		[string]
		$Description,

		[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
		[string]
		$DatabaseServer,

		[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
		[string]
		$DatabaseName,

		[Parameter(ParameterSetName="Use connection string", Mandatory=$true)]
		[string]
		$ConnectionString,

		[Parameter()]
		[ValidateSet("Started", "Stopped")]
		[string]
		$InitialState = "Started",

		[Parameter()]
		[switch]
		$Clone,

		[Parameter()]
		[int]
		$PollingInterval = 5,

		[Parameter()]
		[timespan]
		$Timeout = [timespan]::MaxValue,

		[Parameter(ValueFromPipeline=$true)]
		[object] 
		$Server,
	
		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)
	Process
	{
		$configServer = Get-TfsConfigurationServer $Server -Credential $Credential
		$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')

		$servicingTokens = New-Object 'System.Collections.Generic.Dictionary[string,string]'

		if ($DatabaseName)
		{
			$servicingTokens["CollectionDatabaseName"] = $DatabaseName
		}

		if ($PSCmdlet.ParameterSetName -eq "Use database server")
		{
			$ConnectionString = "Data source=$DatabaseServer; Integrated Security=true; Initial Catalog=$DatabaseName"
		}

		try
		{
			Write-Progress -Id 1 -Activity "Attach team project collection" -Status "Attaching team project collection $Collection" -PercentComplete 0

			#$start = Get-Date

			# string databaseConnectionString, IDictionary<string, string> servicingTokens, bool cloneCollection, string name, string description, string virtualDirectory)

			$tpcJob = $tpcService.QueueAttachCollection(
				$ConnectionString,
				$servicingTokens, 
				$Clone.ToBool(),
				$Collection,
				$Description,
				"~/$Collection/")

			[void] $tpcService.WaitForCollectionServicingToComplete($tpcJob, $Timeout)

			return Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Collection
		}
		finally
		{
			Write-Progress -Id 1 -Activity "Attach team project collection" -Completed
		}

		throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Collection")
	}
}
<#
.SYNOPSIS
Creates a new team project collection.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.INPUTS
System.String
#>
Function New-TfsTeamProjectCollection
{
	[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
	[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[Alias('Name')]
		[string]
		$Collection,

		[Parameter()]
		[string]
		$Description,

		[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
		[string]
		$DatabaseServer,

		[Parameter(ParameterSetName="Use database server")]
		[string]
		$DatabaseName,

		[Parameter(ParameterSetName="Use connection string", Mandatory=$true)]
		[string]
		$ConnectionString,

		[Parameter()]
		[switch]
		$Default,

		[Parameter()]
		[switch]
		$UseExistingDatabase,

		[Parameter()]
		[ValidateSet("Started", "Stopped")]
		[string]
		$InitialState = "Started",

		[Parameter()]
		[int]
		$PollingInterval = 5,

		[Parameter()]
		[timespan]
		$Timeout = [timespan]::MaxValue,

		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty,

		[Parameter()]
		[switch]
		$Passthru
	)

	Process
	{
		if($PSCmdlet.ShouldProcess($Collection, 'Create team project collection'))
		{
			$configServer = Get-TfsConfigurationServer $Server -Credential $Credential
			$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
			$servicingTokens = New-Object 'System.Collections.Generic.Dictionary[string,string]'
			$servicingTokens["SharePointAction"] = "None"
			$servicingTokens["ReportingAction"] = "None"

			if ($DatabaseName)
			{
				$servicingTokens["CollectionDatabaseName"] = $DatabaseName
			}

			if ($UseExistingDatabase)
			{
				$servicingTokens["UseExistingDatabase"] = $UseExistingDatabase.ToBool()
			}

			if ($PSCmdlet.ParameterSetName -eq "Use database server")
			{
				$ConnectionString = "Data source=$DatabaseServer; Integrated Security=true"
			}

			try
			{
				Write-Progress -Id 1 -Activity "Create team project collection" -Status "Creating team project collection $Collection" -PercentComplete 0

				$start = Get-Date

				$tpcJob = $tpcService.QueueCreateCollection(
					$Collection,
					$Description, 
					$Default.ToBool(),
					"~/$Collection/",
					[Microsoft.TeamFoundation.Framework.Common.TeamFoundationServiceHostStatus] $InitialState,
					$servicingTokens,
					$ConnectionString,
					$null,  # Default connection string
					$null)  # Default category connection strings

				while((Get-Date).Subtract($start) -le $Timeout)
				{
					Start-Sleep -Seconds $PollingInterval

					$collectionInfo = $tpcService.GetCollection($tpcJob.HostId, [Microsoft.TeamFoundation.Framework.Client.ServiceHostFilterFlags]::IncludeAllServicingDetails)
					$jobDetail = $collectionInfo.ServicingDetails | Where-Object JobId -eq $tpcJob.JobId

					if (($null -eq $jobDetail) -or 
						(($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Queued) -and 
						($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Running)))
					{
						if ($jobDetail.Result -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobResult]::Failed -or 
							$jobDetail.JobStatus -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Failed)
						{
							throw "Error creating team project collection $Collection : "
						}
					
						$tpc = Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Collection

						if ($Passthru)
						{
							return $tpc
						}
					}
				}
			}
			finally
			{
					Write-Progress -Id 1 -Activity "Create team project collection" -Completed
			}

			throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Collection")
		}
	}
}
<#

.SYNOPSIS
    Deletes a team project collection

.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.INPUTS
	Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
    System.Uri
#>
Function Remove-TfsTeamProjectCollection
{
	[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[object] 
		$Collection,

		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[timespan]
		$Timeout = [timespan]::MaxValue,

		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)

	Process
	{
		$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Credential

		if ($PSCmdlet.ShouldProcess($tpc.Name, "Delete Team Project Collection"))
		{
			Write-Progress -Id 1 -Activity "Delete team project collection" -Status "Deleting $($tpc.Name)" -PercentComplete 0
		
			try
			{
				$configServer = $tpc.ConfigurationServer
				$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
				$collectionInfo = $tpcService.GetCollection($tpc.InstanceId)

				$collectionInfo.Delete()
			}
			finally
			{
				Write-Progress -Id 1 -Activity "Delete team project collection" -Completed
			}
		}
	}
}
<#

.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.INPUTS
	Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
    System.Uri
#>
Function Start-TfsTeamProjectCollection
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[object] 
		$Collection,

		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)

	Process
	{
		if($PSCmdlet.ShouldProcess($Collection, 'Start team project collection'))
		{
			throw "Not implemented"
		}
	}
}
<#
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.


.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Stop-TfsTeamProjectCollection
{
    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[object] 
		$Collection,

		[Parameter()]
		[string]
		$Reason,
	
		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[System.Management.Automation.Credential()]
		[System.Management.Automation.PSCredential]
		$Credential = [System.Management.Automation.PSCredential]::Empty
	)

	Process
	{
		if($PSCmdlet.ShouldProcess($Collection, 'Stop team project collection'))
		{
			throw "Not implemented"
		}
	}
}
tools\TfsCmdlets\TeamProjectCollection\TeamProjectCollection.psd1
@{
    Description = 'This module contains cmdlets to maintain and administer Team Project Collections'

    ModuleVersion = '0.0.0'

    RootModule = 'TeamProjectCollection.psm1'

    PrivateData = @{ 
        FriendlyName = 'Team Project Collections'
    }
}
tools\TfsCmdlets\TestManagement\TestManagement.ps1
<#
.SYNOPSIS
	Clones a test plan and, optionally, its test suites and test cases

.DESCRIPTION
	The Copy-TfsTestPlan copies ("clones") a test plan to help duplicate test suites and/or test cases. Cloning is useful if you want to branch your application into two versions: after copying, the tests for the two versions can be changed without affecting each other.

.EXAMPLE
	Copy-TfsTestPlan -TestPlan 'My test plan' -Project 'SourceProject' -Destination 'TargetProject' -NewName 'My new test plan'

.INPUTS
	Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan

.OUTPUTS
	Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan

.NOTES
	When you clone a test suite, the following objects are copied from the source test plan to the destination test plan: 

    * Test cases (note: Each new test case retains its shared steps. A link is made between the source and new test cases. The new test cases do not have test runs, bugs, test results, and build information);
    * Shared steps referenced by cloned test cases;
    * Test suites (note: The following data is retained - Names and hierarchical structure of the test suites; Order of the test cases; Assigned testers; Configurations)
    * Action Recordings linked from a cloned test case
    * Links and Attachments
    * Test configuration
	
	The items below are only copied when using -CloneRequirements:

    * Requirements-based suites;
    * Requirements work items (product backlog items or user stories);
    * Bug work items, when in a project that uses the Scrum process template or any other project in which the Bug work item type is in the Requirements work item category. In other projects, bugs are not cloned.

.PARAMETER TestPlan

.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 NewName

.PARAMETER DestinationProject

.PARAMETER AreaPath

.PARAMETER IterationPath

.PARAMETER DeepClone

.PARAMETER CopyAllSuites

.PARAMETER CopyAncestorHierarchy

.PARAMETER DestinationWorkItemType

.PARAMETER SuiteIds

.PARAMETER RelatedLinkComment

.PARAMETER Passthru
	Returns the results of the command. By default, this cmdlet does not generate any output. 

.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.

#>
Function Copy-TfsTestPlan
{
    [CmdletBinding()]
    [OutputType('Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan')]
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $TestPlan,

        [Parameter()]
        [object] 
        $Project,

        [Parameter()]
        [string] 
        $NewName,

		[Parameter()]
		[Alias('Destination')]
        [object] 
        $DestinationProject,

        [Parameter()]
        [string] 
        $AreaPath,

        [Parameter()]
        [string] 
        $IterationPath,

        [Parameter()]
        [switch] 
        $DeepClone,

		[Parameter()]
		[Alias("Recurse")]
        [switch] 
        $CopyAllSuites,

        [Parameter()]
        [switch] 
        $CopyAncestorHierarchy,

        [Parameter()]
        [switch] 
        $CloneRequirements,

        [Parameter()]
        [string] 
        $DestinationWorkItemType = 'Test Case',

        [Parameter()]
        [int[]] 
		$SuiteIds,
		
		[Parameter()]
		[string]
		$RelatedLinkComment,

        [Parameter()]
		[ValidateSet('Original', 'Copy', 'None')]
        [string]
        $Passthru = 'None',

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.TestManagement.WebApi'
		$ns = 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
    }

    Process
    {
		$plan = Get-TfsTestPlan -TestPlan $TestPlan -Project $Project -Collect $Collection

		if(-not $plan)
		{
            throw "Invalid or non-existent test plan $TestPlan"
		}

		$destTp = Get-TfsTeamProject -Project $DestinationProject -Collection $Collection

		if(-not $destTp)
		{
            throw "Invalid or non-existent team project $DestinationProject"
		}

		if (-not $Project)
		{
			$Project = $plan.Project.Name
		}

		$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
		
		if(-not $tp)
		{
            throw "Invalid or non-existent team project $Project"
		}

		if (-not $NewName)
		{
			if($tp.Name -ne $destTp.Name)
			{
				$NewName = $plan.Name
			}
			else
			{
				$NewName = "$($plan.Name) (cloned $([DateTime]::Now.ToShortDateString()))"
			}
		}

		if (-not $AreaPath)
		{
			$AreaPath = $destTp.Name
		}

		if (-not $IterationPath)
		{
			$IterationPath = $destTp.Name
		}

        $tpc = $tp.Store.TeamProjectCollection
		
		$client = _GetRestClient "$ns.TestPlanHttpClient" -Collection $tpc

		$cloneParams = New-Object "$ns.CloneTestPlanParams" -Property @{
			sourceTestPlan = New-Object "$ns.SourceTestPlanInfo" -Property @{
				Id = $plan.Id
			};
			destinationTestPlan = New-Object "$ns.DestinationTestPlanCloneParams" -Property @{
				Project = $destTp.Name;
				Name = $NewName;
				AreaPath = $AreaPath;
				Iteration = $IterationPath
			};
			cloneOptions = New-Object "Microsoft.TeamFoundation.TestManagement.WebApi.CloneOptions" -Property @{
				RelatedLinkComment = $RelatedLinkComment;
				CopyAllSuites = $CopyAllSuites.IsPresent;
				CopyAncestorHierarchy = $CopyAncestorHierarchy;
				DestinationWorkItemType = $DestinationWorkItemType;
				CloneRequirements = $CloneRequirements;
				OverrideParameters = _NewDictionary @([string],[string]) @{
					'System.AreaPath' = $AreaPath;
					'System.IterationPath' = $IterationPath
				}
			}
		}
		
		$task = $client.CloneTestPlanAsync($cloneParams, $tp.Name, $DeepClone.IsPresent)

		$result = $task.Result; if($task.IsFaulted) { throw 'Error cloning test plan' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

		$opInfo = $result

		do
		{
			Start-Sleep -Seconds 1
			$opInfo = $client.GetCloneInformationAsync($tp.Name, $opInfo.CloneOperationResponse.opId)
		}
		while ($opInfo.CloneOperationResponse.CloneOperationState -match 'Queued|InProgress')

		if ($opInfo.CloneOperationResponse.CloneOperationState -eq 'Failed')
		{
			throw "Error cloning test plan '$($plan.Name)': $($opInfo.CloneOperationResponse.Message)"
		}
		else
		{
			$copy = $opInfo.DestinationTestPlan	
		}

		if ($Passthru -eq 'Original')
		{
			return $plan
		}
		
		if($Passthru -eq 'Copy')
		{
			return $copy
		}
    }
}
<#
.SYNOPSIS
    Gets the contents of one or more test plans

.DESCRIPTION

.EXAMPLE
    Get-TfsTestPlan 'Release 1 - Sprint*' -Project 'Fabrikam'
    
    Returns all test plans from team project 'Fabrikam' whose names start with 'Release 1 - Sprint'

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project

.OUTPUTS
    Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan

.NOTES
    
#>
Function Get-TfsTestPlan
{
    [CmdletBinding()]
    [OutputType('Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan')]
    Param
    (
        # Specifies the test plan name. Wildcards are supported
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias("Id")]
        [Alias("Name")]
        [object]
        $TestPlan = '*',

        # Specifices the plan's owner name
        [Parameter()]
        [string]
        $Owner,

        # Get only basic properties of the test plan
        [Parameter()]
        [switch]
        $NoPlanDetails,

        # Get just the active plans
        [Parameter()]
        [switch]
        $FilterActivePlans,

        # Specifies the team project
        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        # Specifies the collection / organization
        [Parameter()]
        [Alias("Organization")]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
    }

    Process
    {
        if ($TestPlan -is [Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan])
        {
            return $TestPlan
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $tpc = $tp.Store.TeamProjectCollection
        $client = _GetRestClient 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlanHttpClient' -Collection $tpc

        return $client.GetTestPlansAsync(
            $tp.Name, $Owner, $null, 
            (-not $NoPlanDetails.IsPresent), 
            $FilterActivePlans.IsPresent).Result | Where-Object Name -like $TestPlan
    }
}
Function Remove-TfsTestPlan
{
    [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $TestPlan,

        [Parameter()]
        [object] 
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
		#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.TestManagement.WebApi'
		$ns = 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
    }

    Process
    {
		$plan = Get-TfsTestPlan -TestPlan $TestPlan -Project $Project -Collect $Collection

		if(-not $plan)
		{
            throw "Invalid or non-existent test plan $TestPlan"
		}

		if (-not $Project)
		{
			$Project = $plan.Project.Name
		}

		$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
		
		if(-not $tp)
		{
            throw "Invalid or non-existent team project $Project"
		}

        $tpc = $tp.Store.TeamProjectCollection
        $client = _GetRestClient "$ns.TestPlanHttpClient" -Collection $tpc

        if ($PSCmdlet.ShouldProcess("Plan $($plan.Id) ('$($plan.Name)')", "Remove test plan"))
        {
            $task = $client.DeleteTestPlanAsync($tp.Name, $plan.Id)

            $result = $task.Result; if($task.IsFaulted) { throw 'Error deleting test plan' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        }
    }
}
tools\TfsCmdlets\TfsCmdlets.Format.ps1xml
 
tools\TfsCmdlets\TfsCmdlets.psd1
#
# Module manifest for module 'TfsCmdlets'
#
# Generated by: Igor Abade V. Leite
#
# Generated on: 29/08/2019
#

@{

# Script module or binary module file associated with this manifest.
RootModule = 'TfsCmdlets.psm1'

# Version number of this module.
ModuleVersion = '2.0.0'

# Supported PSEditions
CompatiblePSEditions = 'Desktop'

# ID used to uniquely identify this module
GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'

# Author of this module
Author = 'Igor Abade V. Leite'

# Company or vendor of this module
CompanyName = 'Igor Abade V. Leite'

# Copyright statement for this module
Copyright = '(c) 2014 Igor Abade V. Leite. All rights reserved.'

# Description of the functionality provided by this module
Description = 'PowerShell Cmdlets for Azure DevOps and Team Foundation Server'

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.1'

# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
ScriptsToProcess = 'Startup.ps1'

# Type files (.ps1xml) to be loaded when importing this module
TypesToProcess = 'TfsCmdlets.Types.ps1xml'

# Format files (.ps1xml) to be loaded when importing this module
FormatsToProcess = 'TfsCmdlets.Format.ps1xml'

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('Admin\Admin.ps1', 
               'AreaIteration\Area\AreaIteration_Area.ps1', 
               'AreaIteration\Iteration\AreaIteration_Iteration.ps1', 
               'AreaIteration\AreaIteration.ps1', 
               'ConfigServer\ConfigServer.ps1', 
               'Connection\Connection.ps1', 
               'Git\Branch\Git_Branch.ps1', 
               'Git\Policy\Git_Policy.ps1', 
               'Git\Repository\Git_Repository.ps1', 
               'GlobalList\GlobalList.ps1', 
               'Helpers\Helpers.ps1', 
               'Identity\Identity.ps1', 
               'Organization\Organization.ps1', 
               'Policy\Policy.ps1', 
               'ProcessTemplate\ProcessTemplate.ps1', 
               'ServiceHook\ServiceHook.ps1', 
               'Team\TeamAdmin\Team_TeamAdmin.ps1', 
               'Team\Team.ps1', 
               'TeamProject\TeamProject.ps1', 
               'TeamProjectCollection\TeamProjectCollection.ps1', 
               'TestManagement\TestManagement.ps1', 
               'Work\Work.ps1', 
               'WorkItem\History\WorkItem_History.ps1', 
               'WorkItem\Linking\WorkItem_Linking.ps1', 
               'WorkItem\Query\WorkItem_Query.ps1', 
               'WorkItem\Tagging\WorkItem_Tagging.ps1', 
               'WorkItem\WorkItemType\WorkItem_WorkItemType.ps1', 
               'WorkItem\WorkItem.ps1', 
               'XamlBuild\XamlBuild.ps1', 
               '_Shared\_Shared.ps1')

# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Add-TfsTeamAdmin', 'Add-TfsWorkItemLink', 
               'Connect-TfsConfigurationServer', 'Connect-TfsTeamProject', 
               'Connect-TfsTeamProjectCollection', 'Copy-TfsTestPlan', 
               'Copy-TfsWorkItem', 'Disconnect-TfsConfigurationServer', 
               'Disconnect-TfsTeamProject', 'Disconnect-TfsTeamProjectCollection', 
               'Dismount-TfsTeamProjectCollection', 'Export-TfsGlobalList', 
               'Export-TfsProcessTemplate', 'Export-TfsWorkItemQuery', 
               'Export-TfsWorkItemType', 'Get-AzDevOrganization', 'Get-TfsArea', 
               'Get-TfsConfigurationServer', 
               'Get-TfsConfigurationServerConnectionString', 'Get-TfsCredential', 
               'Get-TfsGitBranch', 'Get-TfsGitBranchPolicy', 'Get-TfsGitRepository', 
               'Get-TfsGlobalList', 'Get-TfsIdentity', 'Get-TfsInstallationPath', 
               'Get-TfsIteration', 'Get-TfsPolicyType', 'Get-TfsProcessTemplate', 
               'Get-TfsRegisteredConfigurationServer', 
               'Get-TfsRegisteredTeamProjectCollection', 'Get-TfsRestClient', 
               'Get-TfsServiceHookConsumer', 
               'Get-TfsServiceHookNotificationHistory', 
               'Get-TfsServiceHookPublisher', 'Get-TfsServiceHookSubscription', 
               'Get-TfsTeam', 'Get-TfsTeamAdmin', 'Get-TfsTeamBacklog', 
               'Get-TfsTeamBoard', 'Get-TfsTeamBoardCardRuleSettings', 
               'Get-TfsTeamProject', 'Get-TfsTeamProjectCollection', 
               'Get-TfsTestPlan', 'Get-TfsWorkItem', 'Get-TfsWorkItemHistory', 
               'Get-TfsWorkItemLink', 'Get-TfsWorkItemLinkEndType', 
               'Get-TfsWorkItemQuery', 'Get-TfsWorkItemQueryFolder', 
               'Get-TfsWorkItemTag', 'Get-TfsWorkItemType', 'Import-TfsGlobalList', 
               'Import-TfsProcessTemplate', 'Import-TfsWorkItemType', 
               'Invoke-TfsRestApi', 'Mount-TfsTeamProjectCollection', 'Move-TfsArea', 
               'Move-TfsIteration', 'Move-TfsWorkItem', 'New-TfsArea', 
               'New-TfsGitRepository', 'New-TfsGlobalList', 'New-TfsIteration', 
               'New-TfsTeam', 'New-TfsTeamProject', 'New-TfsTeamProjectCollection', 
               'New-TfsWorkItem', 'New-TfsWorkItemQuery', 
               'New-TfsWorkItemQueryFolder', 'New-TfsWorkItemTag', 'Remove-TfsArea', 
               'Remove-TfsGitRepository', 'Remove-TfsGlobalList', 
               'Remove-TfsIteration', 'Remove-TfsTeam', 'Remove-TfsTeamAdmin', 
               'Remove-TfsTeamProject', 'Remove-TfsTeamProjectCollection', 
               'Remove-TfsTestPlan', 'Remove-TfsWorkItem', 'Remove-TfsWorkItemQuery', 
               'Remove-TfsWorkItemQueryFolder', 'Remove-TfsWorkItemTag', 
               'Rename-TfsArea', 'Rename-TfsGitRepository', 'Rename-TfsIteration', 
               'Rename-TfsTeam', 'Rename-TfsWorkItemQuery', 'Rename-TfsWorkItemTag', 
               'Set-TfsArea', 'Set-TfsGlobalList', 'Set-TfsIteration', 'Set-TfsTeam', 
               'Set-TfsTeamBoardCardRuleSettings', 'Set-TfsWorkItem', 
               'Set-TfsWorkItemBoardStatus', 'Set-TfsWorkItemQuery', 
               'Start-TfsIdentitySync', 'Start-TfsTeamProjectCollection', 
               'Start-TfsXamlBuild', 'Stop-TfsTeamProjectCollection', 'Test-TfsArea', 
               'Test-TfsIteration'

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()

# Variables to export from this module
# VariablesToExport = @()

# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = 'tfsrv', 'tftpc', 'tftp', 'gtftpc', 'gtftp'

# DSC resources to export from this module
# DscResourcesToExport = @()

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
FileList = 'chocolateyInstall.ps1', 'chocolateyUninstall.ps1', 'Prompt.ps1', 
               'Startup.ps1', 'TfsCmdlets.Format.ps1xml', 'TfsCmdlets.psd1', 
               'TfsCmdlets.psm1', 'TfsCmdlets.Types.ps1xml', 'TfsCmdletsShell.ico', 
               'Admin\Admin.ps1', 'Admin\Admin.psd1', 
               'AreaIteration\AreaIteration.ps1', 
               'AreaIteration\AreaIteration.psd1', 
               'AreaIteration\Area\AreaIteration_Area.ps1', 
               'AreaIteration\Iteration\AreaIteration_Iteration.ps1', 
               'ConfigServer\ConfigServer.ps1', 'ConfigServer\ConfigServer.psd1', 
               'Connection\Connection.ps1', 'Connection\Connection.psd1', 
               'Git\Branch\Git_Branch.ps1', 'Git\Policy\Git_Policy.ps1', 
               'Git\Repository\Git.psd1', 'Git\Repository\Git_Repository.ps1', 
               'GlobalList\GlobalList.ps1', 'GlobalList\GlobalList.psd1', 
               'Helpers\Helpers.ps1', 'Identity\Identity.ps1', 
               'Lib\Ben.Demystifier.dll', 'Lib\HtmlAgilityPack.dll', 
               'Lib\Microsoft.Azure.DevOps.Comments.WebApi.dll', 
               'Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.dll', 
               'Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll', 
               'Lib\Microsoft.IdentityModel.JsonWebTokens.dll', 
               'Lib\Microsoft.IdentityModel.Logging.dll', 
               'Lib\Microsoft.IdentityModel.Tokens.dll', 
               'Lib\Microsoft.TeamFoundation.Build.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Build.Common.dll', 
               'Lib\Microsoft.TeamFoundation.Build2.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Common.dll', 
               'Lib\Microsoft.TeamFoundation.Core.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.Dashboards.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.DeleteTeamProject.dll', 
               'Lib\Microsoft.TeamFoundation.Diff.dll', 
               'Lib\Microsoft.TeamFoundation.Discussion.Client.dll', 
               'Lib\Microsoft.TeamFoundation.DistributedTask.Common.Contracts.dll', 
               'Lib\Microsoft.TeamFoundation.Git.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Lab.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Lab.Common.dll', 
               'Lib\Microsoft.TeamFoundation.Lab.TestIntegration.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.dll', 
               'Lib\Microsoft.TeamFoundation.Policy.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.ProjectManagement.dll', 
               'Lib\Microsoft.TeamFoundation.SharePointReporting.Integration.dll', 
               'Lib\Microsoft.TeamFoundation.SourceControl.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.Test.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.TestImpact.Client.dll', 
               'Lib\Microsoft.TeamFoundation.TestManagement.Client.dll', 
               'Lib\Microsoft.TeamFoundation.TestManagement.Common.dll', 
               'Lib\Microsoft.TeamFoundation.TestManagement.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.VersionControl.Client.dll', 
               'Lib\Microsoft.TeamFoundation.VersionControl.Common.dll', 
               'Lib\Microsoft.TeamFoundation.VersionControl.Common.Integration.dll', 
               'Lib\Microsoft.TeamFoundation.Wiki.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.Work.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Common.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Process.WebApi.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll', 
               'Lib\Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll', 
               'Lib\Microsoft.VisualStudio.Services.Client.Interactive.dll', 
               'Lib\Microsoft.VisualStudio.Services.Common.dll', 
               'Lib\Microsoft.VisualStudio.Services.ServiceHooks.WebApi.dll', 
               'Lib\Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.dll', 
               'Lib\Microsoft.VisualStudio.Services.TestResults.WebApi.dll', 
               'Lib\Microsoft.VisualStudio.Services.WebApi.dll', 
               'Lib\Microsoft.WITDataStore32.dll', 
               'Lib\Microsoft.WITDataStore64.dll', 'Lib\Newtonsoft.Json.dll', 
               'Lib\System.IdentityModel.Tokens.Jwt.dll', 
               'Lib\System.Net.Http.Formatting.dll', 'Lib\System.Web.Http.dll', 
               'Lib\System.Web.Http.WebHost.dll', 'Lib\TfsCmdletsLib.dll', 
               'Organization\Organization.ps1', 'Policy\Policy.ps1', 
               'ProcessTemplate\ProcessTemplate.ps1', 
               'ProcessTemplate\ProcessTemplate.psd1', 
               'ServiceHook\ServiceHook.ps1', 'Team\Team.ps1', 'Team\Team.psd1', 
               'Team\TeamAdmin\Team_TeamAdmin.ps1', 'TeamProject\TeamProject.ps1', 
               'TeamProject\TeamProject.psd1', 
               'TeamProjectCollection\TeamProjectCollection.ps1', 
               'TeamProjectCollection\TeamProjectCollection.psd1', 
               'TestManagement\TestManagement.ps1', 'Work\Work.ps1', 
               'WorkItem\WorkItem.ps1', 'WorkItem\WorkItem.psd1', 
               'WorkItem\History\WorkItem_History.ps1', 
               'WorkItem\Linking\WorkItem_Linking.ps1', 
               'WorkItem\Query\WorkItemQuery.psd1', 
               'WorkItem\Query\WorkItem_Query.ps1', 
               'WorkItem\Tagging\WorkItem_Tagging.ps1', 
               'WorkItem\WorkItemType\WorkItem_WorkItemType.ps1', 
               'XamlBuild\XamlBuild.ps1', 'XamlBuild\XamlBuild.psd1', 
               '_cs\DesktopAssemblyResolver.cs', '_Shared\_Shared.ps1'

# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{

    #TfsClientVersion of this module
    TfsClientVersion = '16.156.0-preview'

    #Branch of this module
    Branch = 'releases/v2.0.0'

    #Version of this module
    Version = '2.0.0-beta.4+3'

    #Build of this module
    Build = '2.0.0-beta.4+1770.03'

    #Commit of this module
    Commit = 'c56ea2b401c1fa2ce31d72a4fc7c084535e913c4'

    PSData = @{

        # Tags applied to this module. These help with module discovery in online galleries.
        Tags = 'TfsCmdlets','TFS','VSTS','PowerShell','Azure','AzureDevOps','DevOps','ALM','TeamFoundationServer'

        # A URL to the license for this module.
        LicenseUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/LICENSE.md'

        # A URL to the main website for this project.
        ProjectUri = 'https://github.com/igoravl/tfscmdlets/'

        # A URL to an icon representing this module.
        IconUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/TfsCmdlets/resources/TfsCmdlets_Icon_32.png'

        # ReleaseNotes of this module
        ReleaseNotes = 'See https://github.com/igoravl/tfscmdlets/wiki/ReleaseNotes'

        # Prerelease string of this module
        Prerelease = 'beta0004'

        # Flag to indicate whether the module requires explicit user acceptance for install/update/save
        # RequireLicenseAcceptance = $false

        # External dependent modules of this module
        # ExternalModuleDependencies = @()

    } # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
HelpInfoURI = 'https://github.com/igoravl/tfscmdlets/wiki/'

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}

tools\TfsCmdlets\TfsCmdlets.psm1
_Log "Loading module TfsCmdlets from $PSScriptRoot"

# Initialize variables

$script:IsDesktop = ($PSEdition -ne 'Core')
$script:IsCore = -not $script:IsDesktop

# Configure assembly resolver

_RegisterAssemblyResolver

# Load essential assemblies

# TODO - Add strong names to loaded assemblies, to avoid loading 2010 assemblies from GAC
_ImportRequiredAssembly "*"

# _ImportRequiredAssembly 'Newtonsoft.Json'
# _ImportRequiredAssembly 'Microsoft.TeamFoundation.Client'
# _ImportRequiredAssembly 'Microsoft.VisualStudio.Services.WebApi'

# $runspace = [runspacefactory]::CreateRunspace()
# $pipeline = $runspace.CreatePipeline('_ImportRequiredAssembly "*"')
# $pipeline.Input.Close()
# $pipeline.InvokeAsync()

# # Load remaining assemblies asynchronously

# $libPath = Join-Path $PSScriptRoot 'lib'

# # $delegate = [Action[object]] {

# $assemblies = (Get-ChildItem "$libPath/*.dll" -Exclude 'Microsoft.WitDataStore*.*').BaseName
# Write-Verbose "Loading $($assemblies.Count) private assemblies"
        
# foreach($asm in $assemblies)
# {
#     Write-Verbose "Loading assembly $asm from folder $libPath"

#     try
#     {
#         Add-Type -Path (Join-Path $libPath "$asm.dll")
#     }
#     catch
#     {
#         Write-Warning ($_.Exception.LoaderExceptions | ConvertTo-Json -Depth 2)
#     }
# }
tools\TfsCmdlets\TfsCmdlets.Types.ps1xml
 
tools\TfsCmdlets\TfsCmdletsShell.ico
 
tools\TfsCmdlets\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
        }
    }
}
tools\TfsCmdlets\WorkItem\History\WorkItem_History.ps1
<#

.SYNOPSIS
    Gets the history of changes of a work item.

.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.

.EXAMPLE
    Get-TfsWorkItem -Filter '[System.WorkItemType] = "Task"' | Foreach-Object { Write-Output "WI $($_.Id): $($_.Title)"; Get-TfsWorkItemHistory -WorkItem $_ } 

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
    System.Int32
#>
Function Get-TfsWorkItemHistory
{
    [CmdletBinding()]
    [OutputType('PSCustomObject')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
        $latestRev = $wi.Revisions.Count - 1

        0..$latestRev | Foreach-Object {
            $rev = $wi.Revisions[$_]

            [PSCustomObject] @{
                Revision = $_ + 1;
                ChangedDate = $rev.Fields['System.ChangedDate'].Value
                ChangedBy = $rev.Fields['System.ChangedBy'].Value
                Changes = _GetChangedFields $wi $_
            }
        }
    }
}

Function _GetChangedFields([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem] $wi, [int] $rev)
{
    $result = @{}

    $wi.Revisions[$rev].Fields | Where-Object IsChangedInRevision -eq $true | Foreach-Object {
        $result[$_.ReferenceName] =  [PSCustomObject] @{
            NewValue = $_.Value;
            OriginalValue = $_.OriginalValue
        }
    }

    return $result
}
tools\TfsCmdlets\WorkItem\Linking\WorkItem_Linking.ps1
<#
.SYNOPSIS
Add a link between two work items

.DESCRIPTION
Add-TfsWorkItemLink permits the creation of a link between two work items. By linking work items and other objects, you can track related work, dependencies, and changes made over time. All links are defined with a specific link type. For example, you can use Parent/Child links to link work items to support a hierarchical tree structure. 

.PARAMETER SourceWorkItem
The first work item (the "leftmost") in a link relationship. For instance, in a Parent-Child relationship, that would be the Parent.

.PARAMETER TargetWorkItem
The second work item (the "rightmost") in a link relationship. For instance, in a Parent-Child relationship, that would be the Child.

.PARAMETER EndLinkType
Determines the kind of link to be created. This argument always refer to the Target (or "end") work item, in order to define directionality. In other words, to create a Parent-Child between a Source (parent) and a Target (child) work items, EndLinkType would be "Child". To learn more about the supported link types, see Get-TfsWorkItemLinkEndType.

.PARAMETER Comment
Add a comment to a link. Link comments can be seen in a work item form's "Links" tab.

.PARAMETER SkipSave
Leaves the source work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the source work item object to persist the newly created link.

.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

.EXAMPLE
Add-TfsWorkItemLink -SourceWorkItem 1 -TargetWorkItem 2 -EndLinkType Child
Creates a parent-child relationship between work items with IDs #1 (source, parent) and #2 (target, child)

.LINK
https://www.visualstudio.com/en-us/docs/work/track/link-work-items-support-traceability

.LINK
Get-TfsWorkItemLinkEndType
#>
Function Add-TfsWorkItemLink
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("Id")]
        [Alias("From")]
        [ValidateNotNull()]
        [object]
        $SourceWorkItem,

        [Parameter(Position=1, Mandatory=$true)]
        [Alias("To")]
        [ValidateNotNull()]
        [object]
        $TargetWorkItem,

        [Parameter(Position=2, Mandatory=$true)]
        [Alias("LinkType")]
        [Alias("Type")]
        [object]
        $EndLinkType,

        [Parameter()]
        [string]
        $Comment,

        [switch]
        $SkipSave,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $sourceWi = Get-TfsWorkItem -WorkItem $SourceWorkItem -Collection $Collection -Project $Project
        $targetWi = Get-TfsWorkItem -WorkItem $TargetWorkItem -Collection $Collection -Project $Project

        
        if ($EndLinkType -isnot [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd])
        {
            try
            {
                $EndLinkType = $sourceWi.Store.WorkItemLinkTypes.LinkTypeEnds[$EndLinkType]
            }
            catch
            {
                throw "Error retrieving work item link type $EndLinkType`: $_"
            }
        }

        $link = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLink' -ArgumentList $EndLinkType, $targetWi.Id
        $link.Comment = $Comment

        $i = $sourceWi.WorkItemLinks.Add($link)

        if (-not $SkipSave)
        {
            $sourceWi.Save()
        }

        return $sourceWi.WorkItemLinks[$i]        
    }
}
<#

.SYNOPSIS
    Gets the links of a work item.

.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-TfsWorkItemLink
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Link')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection

        if ($wi)
        {
            return $wi.Links
        }
    }
}
<#

.SYNOPSIS
    Gets the work item link end types of a team project collection.

.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
#>
Function Get-TfsWorkItemLinkEndType
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd')]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection

        return $tpc.WorkItemStore.WorkItemLinkTypes.LinkTypeEnds
    }
}
tools\TfsCmdlets\WorkItem\Query\WorkItemQuery.psd1
@{
    Description = 'This module contains cmdlets to query, edit and administer work items queries'

    ModuleVersion = '0.0.0'

    RootModule = 'WorkItemQuery.psm1'

    PrivateData = @{ 
        FriendlyName = 'Work Item Query'
    }
}
tools\TfsCmdlets\WorkItem\Query\WorkItem_Query.ps1
<#
.SYNOPSIS
Exports a saved work item query to XML.

.DESCRIPTION
Work item queries can be exported to XML files (.WIQ extension) in order to be shared and reused. Visual Studio Team Explorer has the ability to open and save WIQ files. Use this cmdlet to generate WIQ files compatible with the format supported by Team Explorer.

.PARAMETER Query
Name of the work item query to be exported. Wildcards are supported.

.PARAMETER Folder
Full path of the folder containing the query(ies) to be exported. Wildcards are supported.

.PARAMETER Destination
Path to the target directory where the exported work item query (WIQL file) will be saved. The original folder structure (as defined in TFS/VSTS) will be preserved.

.PARAMETER Encoding
XML encoding of the generated WIQL files. If omitted, defaults to UTF-8.

.PARAMETER Collection
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.TfsTeamProjectCollection
System.String
System.Uri

.EXAMPLE
Export-TfsWorkItemQuery 
.LINK
https://www.visualstudio.com/en-us/docs/work/reference/process-templates/define-work-item-query-process-template

.NOTES
For queries made against Team Services, the WIQL length must not exceed 32K characters. The system won't allow you to create or run queries that exceed that length.
#>
Function Export-TfsWorkItemQuery
{
    [CmdletBinding(DefaultParameterSetName='Export to output stream', SupportsShouldProcess=$true)]
    [OutputType('xml')]
    Param
    (
        [Parameter(ValueFromPipeline=$true, Position=0)]
        [SupportsWildcards()]
        [string] 
        $Query = "**/*",

        [Parameter()]
        [ValidateSet('Personal', 'Shared', 'Both')]
        [string]
        $Scope = 'Both',
    
		[Parameter(ParameterSetName="Export to file", Mandatory=$true)]
		[string]
		$Destination,
    
		[Parameter(ParameterSetName="Export to file")]
		[string]
		$Encoding = "UTF-8",
    
		[Parameter(ParameterSetName="Export to file")]
		[switch]
		$FlattenFolders,
    
		[Parameter(ParameterSetName="Export to file")]
		[switch]
		$Force,
    
		[Parameter(ParameterSetName="Export to output stream")]
		[switch]
		$AsXml,
    
        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if($PSCmdlet.ParameterSetName -eq 'Export to output stream')
        {
            $Encoding = 'UTF-16'
        }
        else
        {
            if (-not (Test-Path $Destination -PathType Container))
            {
                _Log "Destination path '$Destination' not found."

                if ($Force)
                {
                    _Log "-Force switch specified. Creating output directory."

                    if($PSCmdlet.ShouldProcess($Destination, 'Create output directory'))
                    {
                        New-Item $Destination -ItemType Directory | _Log
                    }
                }
                else
                {
                    throw "Invalid output path $Destination"
                }
            }
        }

		$queries = Get-TfsWorkItemQuery -Query $Query -Scope $Scope -Project $Project -Collection $Collection
        
        if (-not $queries)
        {
            throw "No work item queries match the specified `"$Query`" pattern supplied."
        }

		foreach($q in $queries)
		{
			$xml = [xml]@"
<?xml version="1.0" encoding="$Encoding"?>
<!-- Original Query Path: $($q.Path) -->
<WorkItemQuery Version="1">
  <TeamFoundationServer>$($q.Project.Store.TeamProjectCollection.Uri)</TeamFoundationServer>
  <TeamProject>$($q.Project.Name)</TeamProject>
  <Wiql><![CDATA[$($q.QueryText)]]></Wiql>
</WorkItemQuery>
"@
			if (-not $Destination)
			{
                if ($AsXml)
                {
    				Write-Output $xml
                }
                else 
                {
    				Write-Output $xml.OuterXml
                }
                continue
			}

            if ($FlattenFolders)
            {
                $queryPath = $q.Name
            }
            else
            {
                $queryPath = $q.Path.Substring($q.Path.IndexOf('/')+1)
            }

            $fileName = _GetAbsolutePath (Join-Path $Destination "$queryPath.wiql")

            _Log "Exporting query $($q.Name) to path '$fileName'"

            if((Test-Path $fileName) -and (-not $Force))
            {
                throw "File $fileName already exists. To overwrite an existing file, use the -Force switch"
            }

            if($PSCmdlet.ShouldProcess($fileName, "Save query '$($q.Name)'"))
            {
                $xml.Save($fileName)
            }
		}
	}
}
<#
.SYNOPSIS
Gets the definition of one or more work item saved queries.

.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.

.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-TfsWorkItemQuery
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
    Param
    (
        [Parameter(Position=0)]
        [ValidateNotNull()]
        [SupportsWildcards()]
        [Alias("Path")]
        [object]
        $Query = '**/*',

        [Parameter()]
        [ValidateSet('Personal', 'Shared', 'Both')]
        [string]
        $Scope = 'Both',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if($Query -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition2])
        {
            return $Query
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $qh = $tp.GetQueryHierarchy2($true)
        $qh.GetChildrenAsync().Wait()

        $rootFolders = ($qh.GetChildren() | Where-Object {$Scope -eq 'Both' -or $_.IsPersonal -eq ($Scope -eq 'Personal')})
        
        $rootFolders | _GetQueriesRecursively | Where-Object {($_.Path -like $Query) -or ($_.Name -like $Query) -or ($_.RelativePath -like $Query)} | Sort-Object ParentPath, Name

    }
}
<#
.SYNOPSIS
Gets the definition of one or more work item saved queries.

.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.

.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-TfsWorkItemQueryFolder
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder')]
    Param
    (
        [Parameter(Position=0)]
        [ValidateNotNull()]
        [SupportsWildcards()]
        [Alias("Path")]
        [object]
        $Folder = '**/*',

        [Parameter()]
        [ValidateSet('Personal', 'Shared', 'Both')]
        [string]
        $Scope = 'Both',

        [Parameter()]
        [timespan]
        $Timeout = '00:00:10',

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if($Folder -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2])
        {
            return $Folder
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $qh = $tp.GetQueryHierarchy2($false)
        $qh.GetChildrenAsync().Wait()

        $qh = $tp.GetQueryHierarchy2($true)
        $qh.GetChildrenAsync().Wait()

        $rootFolders = ($qh.GetChildren() | Where-Object {$Scope -eq 'Both' -or $_.IsPersonal -eq ($Scope -eq 'Personal')})
        
        $rootFolders | _GetQueryFoldersRecursively | Where-Object {($_.Path -like $Folder) -or ($_.Name -like $Folder)} | Sort-Object ParentPath, Name
    }
}
<#
.SYNOPSIS
Create a new work items query in the given Team Project.

.PARAMETER Query
Specifies the path of the new work item query.
When supplying a path, use a slash ("/") between the path segments. Leading and trailing slashes are optional.  The last segment in the path will be the query name.

.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
System.String
#>
Function New-TfsWorkItemQuery
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Name")]
        [Alias("Path")]
        [string]
        $Query,

        [Parameter()]
        [string]
        $Folder,

        [Parameter()]
        [ValidateSet('Personal', 'Shared')]
        [string]
        $Scope = 'Personal',

        [Parameter(Mandatory=$true)]
        [string]
        $Definition,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Force,

        [Parameter()]
        [switch]
        $SkipSave,

        [Parameter()]
        [switch]
        $Passthru
    )

    Begin
    {
        _RegisterQueryHelper
    }

    Process
    {
        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $qh = $tp.GetQueryHierarchy2($true)
        $qh.GetChildrenAsync().Wait()

        $rootFolder = ($qh.GetChildren() | Where-Object IsPersonal -eq ($Scope -eq 'Personal'))
        $fullPath = _NormalizeQueryPath -Path "$Folder/$Query" -RootFolder $rootFolder.Name -ProjectName $tp.Name
        $queryPath = $fullPath.Substring(0, $fullPath.LastIndexOf('/'))
        $queryName = $fullPath.Substring($fullPath.LastIndexOf('/')+1)
        $relativeQueryPath = $fullPath.Substring($rootFolder.Name.Length + $tp.Name.Length + 2)
        $relativeFolderPath = $queryPath.Substring($rootFolder.Name.Length + $tp.Name.Length + 2)

        if (-not $PSCmdlet.ShouldProcess($queryName, "Create work item query under folder '$queryPath'"))
        {
            return
        }

        _Log "New-TfsWorkItemQuery: Check if query '$relativeQueryPath' exists"

        $existingQuery = Get-TfsWorkItemQuery -Query $relativeQueryPath -Scope $Scope -Project $Project -Collection $Collection

        if ($existingQuery)
        {
            if (-not $Force)
            {
                throw "Work item query '$fullPath' already exists. To overwrite an existing query, use the -Force switch"
            }

            _Log "New-TfsWorkItemQuery: Existing query '$fullPath' will be overwritten"

            $existingQuery.Delete()
            $existingQuery.Save()
        }

        _Log "New-TfsWorkItemQuery: Creating query '$queryName' in folder '$queryPath'"

        $queryFolder = Get-TfsWorkItemQueryFolder -Folder $relativeFolderPath -Scope $Scope -Project $Project -Collection $Collection

        if (-not $queryFolder)
        {
            _Log "New-TfsWorkItemQuery: Destination folder $queryFolder not found"

            if ($Force)
            {
                _Log "New-TfsWorkItemQuery: -Force switch specified. Creating missing folder"
                $queryFolder = New-TfsWorkItemQueryFolder -Path $queryPath -Project $tp.Name -Passthru
            }
            else
            {
                throw "Invalid or non-existent work item query folder $queryPath."
            }
        }

        if ($Definition -match "select \*")
        {
            Write-Warning "New-TfsWorkItemQuery: Queries containing 'SELECT *' may not work in Visual Studio. Consider replacing * with a list of fields."
        }

        $q = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition2' -ArgumentList $queryName, $Definition, $queryFolder

        if (-not $SkipSave)
        {
            $q.Save()
        }
        else
        {
            _Log "New-TfsWorkItemQuery: -SkipSave switch specified. Newly created query will not be saved."
        }

        if ($Passthru -or $SkipSave)
        {
            return $q
        }
    }
}
<#
.SYNOPSIS
    Create a new work items query in the given Team Project.

.PARAMETER Path
    Specifies the path of the new work item query folder.
    When supplying a path, use a slash ("/") between the path segments. Leading and trailing backslashes are optional.  The last segment in the path will be the query name.

.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
    System.String
#>
Function New-TfsWorkItemQueryFolder
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [string]
        [Alias("Name")]
        [Alias("Path")]
        $Folder,

        [Parameter()]
        [ValidateSet('Personal', 'Shared')]
        [string]
        $Scope = 'Personal',

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [switch]
        $Passthru
    )

    Begin
    {
        _RegisterQueryHelper
    }

    Process
    {
        if($PSCmdlet.ShouldProcess($Folder, 'Create work item query folder'))
        {
            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
            #$tpc = $tp.Store.TeamProjectCollection
            #$store = $tp.Store

            if ($Scope -eq 'Shared')
            {
                $rootFolder = 'Shared Queries'
            }
            else
            {
                $rootFolder = 'My Queries'
            }

            $normalizedPath = _NormalizeQueryPath -Path $Folder -RootFolder $rootFolder -ProjectName $tp.Name

            _Log "New-TfsWorkItemQueryFolder: Creating folder '$Folder'"

            $queryFolder = [TfsCmdlets.QueryHelper]::CreateFolder($tp.QueryHierarchy, $normalizedPath)

            if ($Passthru)
            {
                return $queryFolder
            }
        }
    }
}
<#
.SYNOPSIS
    Deletes one or more work item queries from the specified Team Project..

.PARAMETER Query
	Specifies the path of a saved query. Wildcards are supported.

.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 Remove-TfsWorkItemQuery
{
    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateNotNull()] 
        [object]
        $Query,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $queries = Get-TfsWorkItemQuery -Query $Query -Project $Project -Collection $Collection

        foreach($q in $queries)
        {
            if ($PSCmdlet.ShouldProcess($q.Path, "Delete Query"))
            {
				$q.Delete()
            }
        }
    }
}
<#
.SYNOPSIS
    Deletes one or more work item queries from the specified Team Project..

.PARAMETER Query
	Specifies the path of a saved query. Wildcards are supported.

.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 Remove-TfsWorkItemQueryFolder
{
    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateNotNull()] 
        [object]
        $Folder,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [switch]
        $Force,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $folder = Get-TfsWorkItemQueryFolder -Folder $Folder -Project $Project -Collection $Collection

        if (($folder.Count -ne 0) -and (-not $Force))
        {
            throw "Folder is not empty. To delete a folder and its contents, use the -Force switch"
        }

        if ($PSCmdlet.ShouldProcess($folder, "Delete work item query folder"))
        {
            $folder.Delete()
            $folder.Project.Hierarchy.Save()
        }
    }
}
<#

.SYNOPSIS
    Changes the value of a property of an Area.

.PARAMETER Area
    Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned. 
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional. 
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)

.PARAMETER NewName
    Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-Tfsarea generates an error. To rename and move an item, use the Move-Tfsarea cmdlet.

.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 Rename-TfsWorkItemQuery
{
    [CmdletBinding(ConfirmImpact='Medium')]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateNotNull()] 
        [Alias("Path")]
        [object]
        $Query,

        [Parameter()]
        [string]
        $NewName,

        [Parameter()]
        [string]
        $Definition,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $result = Set-TfsWorkItemQuery -Query $Query -NewName $NewName -Project $Project -Collection $Collection -Passthru:$Passthru.IsPresent

        if ($Passthru)
        {
            return $result
        }
    }
}
<#

.SYNOPSIS
    Changes the value of a property of a work item query.

.PARAMETER Query
	Specifies the path of a work item saved query.

.PARAMETER NewName
    Specifies the new name of the query. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-TfsWorkItemQuery generates an error. To rename and move an item, use the Move-TfsWorkItemQuery cmdlet instead.

.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.QueryDefinition
    System.String
#>
Function Set-TfsWorkItemQuery
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateNotNull()] 
        [Alias("Path")]
        [object]
        $Query,

        [Parameter()]
        [string]
        $NewName,

        [Parameter()]
        [string]
        $Definition,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $q = Get-TfsWorkItemQuery -Query $Query -Project $Project -Collection $Collection

        if (-not $q)
        {
            throw "Invalid or non-existent work item query $queries"
        }

		if ($q.Count -ne 1)
		{
			throw "Ambiguous query name '$Query'. $($q.Count) queries were found matching the specified name/pattern:`n`n - " + ($q -join "`n - ")
		}

        if ($NewName -and $PSCmdlet.ShouldProcess($Query, "Rename work item query to '$NewName'"))
        {
            isDirty = $true
            $q.Name = $NewName
        }

        if ($Definition -and $PSCmdlet.ShouldProcess($Query, "Change work item query definition to '$Definition'"))
        {
            isDirty = $true
            $q.QueryText = $Definition
        }

        if ($isDirty)
        {
            $q.Project.QueryHierarchy.Save()
        }

		return $q
    }
}
Function _NormalizeQueryPath($Path, $RootFolder, $ProjectName)
{
    if([string]::IsNullOrWhiteSpace($Path))
    {
        return [string]::Empty
    }

    $newPath = [System.Text.RegularExpressions.Regex]::Replace($Path, '\\+|/{2,}', '/')

    if ($newPath.StartsWith("/"))
    {
        $newPath = $newPath.Substring(1)
    }

    if ($newPath.EndsWith('/'))
    {
        $newPath = $newPath.Substring(0, $newPath.Length-1)
    }

    $pattern = "($ProjectName/)?($RootFolder/)?(.+)"
    $match = [regex]::Match($newPath, $pattern)

    return "$ProjectName/$RootFolder/$($match.Groups[$match.Groups.Count-1])"
}

Function _RegisterQueryHelper()
{
    if (([System.Management.Automation.PSTypeName]'TfsCmdlets.QueryHelper').Type)
    {
        return
    }

    Add-Type -Language CSharp -ReferencedAssemblies 'Microsoft.TeamFoundation.WorkItemTracking.Client' `
        -TypeDefinition @'
${File:CSharp\QueryHelper.cs}
'@
}

Function _GetQueryFoldersRecursively
{
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]
        $Folder
    )
    
    Process
    {
        $Folder.GetChildrenAsync().Wait()

        $Folder.GetChildren() | Where-Object {$_ -Is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]} | ForEach-Object {
            Write-Output $_
            _GetQueryFoldersRecursively $_
        }
    }
}

Function _GetQueriesRecursively
{
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]
        $Folder
    )
    
    Process
    {
        $Folder.GetChildrenAsync().Wait()

        foreach($i in $Folder.GetChildren())
        {
            if ($i -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2])
            {
                _GetQueriesRecursively $i
            }
            else
            {
                Write-Output $i
            }
        }
    }
}

tools\TfsCmdlets\WorkItem\Tagging\WorkItem_Tagging.ps1
<#
.SYNOPSIS
    Gets one or more work item tags
.DESCRIPTION
    
.EXAMPLE

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
.OUTPUTS
    Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
.NOTES
#>
Function Get-TfsWorkItemTag
{

    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition')]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias('Name')]
        [object] 
        $Tag = '*',

        [Parameter()]
        [switch]
        $IncludeInactive,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
    }

    Process
    {
        if ($Tag -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition]) { _Log "Input item is of type Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition; returning input item immediately, without further processing."; return $Tag }

        $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.TaggingHttpClient' -Collection $tpc

        $task = $client.GetTagsAsync($tp.Guid, $IncludeInactive.IsPresent); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving work item tag '$Tag'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

        return $result | Where-Object Name -like $Tag | Add-Member -Name TeamProject -MemberType NoteProperty -Value $TP.Name -PassThru
    }
}
<#
.SYNOPSIS
    Gets one or more work item tags
.DESCRIPTION
    
.EXAMPLE

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
.OUTPUTS
    Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
.NOTES
#>
Function New-TfsWorkItemTag
{

    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition')]
    Param
    (
        [Parameter(Position=0,ValueFromPipeline=$true)]
        [Alias('Name')]
        [string] 
        $Tag,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
    }

    Process
    {
        $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

        if(-not $PSCmdlet.ShouldProcess($tp.Name, "Create work item tag '$Tag'"))
        {
            return
        }

        $client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc

        $task = $client.CreateTagAsync($tp.Guid, $Tag); $result = $task.Result; if($task.IsFaulted) { throw "Error creating work item tag '$Tag'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

        if($Passthru)
        {
            return $result
        }
    }
}
<#
.SYNOPSIS
    Deletes one or more work item tags
.DESCRIPTION
    
.EXAMPLE

.INPUTS
    Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
    System.String
.NOTES
#>
Function Remove-TfsWorkItemTag
{

    [CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Position=0,ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [Alias('Name')]
        [object] 
        $Tag = '*',

        [Parameter()]
        [switch]
        $IncludeInactive,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
    }

    Process
    {
        $tags = Get-TfsWorkItemTag -Tag $Tag -Project $Project -Collection $Collection

        foreach($t in $tags)
        {
            if($t.TeamProject) {$Project = $t.TeamProject}; $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

            if(-not $PSCmdlet.ShouldProcess($tp.Name, "Delete work item tag [$($t.Name)]"))
            {
                continue
            }

            $client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc

            $task = $client.DeleteTagAsync($tp.Guid, $t.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error deleting work item tag [$($t.Name)]'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
        }
    }
}
<#
.SYNOPSIS
    Deletes one or more work item tags
.DESCRIPTION
    
.EXAMPLE

.INPUTS
    Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
    System.String
.NOTES
#>
Function Rename-TfsWorkItemTag
{

    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Position=0,ValueFromPipeline=$true)]
        [Alias('Name')]
        [object] 
        $Tag,

        [Parameter(Position=1)]
        [string]
        $NewName,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
    }

    Process
    {
        $tags = Get-TfsWorkItemTag -Tag $Tag -Project $Project -Collection $Collection

        foreach($t in $tags)
        {
            if(-not $PSCmdlet.ShouldProcess($t.Name, "Rename work item tag to [$NewName]"))
            {
                continue
            }

            if($t.TeamProject) {$Project = $t.TeamProject}; $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.TaggingHttpClient' -Collection $tpc

            $task = $client.UpdateTagAsync($tp.Guid, $t.Id, $NewName, $t.Active); $result = $task.Result; if($task.IsFaulted) { throw "Error renaming work item tag [$($t.Name)]'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

            if($Passthru.IsPresent)
            {
                return $result
            }
        }
    }
}
tools\TfsCmdlets\WorkItem\WorkItem.ps1
<#
.SYNOPSIS
Creates a copy of a work item, optionally changing its type

.DESCRIPTION
Use this cmdlet to create a copy of a work item (using its latest saved state/revision data) that is of the specified work item type. By default, the copy retains the same type of the original work item, unless the Type argument is specified

.PARAMETER WorkItem
Specifies the work item to be copied. Can be either a work item ID or an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem

.PARAMETER Type
Specifies the new type for the copy of the original work item. It can be provided as either a string representing the work item type name (e.g. "Bug" or "Task") or an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType. When an instance of WorkItemType is provided, the team project from where that WorkItemType object was retrieved will be used to define where to copy the work item into, unless the Project argument is specified 

.PARAMETER IncludeAttachments
Includes attachments as part of the copy process. By default, only field values are copied

.PARAMETER IncludeLinks
Includes work item links as part of the copy process. By default, only field values are copied

.PARAMETER Project
Specified the team project where the work item will be copied into. If omitted, the copy will be created in the same team project of the source work item. The value provided to this argument takes precedence over both the source team project and the team project of an instance of WorkItemType provided to the Type argument

.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 SkipSave
Leaves the new work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the new work item object to persist the copy.

.PARAMETER Passthru
Returns the results of the command. It takes one of the following values: Original (returns the original work item), Copy (returns the newly created work item copy) or None.

.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
System.Int32

.EXAMPLE
Copy-TfsWorkItem -WorkItem 123
Creates (and returns) a copy of a work item with ID #123

.EXAMPLE
Get-TfsWorkItem -Filter '[System.WorkItemType] = "Bug"' | Copy-TfsWorkItem -Type Task
Retrieves all work item of Bug type and copy them as Tasks

.LINK
https://msdn.microsoft.com/en-us/library/ff738070.aspx
#>
Function Copy-TfsWorkItem
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object] 
        $Type,

        [Parameter()]
        [object] 
        $Project,

        [Parameter()]
        [switch] 
        $IncludeAttachments,

        [Parameter()]
        [switch] 
        $IncludeLinks,

        [Parameter()]
        [switch] 
        $SkipSave,

        [Parameter()]
		[ValidateSet('Original', 'Copy', 'None')]
        [string]
        $Passthru = 'Copy',

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
		$wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
		#$store = $wi.Store

		if($Type)
		{
			if ($Project)
			{
				$tp = $Project
			}
			else
			{
				$tp = $wi.Project
			}
			$witd = Get-TfsWorkItemType -Type $Type -Project $tp -Collection $wi.Store.TeamProjectCollection
		}
		else
		{
			$witd = $wi.Type
		}

		$flags = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::None

		if ($IncludeAttachments)
		{
			$flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyFiles
		}

		if ($IncludeLinks)
		{
			$flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyLinks
		}

		$copy = $wi.Copy($witd, $flags)

		if(-not $SkipSave)
		{
			$copy.Save()
		}

		if ($Passthru -eq 'Original')
		{
			return $wi
		}
		
		if($Passthru -eq 'Copy')
		{
			return $copy
		}
    }
}
<#

.SYNOPSIS
    Gets the contents of one or more work items.

.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-TfsWorkItem
{
    [CmdletBinding(DefaultParameterSetName="Query by text")]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by revision")]
        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by date")]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter(ParameterSetName="Query by revision")]
        [Alias("rev")]
        [int]
        $Revision,

        [Parameter(Mandatory=$true, ParameterSetName="Query by date")]
        [datetime]
        $AsOf,

        [Parameter(Mandatory=$true, ParameterSetName="Query by WIQL")]
        [Alias('WIQL')]
        [Alias('QueryText')]
        [Alias('SavedQuery')]
        [Alias('QueryPath')]
        [string]
        $Query,

        # [Parameter(Mandatory=$true, ParameterSetName="Query by filter")]
        # [string[]]
        # $Fields,

        [Parameter(Mandatory=$true, ParameterSetName="Query by filter")]
        [string]
        $Filter,

        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by text")]
        [string]
        $Text,

        [Parameter()]
        [hashtable]
        $Macros,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
    }

    Process
    {
        if ($Project)
        {
            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
            $tpc = $tp.Store.TeamProjectCollection
            $store = $tp.Store
        }
        else
        {
            $tpc = Get-TfsTeamProjectCollection -Collection $Collection
            $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
        }

        if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
        {
            if ((-Not $Revision) -and (-Not $AsOf))
            {
                return $WorkItem
            }
        }

        switch($PSCmdlet.ParameterSetName)
        {
            "Query by revision" {
                return _GetWorkItemByRevision $WorkItem $Revision $store
            }

            "Query by date" {
                return _GetWorkItemByDate $WorkItem $AsOf $store
            }

            "Query by text" {
                $localMacros = @{TfsQueryText=$Text}
                $Wiql = "SELECT * FROM WorkItems WHERE [System.Title] CONTAINS @TfsQueryText OR [System.Description] CONTAINS @TfsQueryText"
                return _GetWorkItemByWiql $Wiql $localMacros $tp $store 
            }

            "Query by filter" {
                $Wiql = "SELECT * FROM WorkItems WHERE $Filter"
                return _GetWorkItemByWiql $Wiql $Macros $tp $store 
            }

            "Query by WIQL" {
				_Log "Get-TfsWorkItem: Running query by WIQL. Query: $Query"
                return _GetWorkItemByWiql $Query $Macros $tp $store 
            }

            "Query by saved query" {
                return _GetWorkItemBySavedQuery $StoredQueryPath $Macros $tp $store 
            }
        }
    }
}

Function _GetWorkItemByRevision($WorkItem, $Revision, $store)
{
    if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
    {
        $ids = @($WorkItem.Id)
    }
    elseif ($WorkItem -is [int])
    {
        $ids = @($WorkItem)
    }
    elseif ($WorkItem -is [int[]])
    {
        $ids = $WorkItem
    }
    else
    {
        throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
    }

    if ($Revision -is [int] -and $Revision -gt 0)
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id, $Revision)
        }
    }
    elseif ($Revision -is [int[]])
    {
        if ($ids.Count -ne $Revision.Count)
        {
            throw "When supplying a list of IDs and Revisions, both must have the same number of elements"
        }
        for($i = 0; $i -le $ids.Count-1; $i++)
        {
            $store.GetWorkItem($ids[$i], $Revision[$i])
        }
    }
    else
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id)
        }
    }
}

Function _GetWorkItemByDate($WorkItem, $AsOf, $store)
{
    if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
    {
        $ids = @($WorkItem.Id)
    }
    elseif ($WorkItem -is [int])
    {
        $ids = @($WorkItem)
    }
    elseif ($WorkItem -is [int[]])
    {
        $ids = $WorkItem
    }
    else
    {
        throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
    }

    if ($AsOf -is [datetime[]])
    {
        if ($ids.Count -ne $AsOf.Count)
        {
            throw "When supplying a list of IDs and Changed Dates (AsOf), both must have the same number of elements"
        }
        for($i = 0; $i -le $ids.Count-1; $i++)
        {
            $store.GetWorkItem($ids[$i], $AsOf[$i])
        }
    }
    else
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id, $AsOf)
        }
    }
}

Function _GetWorkItemByWiql($QueryText, $Macros, $Project, $store)
{
	if ($QueryText -notlike 'select*')
	{
		$q = Get-TfsWorkItemQuery -Query $QueryText -Project $Project

		if (-not $q)
		{
			throw "Work item query '$QueryText' is invalid or non-existent."
		}

		if ($q.Count -gt 1)
		{
			throw "Ambiguous query name '$QueryText'. $($q.Count) queries were found matching the specified name/pattern:`n`n - " + ($q -join "`n - ")
		}

		$QueryText = $q.QueryText
	}

    if (-not $Macros -and (($QueryText -match "@project") -or ($QueryText -match "@me")))
    {
        $Macros = @{}
    }

    if ($QueryText -match "@project")
    {
		if (-not $Project)
		{
			$Project = Get-TfsTeamProject -Current
		}

        if (-not $Macros.ContainsKey("Project"))
        {
            $Macros["Project"] = $Project.Name
        }
    }

    if ($QueryText -match "@me")
    {
        $user = $null
        $store.TeamProjectCollection.GetAuthenticatedIdentity([ref] $user)
        $Macros["Me"] = $user.DisplayName
    }

	_Log "Get-TfsWorkItem: Running query $QueryText"

    $wis = $store.Query($QueryText, $Macros)

    # foreach($wi in $wis)
    # {
    #     if($Fields)
    #     {
    #         foreach($f in $Fields)
    #         {
    #             $wi | Add-Member -Name (_GetEncodedFieldName $f.ReferenceName) -MemberType ScriptProperty -Value `
    #                 {$f.Value}.GetNewClosure() `
    #                 {param($Value) $f.Value = $Value}.GetNewClosure()
    #         }
    #     }
    # }

    return $wis
}
Function Move-TfsWorkItem
{
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter(Mandatory=$true, Position=1)]
        [object]
        $Destination,

        [Parameter()]
        [object]
        $Area,

        [Parameter()]
        [object]
        $Iteration,

        [Parameter()]
        [object]
        $State,

        [Parameter()]
        [object]
        $History,

        [Parameter()]
        [object]
        $Collection
    )

    Begin
    {
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
        #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi'
    }

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection

        $targetTp = Get-TfsTeamProject -Project $Destination -Collection $Collection
        $tpc = $targetTp.Store.TeamProjectCollection
        
        if ($Area)
        {
            $targetArea = Get-TfsArea $Area -Project $targetTp

            if (-not $targetArea)
            {
                if ($PSCmdlet.ShouldProcess("Team Project '$($targetTp.Name)'", "Create area path '$Area'"))
                {
                    $targetArea = New-TfsArea $Area -Project $targetTp -Passthru
                }
            }

            _Log "Moving to area $($targetTp.Name)$($targetArea.RelativePath)"
        }
        else
        {
            _Log 'Area not informed. Moving to root iteration.'
            $targetArea = Get-TfsArea '' -Project $targetTp
        }

        if ($Iteration)
        {
            $targetIteration = Get-TfsIteration $Iteration -Project $targetTp

            if (-not $targetIteration)
            {
                if ($PSCmdlet.ShouldProcess("Team Project '$($targetTp.Name)'", "Create iteration path '$Iteration'"))
                {
                    $targetIteration = New-TfsIteration $Iteration -Project $targetTp -Passthru
                }
            }

            _Log "Moving to iteration $($targetTp.Name)$($targetIteration.RelativePath)"
        }
        else
        {
            _Log 'Iteration not informed. Moving to root iteration.'
            $targetIteration = Get-TfsIteration '' -Project $targetTp
        }

        $targetArea = "$($targetTp.Name)$($targetArea.RelativePath)"
        $targetIteration = "$($targetTp.Name)$($targetIteration.RelativePath)"

        $patch = _GetJsonPatchDocument @(
            @{
                Operation = 'Add';
                Path = '/fields/System.TeamProject';
                Value = $targetTp.Name
            },
            @{
                Operation = 'Add';
                Path = "/fields/System.AreaPath";
                Value = $targetArea
            },
            @{
                Operation = 'Add';
                Path = "/fields/System.IterationPath";
                Value = $targetIteration
            }
        )

        if ($State)
        {
            $patch.Add( @{
                Operation = 'Add';
                Path = '/fields/System.State';
                Value = $State
            })
        }

        if ($History)
        {
            $patch.Add( @{
                Operation = 'Add';
                Path = '/fields/System.History';
                Value = $History
            })
        }

        if ($PSCmdlet.ShouldProcess("$($wi.WorkItemType) $($wi.Id) ('$($wi.Title)')", 
            "Move work item to team project '$($targetTp.Name)' under area path " +
            "'$($targetArea)' and iteration path '$($targetIteration)'"))
        {
            $client = _GetRestClient 'Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItemTrackingHttpClient' -Collection $tpc
            $task = $client.UpdateWorkItemAsync($patch, $wi.Id)

            $result = $task.Result; if($task.IsFaulted) { throw 'Error moving work item' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }

            return Get-TfsWorkItem $result.Id -Collection $tpc
        }
    }
}
<#

.SYNOPSIS
    Creates a new work item in a team project.

.PARAMETER Type
    Represents the name of the work item type to create.

.PARAMETER Title
    Specifies a Title field of new work item type that will be created.

.PARAMETER Fields
    Specifies the fields that are changed and the new values to give to them.
    FieldN The name of a field to update.
    ValueN The value to set on the fieldN.
    [field1=value1[;field2=value2;...]

.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.

.EXAMPLE
    New-TfsWorkItem -Type Task -Title "Task 1" -Project "MyTeamProject"
    This example creates a new Work Item on Team Project "MyTeamProject".

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType
    System.String    
#>
Function New-TfsWorkItem
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
    Param
    (
        [Parameter(ValueFromPipeline=$true, Mandatory=$true, Position=0)]
        [object] 
        $Type,

        [Parameter(Position=1)]
        [string]
        $Title,

        [Parameter()]
        [hashtable]
        $Fields,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $SkipSave,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        if($PSCmdlet.ShouldProcess($Type, 'Create work item of specified type'))
        {
            $wit = Get-TfsWorkItemType -Type $Type -Project $Project -Collection $Collection

            $wi = $wit.NewWorkItem()

            if ($Title)
            {
                $wi.Title = $Title
            }

            foreach($field in $Fields)
            {
                $wi.Fields[$field.Key] = $field.Value
            }

            if (-not $SkipSave.IsPresent)
            {
                $wi.Save()
            }

            if ($Passthru)
            {
                return $wi
            }
        }
    }
}
<#

.SYNOPSIS
    Deletes a work item from a team project collection.

.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.WorkItem
    System.Int32
#>
Function Remove-TfsWorkItem
{
    [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $ids = @()

        foreach($wi in $WorkItem)
        {
            if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
            {
                $id = $WorkItem.Id
            }
            elseif ($WorkItem -is [int])
            {
                $id = $WorkItem
            }
            else
            {
                throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
            }

            if ($PSCmdlet.ShouldProcess("$($wi.WorkItemType) $id ('$($wi.Title)')", "Remove work item"))
            {
                $ids += $id
            }
        }

        if ($ids.Count -gt 0)
        {
            $tpc = Get-TfsTeamProjectCollection $Collection
            $store = $tpc.GetService([type] "Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore")

            $errors = $store.DestroyWorkItems([int[]] $ids)
        
            if ($errors -and ($errors.Count -gt 0))
            {
                $errors | Write-Error "Error $($_.Id): $($_.Exception.Message)"

                throw "Error destroying one or more work items"
            }
        }
    }
}
<#
.SYNOPSIS
Sets the contents of one or more work items.

.PARAMETER SkipSave
Leaves the work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the work item object to persist the changes.

.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.
#>
Function Set-TfsWorkItem
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(ValueFromPipeline=$true, Position=0)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter(Position=1)]
        [hashtable]
        $Fields,

        [Parameter()]
        [switch]
        $BypassRules,

        [Parameter()]
        [switch] 
        $SkipSave,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
        {
            $tpc = $WorkItem.Store.TeamProjectCollection
            $id = $WorkItem.Id
        }
        else
        {
            $tpc = Get-TfsTeamProjectCollection -Collection $Collection
            $id = (Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection).Id
        }

        if ($BypassRules)
        {
            $store = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore' -ArgumentList $tpc, [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStoreFlags]::BypassRules
        }
        else
        {
            $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
        }

        $wi = $store.GetWorkItem($id)

        $Fields = _FixAreaIterationValues -Fields $Fields -ProjectName $wi.Project.Name

        if($PSCmdlet.ShouldProcess("Set work item fields $($Fields.Keys -join ', ') to $($Fields.Values -join ', '), respectively"))
        {
            foreach($fldName in $Fields.Keys)
            {
                $wi.Fields[$fldName].Value = $Fields[$fldName]
            }

            if(-not $SkipSave)
            {
                $wi.Save()
            }
        }
        
        return $wi
    }
}
Function _FixAreaIterationValues([hashtable] $Fields, $ProjectName)
{
	if ($Fields.ContainsKey('System.AreaPath') -and ($Fields['System.AreaPath'] -notmatch "'\\?$ProjectName\\.+'"))
	{
		$Fields['System.AreaPath'] = ("$ProjectName\$($Fields['System.AreaPath'])" -replace '\\', '\')
	}

	if ($Fields.ContainsKey('System.IterationPath') -and ($Fields['System.IterationPath'] -notmatch "'\\?$ProjectName\\.+'"))
	{
		$Fields['System.IterationPath'] = ("$ProjectName\$($Fields['System.IterationPath'])" -replace '\\', '\')
	}
	
	return $Fields
}

Function _GetEscapedFieldName([string] $fieldName)
{
	$fieldName = $fieldName.Trim()

	if(-not $fieldName.StartsWith('['))
	{
		$fieldName = '[' + $fieldName
	}

	if(-not $fieldName.EndsWith(']'))
	{
		$fieldName += ']'
	}

	return $fieldName
}

Function _GetEncodedFieldName([string] $fieldName)
{
	return $fieldName.Trim(' ', '[', ']') -replace '[/W]', '_'
}
tools\TfsCmdlets\WorkItem\WorkItem.psd1
@{
    Description = 'This module contains cmdlets to query, edit and administer work items'

    ModuleVersion = '0.0.0'

    RootModule = 'WorkItem.psm1'

    PrivateData = @{ 
        FriendlyName = 'WorkItem'
    }
}
tools\TfsCmdlets\WorkItem\WorkItemType\WorkItem_WorkItemType.ps1
<#

.SYNOPSIS
    Exports a work item type definition from a team project to XML.

.PARAMETER Name
    Uses this parameter to filter for an specific Work Item Type.
    If suppress, cmdlet will return all Work Item Types on XML format.

.PARAMETER IncludeGlobalLists
     Exports the definitions of referenced global lists. If not specified, global list definitions are omitted.

.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 Export-TfsWorkItemType
{
    [CmdletBinding()]
    [OutputType('Xml')]
    Param
    (
        [Parameter()]
        [Alias('Name')]
        [SupportsWildcards()]
        [string] 
        $WorkItemType = "*",

        [Parameter()]
        [switch]
        $IncludeGlobalLists,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $types = Get-TfsWorkItemType -Name $WorkItemType -Project $Project -Collection $Collection

        foreach($type in $types)
        {
            $type.Export($IncludeGlobalLists)
        }
    }
}
<#

.SYNOPSIS
    Gets one or more Work Item Type definitions from a team project.

.PARAMETER Name
    Uses this parameter to filter for an specific Work Item Type.
    If suppress, cmdlet will show all Work Item Types.

.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.

.EXAMPLE
    Get-TfsWorkItemType -Name "Task" -Project "My Team Project"
    Get informations about Work Item Type "Task" of a team project name "My Team Project"

.EXAMPLE
    Get-TfsWorkItemType -Project "My Team Project"
    Get all Work Item Types of a team project name "My Team Project"

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>
Function Get-TfsWorkItemType
{
    [CmdletBinding()]
    [OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType')]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias("Name")]
        [object] 
        $Type = "*",

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($Type -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType])
        {
            return $Type
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection

        return $tp.WorkItemTypes | Where-Object Name -Like $Type
    }
}
<#

.SYNOPSIS
    Imports a work item type definition to a team project from XML.

.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
    System.Xml.XmlDocument
#>
Function Import-TfsWorkItemType
{
    [CmdletBinding(ConfirmImpact='Medium')]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [xml] 
        $Xml,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tp = Get-TfsTeamProject $Project $Collection
        $tp.WorkItemTypes.Import($Xml.OuterXml)
    }
}
tools\TfsCmdlets\XamlBuild\XamlBuild.ps1
<#
.SYNOPSIS
Queues a XAML Build.

.PARAMETER BuildDefinition
Build Definition Name that you want to queue.

.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.

.EXAMPLE
Start-TfsBuild -BuildDefinition "My Build Definition" -Project "MyTeamProject"
This example queue a Build Definition "My Build Definition" of Team Project "MyTeamProject".
#>
Function Start-TfsXamlBuild
{
    [CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [object] 
        $BuildDefinition,

        [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
        [object]
        [ValidateNotNull()]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.WorkItemTracking.Client.Project])})] 
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [string]
        [ValidateSet("LatestOnQueue", "LatestOnBuild", "Custom")]
        $GetOption = "LatestOnBuild",

        [Parameter()]
        [string]
        $GetVersion,

        [Parameter()]
        [string]
        $DropLocation,

        [Parameter()]
        [hashtable]
        $Parameters
    )

    Begin
    {
        if ($PSVersionTable.PSEdition -ne 'Desktop') { throw "This cmdlet requires does not work in PowerShell Core. It uses TFS Client Object Model, which only works in Windows PowerShell" }
    }

    Process
    {
        if($PSCmdlet.ShouldProcess($BuildDefinition, 'Queue new build'))
        {
            $tp = Get-TfsTeamProject $Project $Collection
            $tpc = $tp.Store.TeamProjectCollection

            $buildServer = $tpc.GetService([type]"Microsoft.TeamFoundation.Build.Client.IBuildServer")

            if ($BuildDefinition -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition])
            {
                $buildDef = $BuildDefinition
            }
            else
            {
                $buildDef = $buildServer.GetBuildDefinition($tp.Name, $BuildDefinition);
            }

            $req = $buildDef.CreateBuildRequest()
            $req.GetOption = [Microsoft.TeamFoundation.Build.Client.GetOption] $GetOption;

            if ($GetOption -eq "Custom")
            {
                $req.CustomGetVersion = $GetVersion
            }

            if ($DropLocation)
            {
                $req.DropLocation = $DropLocation
            }

            $buildServer.QueueBuild($req)
        }
    }
}
tools\TfsCmdlets\XamlBuild\XamlBuild.psd1
@{
    Description = 'This module contains cmdlets to maintain and administer XAML Builds and their infrastructure (controllers, agents etc.)'

    ModuleVersion = '0.0.0'

    RootModule = 'XamlBuild.psm1'

    PrivateData = @{ 
        FriendlyName = 'XAML Builds'
    }
}
tools\TfsCmdlets\_cs\DesktopAssemblyResolver.cs
using System;
using System.Collections.Generic;
using System.Reflection;

namespace TfsCmdlets
{
    public class AssemblyResolver
    {
        private static bool IsVerbose {get;set;}

        public static Dictionary<string, string> PrivateAssemblies {get;set;}

        public static readonly Dictionary<string, Assembly> LoadedAssemblies = new Dictionary<string, Assembly>();

        public static readonly Dictionary<string, object> LogEntries = new Dictionary<string, object>();

        public static void Register(Dictionary<string, string> privateAssemblies, bool verbose = false)
        {
            PrivateAssemblies = privateAssemblies;
            IsVerbose = verbose;

            AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
            {
                var assemblyName = e.Name.Split(',')[0];

                try
                {
                    if (!PrivateAssemblies.ContainsKey(assemblyName))
                    {
                        LogWarn("Skipping unknown assembly " + e.Name);
                        return null;
                    }

                    var asm = LoadAssembly(assemblyName);
                    LogInfo(assemblyName + " resolved as '" + asm.FullName + "'");

                    return asm;
                }
                catch(Exception ex)
                {
                    LogError(ex, assemblyName);
                    return null;
                }
            };
        }

        private static Assembly LoadAssembly(string assemblyName)
        {
            if(LoadedAssemblies.ContainsKey(assemblyName))
            {
                return LoadedAssemblies[assemblyName];
            }

            var assembly = Assembly.LoadFrom(PrivateAssemblies[assemblyName]);
            LoadedAssemblies.Add(assemblyName, assembly);

            return assembly;
        }

        private static void Log(string message, object data)
        {
            message = "[" + (LogEntries.Count+1).ToString("00000") + " - " + DateTime.Now.ToString("HH:mm:ss.ffff") + "] " + message;

            LogEntries.Add(message, data);
        }

        private static void LogInfo(string message)
        {
            if (!IsVerbose) return;

            Log("[INFO ] " + message, string.Empty);
        }

        private static void LogWarn(string message)
        {
            Log("[WARN ] " + message, string.Empty);
        }

        private static void LogError(Exception ex, string assemblyName = null)
        {
            Log("[ERROR] Loading assembly " + (assemblyName?? "(unknown)"), ex);
        }
    }
}
tools\TfsCmdlets\_Shared\_Shared.ps1
function _GetAbsolutePath 
{
    [CmdletBinding()]
    Param
    (
        $Path, 

        [switch]$CreateFolder
    )

    Process
    {
        $Path = [System.IO.Path]::Combine($pwd.Path, $Path)
        $Path = [System.IO.Path]::GetFullPath($Path)

        $folder = Split-Path $Path -Parent

        if ((-not (Test-Path $folder)) -and ($CreateFolder.IsPresent))
        {
            New-Item $folder -ItemType Directory -Force | _Log
        }

        return $Path
    }
}
Function _GetJsonPatchDocument
{
    [CmdletBinding()]
    [OutputType([Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument])]
    Param
    (
        $operations
    )
    
    $doc = New-Object 'Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument'

    foreach($op in $operations)
    {
        if ($op -is [Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation])
        {
            $doc.Add($op)
            continue
        }

        $jsonOp = New-Object 'Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation'
        $jsonOp.Operation = $op.Operation
        $jsonOp.Path = $op.Path
        $jsonOp.Value = $op.Value

        $doc.Add($jsonOp)
    }

    Write-Output -NoEnumerate $doc
}
Function _GetRegistryValue
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Path,

		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Value
	)

	Process
	{
		return Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value
	}
}
Function _GetRestClient
{
    [CmdletBinding()]
    [OutputType('Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $Type,

        [Parameter()]
        [object] 
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection

        return _InvokeGenericMethod -InputObject $tpc -MethodName GetClient -GenericType $Type
    }
}
Function _ImportRequiredAssembly($assemblyName)
{
    $libPath = (Join-Path $PSScriptRoot "../lib" -Resolve)

    if($assemblyName -eq '*')
    {
        $assemblies = (Get-ChildItem "$libPath/*.dll" -Exclude 'Microsoft.WitDataStore*.*','TfsCmdletsLib.dll').BaseName
        $assemblies += (Get-ChildItem "$libPath/TfsCmdletsLib.dll").BaseName
    }
    else
    {
        $assemblies = (Get-ChildItem "$libPath/$assemblyName.dll").BaseName
    }
    
    foreach($asm in $assemblies)
    {
        Write-Verbose "Loading assembly $asm from folder $libPath"

        try
        {
            Add-Type -Path (Join-Path $libPath "$asm.dll")
        }
        catch
        {
            Write-Error "Error loading assembly '$asm': $($_.Exception)"
        }
    }
}

Function _TestLoadedAssembly($assemblyName)
{
    try
    {
        $asm = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object FullName -like "$assemblyName,*"

        return $asm -is [System.Reflection.Assembly]
    }
    catch
    {
        return $false
    }
}
function _InvokeGenericMethod
{
    [CmdletBinding(DefaultParameterSetName = 'Instance')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Instance')]
        $InputObject,

        [Parameter(Mandatory = $true, ParameterSetName = 'Static')]
        [Type]
        $Type,

        [Parameter(Mandatory = $true)]
        [string]
        $MethodName,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $GenericType,

        [Object[]]
        $ArgumentList
    )

    process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            'Instance'
            {
                $_type  = $InputObject.GetType()
                $object = $InputObject
                $flags  = [System.Reflection.BindingFlags] 'Instance, Public'
            }

            'Static'
            {
                $_type  = $Type
                $object = $null
                $flags  = [System.Reflection.BindingFlags] 'Static, Public'
            }
        }

        if ($null -ne $ArgumentList)
        {
            $argList = $ArgumentList.Clone()
        }
        else
        {
            $argList = @()
        }

        $params = @{
            Type         = $_type
            BindingFlags = $flags
            MethodName   = $MethodName
            GenericType  = $GenericType
            ArgumentList = [ref]$argList
        }

        $method = _GetGenericMethod @params

        if ($null -eq $method)
        {
            Write-Error "No matching method was found"
            return
        }

        return [PSGenericMethods.MethodInvoker]::InvokeMethod($method, $object, $argList)
    } 
}

function _GetGenericMethod
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [Type]
        $Type,

        [Parameter(Mandatory = $true)]
        [string]
        $MethodName,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $GenericType,

        [ref]
        $ArgumentList,

        [System.Reflection.BindingFlags]
        $BindingFlags = [System.Reflection.BindingFlags]::Default,

        [switch]
        $WithCoercion
    )

    if ($null -eq $ArgumentList.Value)
    {
        $originalArgList = @()
    }
    else
    {
        $originalArgList = @($ArgumentList.Value)
    }

    foreach ($method in $Type.GetMethods($BindingFlags))
    {
        $argList = $originalArgList.Clone()

        if (-not $method.IsGenericMethod -or $method.Name -ne $MethodName) { continue }
        if ($GenericType.Count -ne $method.GetGenericArguments().Count) { continue }

        if (_TestGenericMethodParameters -MethodInfo $method -ArgumentList ([ref]$argList) -GenericType $GenericType -WithCoercion:$WithCoercion)
        {
            $ArgumentList.Value = $argList
            return $method.MakeGenericMethod($GenericType)
        }
    }

    if (-not $WithCoercion)
    {
        $null = $PSBoundParameters.Remove('WithCoercion')
        return _GetGenericMethod @PSBoundParameters -WithCoercion
    }

}

function _TestGenericMethodParameters
{
    [CmdletBinding()]
    param (
        [System.Reflection.MethodInfo] $MethodInfo,

        [ref]
        $ArgumentList,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $GenericType,

        [switch]
        $WithCoercion
    )

    if ($null -eq $ArgumentList.Value)
    {
        $argList = @()
    }
    else
    {
        $argList = @($ArgumentList.Value)
    }

    $parameterList = $MethodInfo.GetParameters()

    $arrayType = $null

    $_HasParamsArray = _HasParamsArray -ParameterList $parameterList

    if ($parameterList.Count -lt $argList.Count -and -not $_HasParamsArray)
    {
        return $false
    }

    $methodGenericType = $MethodInfo.GetGenericArguments()

    for ($i = 0; $i -lt $argList.Count; $i++)
    {
        $params = @{
            ArgumentList       = $argList
            ParameterList      = $ParameterList
            WithCoercion       = $WithCoercion
            RuntimeGenericType = $GenericType
            MethodGenericType  = $methodGenericType
            Index              = [ref]$i
            ArrayType          = [ref]$arrayType
        }

        $isOk = _TryMatchParameter @params

        if (-not $isOk) { return $false }
    }

    $defaults = New-Object System.Collections.ArrayList

    for ($i = $argList.Count; $i -lt $parameterList.Count; $i++)
    {
        if (-not $parameterList[$i].HasDefaultValue)  { return $false }
        $null = $defaults.Add($parameterList[$i].DefaultValue)
    }

    # When calling a method with a params array using MethodInfo, you have to pass in the array; the
    # params argument approach doesn't work.

    if ($_HasParamsArray)
    {
        $firstArrayIndex = $parameterList.Count - 1
        $lastArrayIndex = $argList.Count - 1

        $newArgList = $argList[0..$firstArrayIndex]
        $newArgList[$firstArrayIndex] = $argList[$firstArrayIndex..$lastArrayIndex] -as $arrayType
        $argList = $newArgList
    }

    $ArgumentList.Value = $argList + $defaults.ToArray()

    return $true

} 

function _TryMatchParameter
{
    param (
        [System.Reflection.ParameterInfo[]]
        $ParameterList,

        [object[]]
        $ArgumentList,

        [Type[]]
        $MethodGenericType,

        [Type[]]
        $RuntimeGenericType,

        [switch]
        $WithCoercion,

        [ref] $Index,
        [ref] $ArrayType
    )

    $params = @{
        ParameterType = $ParameterList[$Index.Value].ParameterType
        RuntimeType   = $RuntimeGenericType
        GenericType   = $MethodGenericType
    }

    $runtimeType = _ResolveRuntimeType @params

    if ($null -eq $runtimeType)
    {
        throw "Could not determine runtime type of parameter '$($ParameterList[$Index.Value].Name)'"
    }

    $_IsParamsArray = _IsParamsArray -ParameterInfo $ParameterList[$Index.Value]

    if ($_IsParamsArray)
    {
        $ArrayType.Value = $runtimeType
        $runtimeType     = $runtimeType.GetElementType()
    }

    do
    {
        $isOk = _TryMatchArgument @PSBoundParameters -RuntimeType $runtimeType
        if (-not $isOk) { return $false }

        if ($_IsParamsArray) { $Index.Value++ }
    }
    while ($_IsParamsArray -and $Index.Value -lt $ArgumentList.Count)

    return $true
}

function _TryMatchArgument
{
    param (
        [System.Reflection.ParameterInfo[]]
        $ParameterList,

        [object[]]
        $ArgumentList,

        [Type[]]
        $MethodGenericType,

        [Type[]]
        $RuntimeGenericType,

        [switch]
        $WithCoercion,

        [ref] $Index,
        [ref] $ArrayType,

        [Type] $RuntimeType
    )

    Function _GetType($object)
    {
        if ($null -eq $object) { return $null }
        return $object.GetType()
    }

    $argValue = $ArgumentList[$Index.Value]
    $argType = _GetType $argValue

    $isByRef = $RuntimeType.IsByRef
    if ($isByRef)
    {
        if ($ArgumentList[$Index.Value] -isnot [ref]) { return $false }

        $RuntimeType = $RuntimeType.GetElementType()
        $argValue = $argValue.Value
        $argType = _GetType $argValue
    }

    $isNullNullable = $false

    while ($RuntimeType.FullName -like 'System.Nullable``1*')
    {
        if ($null -eq $argValue)
        {
            $isNullNullable = $true
            break
        }

        $RuntimeType = $RuntimeType.GetGenericArguments()[0]
    }

    if ($isNullNullable) { continue }

    if ($null -eq $argValue)
    {
        return -not $RuntimeType.IsValueType
    }
    else
    {
        if ($argType -ne $RuntimeType)
        {
            $argValue = $argValue -as $RuntimeType
            if (-not $WithCoercion -or $null -eq $argValue)  { return $false }
        }

        if ($isByRef)
        {
            $ArgumentList[$Index.Value].Value = $argValue
        }
        else
        {
            $ArgumentList[$Index.Value] = $argValue
        }
    }

    return $true
}
function _HasParamsArray([System.Reflection.ParameterInfo[]] $ParameterList)
{
    return $ParameterList.Count -gt 0 -and (_IsParamsArray -ParameterInfo $ParameterList[-1])
}

function _IsParamsArray([System.Reflection.ParameterInfo] $ParameterInfo)
{
    return @($ParameterInfo.GetCustomAttributes([System.ParamArrayAttribute], $true)).Count -gt 0
}

function _ResolveRuntimeType
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [Type]
        $ParameterType,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $RuntimeType,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $GenericType
    )

    if ($ParameterType.IsByRef)
    {
        $elementType = _ResolveRuntimeType -ParameterType $ParameterType.GetElementType() -RuntimeType $RuntimeType -GenericType $GenericType
        return $elementType.MakeByRefType()
    }
    elseif ($ParameterType.IsGenericParameter)
    {
        for ($i = 0; $i -lt $GenericType.Count; $i++)
        {
            if ($ParameterType -eq $GenericType[$i])
            {
                return $RuntimeType[$i]
            }
        }
    }
    elseif ($ParameterType.IsArray)
    {
        $arrayType = $ParameterType
        $elementType = _ResolveRuntimeType -ParameterType $ParameterType.GetElementType() -RuntimeType $RuntimeType -GenericType $GenericType

        if ($ParameterType.GetElementType().IsGenericParameter)
        {
            $arrayRank = $arrayType.GetArrayRank()

            if ($arrayRank -eq 1)
            {
                $arrayType = $elementType.MakeArrayType()
            }
            else
            {
                $arrayType = $elementType.MakeArrayType($arrayRank)
            }
        }

        return $arrayType
    }
    elseif ($ParameterType.ContainsGenericParameters)
    {
        $genericArguments = $ParameterType.GetGenericArguments()
        $runtimeArguments = New-Object System.Collections.ArrayList

        foreach ($argument in $genericArguments)
        {
            $null = $runtimeArguments.Add((_ResolveRuntimeType -ParameterType $argument -RuntimeType $RuntimeType -GenericType $GenericType))
        }

        $definition = $ParameterType
        if (-not $definition.IsGenericTypeDefinition)
        {
            $definition = $definition.GetGenericTypeDefinition()
        }

        return $definition.MakeGenericType($runtimeArguments.ToArray())
    }
    else
    {
        return $ParameterType
    }
}

if (-not ([System.Management.Automation.PSTypeName]'PSGenericMethods.MethodInvoker').Type)
{
	Add-Type -ErrorAction SilentlyContinue -TypeDefinition @'
    namespace PSGenericMethods
    {
        using System;
        using System.Reflection;
        using System.Management.Automation;

        public static class MethodInvoker
        {
            public static object InvokeMethod(MethodInfo method, object target, object[] arguments)
            {
                if (method == null) { throw new ArgumentNullException("method"); }

                object[] args = null;

                if (arguments != null)
                {
                    args = (object[])arguments.Clone();
                    for (int i = 0; i < args.Length; i++)
                    {
                        PSObject pso = args[i] as PSObject;
                        if (pso != null)
                        {
                            args[i] = pso.BaseObject;
                        }

                        PSReference psref = args[i] as PSReference;

                        if (psref != null)
                        {
                            args[i] = psref.Value;
                        }
                    }
                }

                object result = method.Invoke(target, args);

                for (int i = 0; i < arguments.Length; i++)
                {
                    PSReference psref = arguments[i] as PSReference;

                    if (psref != null)
                    {
                        psref.Value = args[i];
                    }
                }

                return result;
            }
        }
    }
'@
}
Function _InvokeScriptBlock($ScriptBlock, $Computer, $Credentials, $ArgumentList)
{
	if (-not $Computer)
	{
		return Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $ArgumentList
	}
	elseif ($Computer -is [System.Management.Automation.Runspaces.PSSession])
	{
		return Invoke-Command -ScriptBlock $scriptBlock -Session $Computer -ArgumentList $ArgumentList
	}

	return Invoke-Command -ScriptBlock $scriptBlock -ComputerName $Computer -Credential $Credential -ArgumentList $ArgumentList
}
Function _Log
{
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Message,

        [Parameter()]
        [string]
        $Caller,

        [Parameter()]
        [switch]
        $Force
    )

    if(($VerbosePreference -ne 'Continue') -and (-not $Force.IsPresent))
    {
        # No verbose set. Exit now to avoid expensive/unnecessary calls to Get-PSCallStack and Write-Verbose
        return
    }

    if(-not $Caller)
    {
        $caller = _GetLogCallStack
    }

    Write-Verbose "[$([DateTime]::Now.ToString('HH:mm:ss.ffff'))] [$caller] $Message"
}

Function _GetLogCallStack
{
    $cs = [System.Collections.Stack]::new()

    foreach($frame in Get-PSCallStack)
    {
        if ($frame.Command -in @('_Log', '_GetLogCallStack', '', $null))
        {
            continue
        }
        
        $cs.Push($frame.Command.Trim('_'))

        if ($frame.Command -like '*-*')
        {
            break
        }
    }

    return $cs.ToArray() -join ':'
}

Function _DumpObj
{
    Param
    (
        [Parameter(ValueFromPipeline=$true, Position=0)]
        [object]
        $InputObject,

        [Parameter()]
        $Depth = 5
    )

    return $InputObject | ConvertTo-Json -Depth $Depth -Compress
}
function _NewDictionary
{
    #requires -Version 2.0

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position=1)]
        [ValidateNotNull()]
        [hashtable]
        $InputObject,

        [Parameter(Position=0)]
        [ValidateCount(2,2)]
        [Type[]]
        $Types = @([string], [object])
    )

    process
    {
        $KeyType = $Types[0]
        $ValueType = $Types[1]

        $outputObject = New-Object "System.Collections.Generic.Dictionary[[$($KeyType.FullName)],[$($ValueType.FullName)]]"

        foreach ($entry in $InputObject.GetEnumerator())
        {
            $newKey = $entry.Key -as $KeyType
            
            if ($null -eq $newKey)
            {
                throw 'Could not convert key "{0}" of type "{1}" to type "{2}"' -f
                      $entry.Key,
                      $entry.Key.GetType().FullName,
                      $KeyType.FullName
            }
            elseif ($outputObject.ContainsKey($newKey))
            {
                throw "Duplicate key `"$newKey`" detected in input object."
            }

            $outputObject.Add($newKey, $entry.Value -as $ValueType)
        }

        Write-Output $outputObject
    }
}
Function _NewScriptBlock($EntryPoint, [string[]]$Dependency)
{
	$entryPoint = (Get-Item "function:$EntryPoint").Definition.Trim()
	$paramSection = $entryPoint.Substring(0, $entryPoint.IndexOf("`n"))
	$bodySection = $entryPoint.Substring($paramSection.Length) + "`n`n"
	
	$body = $paramSection

	foreach($depFn in $Dependency)
	{
		$f = Get-Item "function:$depFn"

		$body += "Function $f `n{`n"
		$body += $f.Definition 
		$body += "`n}`n`n"
	}

	$body += $bodySection

	return [scriptblock]::Create($body)
}
Function _RegisterAssemblyResolver
{
    if ($TfsCmdletsDebugStartup)
    {
        Write-Host "Entering TfsCmdlets startup debug mode" -ForegroundColor DarkYellow
    
        # For some reason, setting VerbosePreference here breaks the script. Using Set-Alias to work around it
        Set-Alias Write-Verbose Write-Host -Option Private
    }
    
    Write-Verbose 'Registering custom Assembly Resolver'

    if (-not ([System.Management.Automation.PSTypeName]'TfsCmdlets.AssemblyResolver').Type)
    {
        Write-Verbose "Compiling $PSEdition version of the assembly resolver"

        $sourcePath = (Join-Path $PSScriptRoot "../_cs/$($PSEdition)AssemblyResolver.cs" -Resolve)
        $sourceText = (Get-Content $sourcePath -Raw)

        Add-Type -TypeDefinition $sourceText -Language CSharp

        $libPath = (Join-Path $PSScriptRoot '../Lib' -Resolve)
        $assemblies = [System.Collections.Generic.Dictionary[string,string]]::new()

        Write-Verbose "Enumerating assemblies from $libPath"

        foreach($f in (Get-ChildItem $libPath -Filter '*.dll'))
        {
            Write-Verbose "Adding $f to list of private assemblies"
            $assemblies.Add($f.BaseName, $f.FullName)
        }

        Write-Verbose 'Calling AssemblyResolver.Register()'
        [TfsCmdlets.AssemblyResolver]::Register($assemblies, [bool]($TfsCmdletsDebugStartup))
    }
    else
    {
        Write-Verbose 'Custom Assembly Resolver already registered; skipping'
    }
}
Function _TestGuid([string]$guid)
{
    if([string]::IsNullOrEmpty($guid))
    {
        return $false
    }

    $parsedGuid = [guid]::Empty

    return [guid]::TryParse($guid, [ref] $parsedGuid)
}
Function _TestRegistryValue
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Path,

		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Value
	)

	Process
	{
		try
		{
			_GetRegistryValue -Path $Path -Value $Value | Out-Null
			return $true
		}
		finally {}

		return $false

	}
}
Function _Throw
{
    Param
    (
        [Parameter(ValueFromPipeline=$true, Position=0)]
        [object]
        $Message,

        [Parameter(Position=1)]
        [object]
        $Exception
    )

    $caller = (Get-PSCallStack)[1].Command

    if ($Exception)
    {
        $Message += "`r`rAdditional error information: $Exception"
    }

    throw "[$caller] $Message"
}

Log in or click on link to see number of positives.

In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).

Chocolatey Pro provides runtime protection from possible malware.

Add to Builder Version Downloads Last Updated Status
TfsCmdlets 2.8.2 36 Wednesday, July 24, 2024 Approved
TfsCmdlets 2.8.1 26 Tuesday, July 16, 2024 Approved
TfsCmdlets 2.8.0 33 Tuesday, July 9, 2024 Approved
TfsCmdlets 2.7.1 26 Wednesday, July 3, 2024 Approved
TfsCmdlets 2.6.1 46 Wednesday, May 15, 2024 Approved
TfsCmdlets 2.6.0 248 Saturday, October 1, 2022 Approved
TfsCmdlets 2.5.1 62 Monday, August 22, 2022 Approved
TfsCmdlets 2.5.0 60 Wednesday, August 3, 2022 Approved
TfsCmdlets 2.4.1 71 Thursday, July 21, 2022 Approved
TfsCmdlets 2.4.0 93 Monday, May 23, 2022 Approved
TfsCmdlets 2.3.2 63 Wednesday, May 18, 2022 Approved
TfsCmdlets 2.3.1 74 Saturday, April 9, 2022 Approved
TfsCmdlets 2.3.0 71 Sunday, April 3, 2022 Approved
TfsCmdlets 2.2.1 76 Friday, February 11, 2022 Approved
TfsCmdlets 2.2.0 66 Saturday, February 5, 2022 Approved
TfsCmdlets 2.1.4 94 Tuesday, November 30, 2021 Approved
TfsCmdlets 2.1.3 71 Thursday, November 25, 2021 Approved
TfsCmdlets 2.1.2 87 Friday, September 10, 2021 Approved
TfsCmdlets 2.1.1 80 Wednesday, September 8, 2021 Approved
TfsCmdlets 2.0.0 87 Tuesday, August 3, 2021 Approved
TfsCmdlets 2.0.0-rc0005 88 Sunday, April 18, 2021 Exempted
TfsCmdlets 2.0.0-rc0004 88 Monday, April 5, 2021 Exempted
TfsCmdlets 2.0.0-rc0003 78 Friday, February 19, 2021 Exempted
TfsCmdlets 2.0.0-rc0002 87 Tuesday, December 1, 2020 Exempted
TfsCmdlets 2.0.0-beta0015 89 Tuesday, July 21, 2020 Exempted
TfsCmdlets 2.0.0-beta0014 69 Sunday, July 19, 2020 Exempted
TfsCmdlets 2.0.0-beta0013 68 Saturday, July 18, 2020 Exempted
TfsCmdlets 2.0.0-beta0010 162 Thursday, September 12, 2019 Exempted
TfsCmdlets 2.0.0-beta0009 97 Tuesday, September 10, 2019 Exempted
TfsCmdlets 2.0.0-beta0008 109 Friday, September 6, 2019 Exempted
TfsCmdlets 2.0.0-beta0004 119 Thursday, August 29, 2019 Exempted
TfsCmdlets 1.0.0.894-beta1 392 Thursday, April 6, 2017 Exempted
TfsCmdlets 1.0.0-alpha9 333 Saturday, December 24, 2016 Exempted
TfsCmdlets 1.0.0-alpha7 299 Thursday, October 22, 2015 Exempted
TfsCmdlets 1.0.0-alpha6 281 Thursday, October 22, 2015 Exempted
TfsCmdlets 1.0.0-alpha5 259 Thursday, September 10, 2015 Exempted
TfsCmdlets 1.0.0-alpha4 248 Friday, September 4, 2015 Exempted
TfsCmdlets 1.0.0-alpha3 314 Thursday, September 3, 2015 Exempted
TfsCmdlets 1.0.0-alpha1 313 Friday, July 31, 2015 Exempted

This package has no dependencies.

Discussion for the TfsCmdlets Package

Ground Rules:

  • This discussion is only about TfsCmdlets and the TfsCmdlets package. If you have feedback for Chocolatey, please contact the Google Group.
  • This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
  • The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
  • Tell us what you love about the package or TfsCmdlets, or tell us what needs improvement.
  • Share your experiences with the package, or extra configuration or gotchas that you've found.
  • If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.
comments powered by Disqus