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:

4,209

Downloads of v 1.0.0-alpha9:

321

Last Update:

24 Dec 2016

Package Maintainer(s):

Software Author(s):

  • Igor Abade V. Leite

Tags:

tfscmdlets tfs powershell

TfsCmdlets

This is a prerelease version of TfsCmdlets.

  • 1
  • 2
  • 3

1.0.0-alpha9 | Updated: 24 Dec 2016

Downloads:

4,209

Downloads of v 1.0.0-alpha9:

321

Maintainer(s):

Software Author(s):

  • Igor Abade V. Leite

TfsCmdlets 1.0.0-alpha9

This is a prerelease version of TfsCmdlets.

  • 1
  • 2
  • 3

All Checks are Passing

3 Passing Tests


Validation Testing Passed


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="'1.0.0-alpha9'" --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="'1.0.0-alpha9'" --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: '1.0.0-alpha9'
    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  '1.0.0-alpha9'
  options  '--prerelease'
end

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


cChocoPackageInstaller tfscmdlets
{
    Name        = "tfscmdlets"
    Version     = "1.0.0-alpha9"
    Source      = "INTERNAL REPO URL"
    chocoParams = "--prerelease"
}

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


package { 'tfscmdlets':
  ensure          => '1.0.0-alpha9',
  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 TFS and VSTS


tools\Admin\Admin.psm1
Function Test-RegistryValue
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Path,

		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Value
	)

	Process
	{
		try
		{
			Get-RegistryValue -Path $Path -Value $Value | Out-Null
			return $true
		}
		catch {}

		return $false

	}
}

Function Get-RegistryValue
{
	Param
	(
		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Path,

		[Parameter(Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		$Value
	)

	Process
	{
		return Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value
	}
}
Function New-ScriptBlock($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 Invoke-ScriptBlock($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
}
<#
.SYNOPSIS
    Gets the installation path of a given Team Foundation Server component.

.PARAMETER Computer
    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. If omitted, defaults to the local machine where the script is being run.
    Optionally, a System.Management.Automation.Runspaces.PSSession object pointing to a previously opened PowerShell Remote session can be provided instead.

.PARAMETER Component
    Indicates the TFS component whose installation path is being searched for. For the main TFS installation directory, use 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.
#>
Function Get-TfsInstallationPath
{
	[CmdletBinding()]
	[OutputType([string])]
	Param
	(
		[Parameter()]
		[object]
		[Alias('Session')]
		$Computer,

		[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 = New-ScriptBlock -EntryPoint '_GetInstallationPath' -Dependency 'Test-RegistryValue', 'Get-RegistryValue'

		return Invoke-ScriptBlock -ScriptBlock $scriptBlock -Computer $Computer -Credential $Credential -ArgumentList $Version, $Component
	}
}


Function _GetInstallationPath($Version, $Component)
{
	$rootKeyPath = "HKLM:\Software\Microsoft\TeamFoundationServer\$Version"

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

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

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

	return Get-RegistryValue -Path $componentPath -Value 'InstallPath'
}

tools\AreaIteration\AreaIteration.psm1
Function _GetCssNodes($Node, $Scope, $Project, $Collection)
{
    Process
	{
		if ($Node -is [Microsoft.TeamFoundation.Server.NodeInfo])
		{
			return $Node
		}

		$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
		$tpc = $tp.Store.TeamProjectCollection
		$projectName = $tp.Name
        $cssService = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService")
        
		if ($node -is [uri])
		{
			return $cssService.GetNode($node)
		}

		$rootPath = _NormalizePath "$projectName\$Scope"
		$fullPath = _NormalizePath "$rootPath\$Node"

		$rootNodeUri = $cssService.GetNodeFromPath("$rootPath").Uri
		$rootElement = $cssService.GetNodesXml(@($rootNodeUri), $true)
		
		$nodePaths = $rootElement.SelectNodes('//@Path') | Select -ExpandProperty '#text'
		$matchingPaths = $nodePaths | ? { $_ -like $fullPath }

        return $matchingPaths | % { $cssService.GetNodeFromPath($_) }
    }
}

Function _DeleteCssNode($Node, $Scope, $MoveToNode, $Project, $Collection)
{
    Process
	{
		$newNode = _GetCssNodes -Node $MoveToNode -Scope $Scope -Project $Project -Collection $Collection
		$cssService = _GetCssService -Project $Project -Collection $Collection

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

Function _NewCssNode ($Project, $Path, $Scope, $Collection, $StartDate, $FinishDate)
{
	Process
	{
		$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
		$tpc = $tp.Store.TeamProjectCollection
		$projectName = $tp.Name
        $cssService = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService")

        try
        {
			$fullPath = _NormalizePath "$projectName\$Scope\$Path"
			$parentPath = Split-Path $fullPath -Parent
			$nodeName = Split-Path $fullPath -Leaf
            $parentNode = $cssService.GetNodeFromPath($parentPath)
        }
        catch
        {
            $parentNode = _NewCssNode -Project $Project -Path $parentPath -Scope $Scope -Collection $Collection
        }

		if ($StartDate -or $FinishDate)
		{
			$cssService = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService4")
			$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri, $StartDate, $FinishDate)
		}
		else
		{
			$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri)
		}

        return $cssService.GetNode($nodeUri)
    }
}

Function _NormalizePath($Path)
{
	if([string]::IsNullOrWhiteSpace($Path))
	{
		return [string]::Empty
	}

	$newPath = [System.Text.RegularExpressions.Regex]::Replace($Path, '\\{2,}', '\')

	if (-not $newPath.StartsWith("\"))
	{
		$newPath = "\$newPath"
	}

	if ($newPath.EndsWith("\"))
	{
		$newPath = $newPath.Substring(0, $newPath.Length-1)
	}

	return $newPath
}

Function _GetCssService($Project, $Collection, $Version)
{
	$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
	$tpc = $tp.Store.TeamProjectCollection
	$projectName = $tp.Name

    return $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService$Version")
}
<#
.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
#>
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
    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.

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

#>
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 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()]
    [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
    )

    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)

        return $cssService.GetNode($node.Uri)
    }
}
<#
.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.

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 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()]
    [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
    )

    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)

        return $cssService.GetNode($node.Uri)
    }
}
<#
.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()]
    [OutputType([Microsoft.TeamFoundation.Server.NodeInfo])]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Path")]
        [string]
        $Area,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        return _NewCssNode -Path $Area -Scope Area -Project $Project -Collection $Collection
    }
}
<#
.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()]
    [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
    )

    Process
    {
        return _NewCssNode -Path $Iteration -Scope Iteration -Project $Project -Collection $Collection -StartDate $StartDate -FinishDate $FinishDate
    }
}
<#
.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 -Property Path -Descending

        foreach($i in $Areas)
        {
            if ($PSCmdlet.ShouldProcess($i.RelativePath, "Delete Area"))
            {
                $projectName = $i.Path.Split("\")[1]
                _DeleteCssNode -Node $i -MoveToNode $MoveTo -Scope Area -Project $projectName -Collection $Collection
            }
        }
    }
}
<#
.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.

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 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)]
        [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 -Property Path -Descending

        foreach($i in $iterations)
        {
            if ($PSCmdlet.ShouldProcess($i.RelativePath, "Delete Iteration"))
            {
                $projectName = $i.Path.Split("\")[1]
                _DeleteCssNode -Node $i -MoveToNode $MoveTo -Scope Iteration -Project $Project -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()]
    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
    )

    Process
    {
        Set-TfsArea -Area $Area -NewName $NewName -Project $Project -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.

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 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()]
    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
    )

    Process
    {
        Set-TfsIteration -Iteration $Iteration -NewName $NewName -Project $Project -Collection $Collection
    }
}
<#
.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()]
    [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)
        {
            $cssService.RenameNode($node.Uri, $NewName)
        }

        if ($MoveBy)
        {
            $cssService.ReorderNode($node.Uri, $MoveBy)
        }

        return $cssService.GetNode($node.Uri)
    }
}
<#
.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.

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 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()]
    [OutputType([Microsoft.TeamFoundation.Server.NodeInfo])]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("Path")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})] 
        [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)
        {
            $cssService.RenameNode($node.Uri, $NewName)
        }

        if ($MoveBy)
        {
            $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
            }

            [void]$cssService4.SetIterationDates($node.Uri, $StartDate, $FinishDate)
        }

        return $cssService.GetNode($node.Uri)
    }
}

tools\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 = 'Team Foundation Server 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\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 = 'Team Foundation Server Shell'
$ShortcutFilePath = "$ShortcutTargetDir\$ShortcutName.lnk"

if (Test-Path $ShortcutFilePath)
{
    Write-Output "TfsCmdlets: Removing Start Menu shortcut file"
    Remove-Item $ShortcutFilePath
}

tools\ConfigServer\ConfigServer.psm1
<#
.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.

To 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])]
	Param
	(
		[Parameter(Position=0, ParameterSetName='Get by server', Mandatory=$true, ValueFromPipeline=$true)]
        [AllowNull()]
		[object] 
		$Server,
	
		[Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

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

	Process
	{
		if ($Current)
		{
			return $Global:TfsServerConnection
        }

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

		if ($Server -is [Uri])
		{
			return _GetConfigServerFromUrl $Server $Credential
		}

		if ($Server -is [string])
		{
			if ([Uri]::IsWellFormedUriString($Server, [UriKind]::Absolute))
			{
				return _GetConfigServerFromUrl ([Uri] $Server) $Credential
			}

			if (-not [string]::IsNullOrWhiteSpace($Server))
			{
				return _GetConfigServerFromName $Server $Credential
			}
		}

		if ($Server -eq $null)
		{
			if ($Global:TfsServerConnection)
			{
				return $Global:TfsServerConnection
			}
		}

		throw "No TFS connection information available. Either supply a valid -Server argument or use Connect-TfsConfigurationServer prior to invoking this cmdlet."
	}
}

# =================
# Helper Functions
# =================

Function _GetConfigServerFromUrl([uri] $Url, $Credential)
{
	$cred = Get-TfsCredential -Credential $Credential

	return New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList ([Uri] $Url), $cred
}

Function _GetConfigServerFromName($Name, $Credential)
{
	$Servers = Get-TfsRegisteredConfigurationServer $Name
	
	foreach($Server in $Servers)
	{
		$Url = $Server.Uri
		$cred = Get-TfsCredential -Credential $Credential
		$configServer = New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList $Url,  $cred
		$configServer.EnsureAuthenticated()

		Write-Output $configServer
	}
}
<#
.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.

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

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

For 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 = New-ScriptBlock -EntryPoint '_GetConnectionString' -Dependency 'Get-InstallationPath', 'Test-RegistryValue', 'Get-RegistryValue'

		return Invoke-ScriptBlock -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)]
        [string]
        $Name = "*"
    )

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

        return [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetConfigurationServers() | ? Name -Like $Name
    }
}

tools\Connection\Connection.psm1
<#

.SYNOPSIS
    Connects to a 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

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

.INPUTS
    Microsoft.TeamFoundation.Client.TfsConfigurationServer
    System.String
    System.Uri
#>
Function Connect-TfsConfigurationServer
{
	[CmdletBinding()]
	[OutputType([Microsoft.TeamFoundation.Client.TfsConfigurationServer])]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Server,
	
		[Parameter(Position=1)]
		[object]
		$Credential,

		[Parameter()]
		[switch]
		$Passthru
	)

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

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

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

		if ($Passthru)
		{
			return $configServer
		}
	}
}
<#

.SYNOPSIS
    Connects to a team project.

.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 Passthru
    Returns the results of the command. By default, this cmdlet does not generate any output.

#>
Function Connect-TfsTeamProject
{
	[CmdletBinding()]
	[OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.Project])]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Project,
	
		[Parameter()]
		[object] 
		$Collection,
	
		[Parameter()]
		[object]
		$Credential,

		[Parameter()]
		[switch]
		$Passthru
	)

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

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

		$Global:TfsTeamConnection = $null
		$Global:TfsProjectConnection = $tp
		$Global:TfsTpcConnection = $tp.Store.TeamProjectCollection
		$Global:TfsServerConnection = $Global: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. 
    Finally, if a TfsTeamProjectCollection object is provided via this argument, it will be used as the new default connection. This may be especially useful if you e.g. received a pre-initialized connection to a TFS collection via a call to an external library or API.
	For more details, see the -Collection argument in 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-TfsConfigurationServer 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 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 default credentials of the logged-on user

.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()]
	[OutputType([Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])]
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[ValidateNotNull()]
		[object] 
		$Collection,
	
		[Parameter()]
		[object] 
		$Server,
	
		[Parameter()]
		[object]
		$Credential,

		[Parameter()]
		[switch]
		$Passthru
	)

	Process
	{
		$tpc = $null

		try
		{
			$tpc = (Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Credential | Select -First 1)
			$tpc.EnsureAuthenticated()
		}
		catch
		{
			throw "Error connecting to team project collection $Collection ($_)"
		}

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

		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
{
	Process
	{
        Disconnect-TfsTeamProjectCollection

		if ($Global:TfsServerConnection)
        {
		    Remove-Variable -Name TfsServerConnection -Scope Global
		}
	}
}
<#

.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
{
    Process
    {
        if ($Global:TfsProjectConnection)
        {
            Remove-Variable -Name TfsProjectConnection -Scope Global
        }
    }
}
<#

.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
{
	Process
	{
        Disconnect-TfsTeamProject

        if ($Global:TfsTpcConnection)
        {
		    Remove-Variable -Name TfsTpcConnection -Scope Global
		}
	}
}
<#
.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="Prompt for credential")]
    [OutputType([Microsoft.TeamFoundation.Client.TfsClientCredentials])]
    Param
    (
        [Parameter(ParameterSetName="Cached Credential", Mandatory=$true)]
        [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")]
        [object]
        $Credential,

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

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

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

        $allowInteractive = $false

        switch($parameterSetName)
        {
            'Cached Credential' {
                $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
            }

            'Interactive' {
                $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\Git\Git.psm1
<#

.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()]
        [SupportsWildcards()]
        [string] 
        $Name = '*',

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

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $tpc = $tp.Store.TeamProjectCollection
        $id = $tp.Guid

        $gitService = $tpc.GetService([type]'Microsoft.TeamFoundation.Git.Client.GitRepositoryService')

        return $gitService.QueryRepositories($tp.Name) | ? Name -Like $Name
    }
}

<#

.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
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [string] 
        $Name,

        [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'
    }

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

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

        $task.Wait()
        
        if ($Passthru)
        {
            return $task.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 = Get-TfsHttpClient -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)]
    [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
    {
        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 = Get-TfsHttpClient -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\GlobalList\GlobalList.psm1
<#

.SYNOPSIS
    Exports the contents of one or more Global Lists to XML.

.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 Export-TfsGlobalList
{
    [CmdletBinding()]
    [OutputType([xml])]
    Param
    (
        [Parameter()]
        [SupportsWildcards()]
        [string] 
        $Name = "*",
    
        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    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") #| ? ([System.Xml.XmlElement]$_).GetAttribute("name") -NotLike $Name

        foreach($node in $nodesToRemove)
        {
            if (([System.Xml.XmlElement]$node).GetAttribute("name") -notlike $Name)
            {
                [void]$xml.DocumentElement.RemoveChild($node)
            }
        }

        return $xml
    }
}
<#

.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()]
    Param
    (
        [Parameter()]
        [SupportsWildcards()]
        [string] 
        $Name = "*",
    
        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Collection
    )

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

.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-TfsGlobalList
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [xml] 
        $Xml,
    
        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection $Collection
        $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')

        [void] $store.ImportGlobalLists($Xml.OuterXml)
    }
}
<#

.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
{
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')]
        [string] 
        $Name,
    
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Items')] 
        [string[]] 
        $Items,

        [Parameter()]
        [switch]
        $Force,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        [xml] $xml = Export-TfsGlobalList -Collection $Collection

        # Checks whether the global list already exists
        $list = $xml.SelectSingleNode("//GLOBALLIST[@name='$Name']")

        if ($list -ne $null)
        {
            if ($Force.IsPresent)
            {
                [void] $list.ParentNode.RemoveChild($list)
                $overwritten = $true
            }
            else
            {
                Throw "Global List $Name already exists. To overwrite an existing list, use the -Force switch."
            }
        }

        # Creates the new list XML element
        $list = $xml.CreateElement("GLOBALLIST")
        $list.SetAttribute("name", $Name)

        # 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)

        # Saves the list back to TFS
        Import-TfsGlobalList -Xml $xml -Collection $Collection

        return Get-TfsGlobalList -Name $Name -Collection $Collection
    }
}
<#

.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')]
        [SupportsWildcards()]
        [string] 
        $Name = "*",
    
        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection $Collection
        $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')

        $lists = Get-TfsGlobalList -Name $Name -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
{
    Param
    (
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')]
        [string] 
        $Name,
    
        [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
    )

    Process
    {
        [xml] $xml = Export-TfsGlobalList -Name $Name -Collection $Collection

        # Retrieves the list
        $list = $xml.SelectSingleNode("//GLOBALLIST")
        $newList = $false

        if ($list -eq $null)
        {
            if (-not $Force.IsPresent)
            { 
                throw "Global list name $Name 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", $Name)
            [void] $xml.DocumentElement.AppendChild($list)
            $newList = $true
        }

        if ($PSCmdlet.ParameterSetName -eq "Rename list")
        {
            $list.SetAttribute("name", $NewName)
            Import-TfsGlobalList -Xml $xml -Collection $Collection

            Remove-TfsGlobalList -Name $Name -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 ($existingItem -ne $null) { continue }
            }

            $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)
                {
                    [void]$list.RemoveChild($existingItem)
                }
            }
        }
                
        # Saves the list back to TFS
        Import-TfsGlobalList -Xml $xml -Collection $Collection

        return Get-TfsGlobalList -Name $Name -Collection $Collection
    }
}

tools\Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
md5: 9F99D2F73D03F743AF46952BBF914A2C | sha1: 95BE30EE4A25696DC4D69D00F3949BA60F065436 | sha256: A61A9F67FFA9361E4DA177A6ADE91FFB6102F11F311550E8E225EDE1D4166A98 | sha512: 7A407B7C2CAD4B61CDF8E24B3247C3F0F9AB8527642BF57892D36DC78750F493F1AFED5060620F9961DE075DF56BEEFE04FA17B70971BB8A8CEE1CD94F1A1F34
tools\Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll
md5: F223D8446FD4023B41FD3BEC98429F0E | sha1: FD786557E8BF441F45A1AD9B01222E0C6479DE5A | sha256: EB522D022ACCBBD8A27498653D0D67B9AB3240B564DA9707B21E6BA76BA8CB17 | sha512: 8D49513BBF5D84B9E1D23D213D292DFCF4AAA23E2D5D62C383B5A32EEB4993EEF554051B8DACEBF6D1212A9FCF2BF245F54AEFD6A648B83060A47412E19197BD
tools\Lib\Microsoft.ServiceBus.dll
md5: BB826D1A6E667DABEAC78D089B6E1206 | sha1: D0B3E61F898E9ACB752EF7D81B0F50CD1060609A | sha256: 05D763BE498DD8984385B04FBA3AAB66D211C3ADED49FD9FAFBA5A15BDE9EC99 | sha512: 6A241A4BE73F42D1FC1E498C84CE1A77584BBBE313A0088E74F608F917F1909FFA3F539313104E750E357141B8073317B77FDAB870377D2B5E99FBDF382D2BC6
tools\Lib\Microsoft.TeamFoundation.Build.Client.dll
md5: B4B6B38A06747981B5EF628EC1A6B5F0 | sha1: 119317B099625BAC4BC8AF3312E100CF29C71141 | sha256: 83A40E2FF64C1C71E7A05B8040B195607F500C0419C6A4CA382CE002E55DB07E | sha512: FBEBD738A6985DC888270D25F7B6FCE40DB82703070CC73CBACDEC0922751F05354216A65D0A5DD2EF1886AAA4423ED3B4E67DDE1B818AB5CB36CFD2892F3203
tools\Lib\Microsoft.TeamFoundation.Build.Common.dll
md5: 1B453304BD6233F16CAA65EA12D25198 | sha1: 169E5626ED0EEEA9F4A957B8024C02F5520A88A5 | sha256: C87605EE2D928A692EB2A16CF7525AE19F6C42A5493749B7A2634714A632330F | sha512: 9C1C75D28B836C156180B538DCEF2FC323F9EF70E5358B6DFB461229170D6C9D779A536810BB5AD1017107B2FB68C40053B569A1D1F6CDE84BB30CFFBBE460D1
tools\Lib\Microsoft.TeamFoundation.Build2.WebApi.dll
md5: 7C9A4209C1ACF759A4729C24A04BD0F5 | sha1: 3F8378A5AD6B62D4D1F2116EEC7CA75EA72356A4 | sha256: 2488BFBD9478EC05DF9BE5A9B93BF3514717AB8CFEB072105BB6BE198212F686 | sha512: 6550CF781027B14CDE480CDA2AECD5A4C5A80C434AD1B1D5C5B4F520CB78B16BA398C874FA1B99A22A4DDEF8FEBEB3107ED57C0FDB6311CD83882A883D6B9303
tools\Lib\Microsoft.TeamFoundation.Chat.WebApi.dll
md5: 3499AEB4F2DC2F24962287BDE85C747D | sha1: F9C54A32E34048371A129407DE644CE914EBF9E4 | sha256: AE64D8130D6AC13B3366502F4D9E1430E46A671776D2DB63DC7F3F5242577D6A | sha512: 74AB49160FD08008692C359AFBEA7155C4140701F024C2C2F1C45E7C2BDFF1A60EE0F31A29B2120BAF2E1060DC19A0CCBED7194929EC017A87DC4210644FA246
tools\Lib\Microsoft.TeamFoundation.Client.dll
md5: EE453D65979ED30AAD9F1C9014DC65C3 | sha1: 5929E2C2FBE3ED8CE7C6511FE5F03971C88A2A4D | sha256: 2FBB568FAFFC91E197AAEA20D46CE1F39BF31E272F980B611F26DDC5FC7C89E9 | sha512: F550A434E0C8AFD9E417EE7718077E772FA059B7992A25BFA79BF1ECDF48F25FB5883486F3F76F74C4292C1807D1FF1BF56DEFEBCAC3DF1BFF0DFD8DE5134A0F
tools\Lib\Microsoft.TeamFoundation.Common.dll
md5: 4D2107991CAE379AE46CB5324ACFFCEF | sha1: 0292BF0DB6F3FB817841612A74473C0BBF12BB1D | sha256: 816F6A5F4EC79D248E519333667756E010576F2B89686B15F8F34C407050A440 | sha512: BD174E7BBAC754591B7B266772C2BB9BE2F80B74CCD27E175314A402431AE7DCF4DCD54C7833DAF4BD61D8CFFA22EF7334EB3A59EAC01DB40DF1E6652C3E76F7
tools\Lib\Microsoft.TeamFoundation.Core.WebApi.dll
md5: BAD8113A30E107E572C7E00D2580F22D | sha1: B507E3EE4D111C029EB295CE99E047C03EF99B30 | sha256: 5777AC68B35290D0952C9C22FE578DDB355087FD8EFB94CE5DE97C4C6FD45CC5 | sha512: 8907BF8587F62B6C56F01A652865FE8DFA0201A5F667256D7843FF1ECFB029F67C70CCAFBCA94AFC1A596FDE1D94A354FA007F602A2335F931FABFC58BA2C40F
tools\Lib\Microsoft.TeamFoundation.DeleteTeamProject.dll
md5: FCF6EBD90DF1353912B5FB48980BE572 | sha1: 25E75D9D73EAF045F5E6A8BF928F9816287EB255 | sha256: 91F0FD0ACBADDD0819D7AB8E6815D94A9822E53722FF5908E0A4A639C4AE946C | sha512: 3705C44734D96CA74656F91E256903A08937C2B0C47680515CA4BD8E94A3DB869AD12B5B424062DEC17034A97769914BD826F5665F94A8D8D184B277B65D406D
tools\Lib\Microsoft.TeamFoundation.Diff.dll
md5: 59535511A9579ADE7986F2CF9911BFA4 | sha1: 8DCF5BB69BB8D15DB1195851DA4809524C1255C5 | sha256: DCB187815D27D5E615F4AE0EE25D364BCEE9F6C5F0E444F0B840AA35C758C4B9 | sha512: FAB7CFE89A1D8B052CCC554AD3C7F1A3CCF5FC1498A719340FF1A4F4D60D9DB82BB43E2DF3E14F8C6E190EFA067CC707C27BD2DA7B50316174A8AFEC9FDAEEB8
tools\Lib\Microsoft.TeamFoundation.Discussion.Client.dll
md5: 65699CC0E6C9C1F630FB0F75CFBAC874 | sha1: EDC4C14D83901BF36A9564FB6CC1C0610667FEB1 | sha256: 96270166C466C5D38ADE551B8B4F8EE50292FAD23E2C42F93951A29F03797258 | sha512: 3BFB5363108083857DEC828484B7398D57C3BD0747192D9082EC66AA90E70456DD74E4CBE5EC648BDB2E1E81C53D5D8149D17C152689C6E27C60756260FA0565
tools\Lib\Microsoft.TeamFoundation.Git.Client.dll
md5: A880C88CCD6BF5D07897776DC9F69B22 | sha1: 134C6293FD44FC3AB2F87AA123979F568112FEAD | sha256: 167223B6A154193FEB5930B4D3CB4E38A1336ED447F298638B59551722E56D5A | sha512: 4B18E007BD02986217A74A4B42581C117E0CB1FB799335EC63EE0C55FAC6F3034A2D7188EED83890D2FD34DF67BAF2E5E79B88EC2660E8EC5D32B4DA6E620D31
tools\Lib\Microsoft.TeamFoundation.Lab.Client.dll
md5: 4886BBD37D523E5BD8D3B636C00B7E60 | sha1: 23BFF7060DC6D3A94E2CDBE9C1B26B685FF11D84 | sha256: 9002653BBAF0E5E66663E1CED2C4782DCAE2DDC578A71A6508ECB88A29A94A83 | sha512: E694226E6B201D98985D38B00C51CA0E4AFF25602CEC256875FF916ED06681E6012E2B2AD11C7422881889D3F339CC8BE5336310E3F69283C3259B34DEFB2A48
tools\Lib\Microsoft.TeamFoundation.Lab.Common.dll
md5: 381F617B7BC5B9C7CF68E934ACF42D07 | sha1: C8190813B2C90F122344BF90E14D4494B1FBBB4B | sha256: 5786B6CD1BA5A32749DFB0EAE0DD8436CB58DA63E33CF7A29C330F8D75B9C5A0 | sha512: 0C0C56557E580859F1CB1C5247355E1109638D8C66724CAD389E3D61800491ABAE07EBA63BB9402546F33E5971E18C495D58488FB3F9AE30D33165CAE2211BC3
tools\Lib\Microsoft.TeamFoundation.Lab.TestIntegration.Client.dll
md5: 11A0838940CA664768636EC4B712CB5D | sha1: 418C4945F2D84B2894CE669AF2F210897A1AB9B7 | sha256: 81669CEA7224BB6D93244F77309B80B04F9CFEBBBEAD85A9E0770598D7774F9D | sha512: 482DF0D6DC807846E8B52F1D462F281D7D1C5B235ADDA6D66D628FC358272DFE909D5FAD4E2A20765995E3C17F15B0130D4CA40E874BCE5B32A34FE925A0D4D8
tools\Lib\Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.dll
md5: CFDB1459E47CC23A5B61788C4CD636D1 | sha1: F669259D34559F67590A8D29DE9C77C619D6B86F | sha256: DB63BAF68CEA2B6B1A2AC91A07C0B4F92115C212E0F550E93251D6FF4DF7205D | sha512: 99BD00FC9D2BAE4999A17C8B7A4730858F657DE402FC9B8444C99D03385123C3B3784398E4FAF86DF35E301EAA18DCD41E62E08D1D75C86DF2EB0CCA0C7CA8B4
tools\Lib\Microsoft.TeamFoundation.Policy.WebApi.dll
md5: 7AD9F8314298B9C81B2BD84A8201DADE | sha1: BD81B860CE8EF80DDFFB4C8E5E84F5F835407772 | sha256: 2594A43D904E0FB6D404F636588B05EB4FE6B321E9DCC48445052E1DEA786BD9 | sha512: E794426A35236341B025D8347A232087205EC31C6B6E79640E7C989DED530BD9B5C030AB28547FDE01E36964B5793BC2513D917D05B167BA2E9E5E9338A2EFB8
tools\Lib\Microsoft.TeamFoundation.ProjectManagement.dll
md5: EBF7692BDB7708FEC9F644D02E221716 | sha1: FFA05E1AFC21E8F8FF97ED332191AB1983E8B632 | sha256: 3778B5461DBA53CC42A4063986D910BBEEF72409EC16A0077F0BAE4D441231AD | sha512: 7A0978D7A34D701A163004CC0E86AEB2CB8BF3C4246D827691CD212FB7A58347BE8B8C8BB8A975C3268F17AA70F71562C6B5B77CABB40C9F40965CBCE11A272B
tools\Lib\Microsoft.TeamFoundation.SharePointReporting.Integration.dll
md5: 9F3D93A78E3AEBBFFBFF88E21BC5B410 | sha1: A7E6C6BECA9F0CBED9297ED627087F6653C1CFC0 | sha256: F26028D79100E7C8E19964A2A68332AAA1CAEC2BF28B512C18E6061D1DA9A225 | sha512: C6ED6A4214012B3B1E59B2CF8AD243977A4BE609C64F3985E5DAA46F33174CDE05194443A8CF3572CE56A3C8DED89C51BB531BBF2433A68026D8ADA413F2B2CA
tools\Lib\Microsoft.TeamFoundation.SourceControl.WebApi.dll
md5: C20EE3BDD183C59E2C27F1E831C47AC2 | sha1: 4FDAFDB6559297FF848A02A6B626E75EB8DBE0BE | sha256: 62A56DA107836E7B11EB7B4152B0BA519C345E22DD6D00607A8974EEBB6C7D1D | sha512: 3F3C369CE1A1A5E2FD5C402FCBE934E11ADFD4785DC2F9A44407B8212DEBD0E056678322954A8EA1A50144766A1BCED349005CC18933F3AB1279BE27CC2D83D7
tools\Lib\Microsoft.TeamFoundation.Test.WebApi.dll
md5: 6AE8C9D9FA5168C5539B0E84FA7B12A1 | sha1: 8F5589D7827124F9FD8C48708EC102EFAF93341D | sha256: 8918F9E1E81FA44A95FFFA4455853BA1F5539706A8436081C4111EC008A41A0D | sha512: E13FEC8B3BE171EA749D057ACCEAD4175EB804551F9594EA057213F0B3E0E2280547B453B81FED70F0293FA3CF3A43BCBBF1F4235D5E053FA05AD64B6EC07E6F
tools\Lib\Microsoft.TeamFoundation.TestImpact.Client.dll
md5: 6CB08BFA2D2C65EA29310C197EBC2219 | sha1: CD3729D231CA2001292FB66896837D36B6227ACA | sha256: E3D054E0008F2364EA98DF30052063B619CD510B97E96CEDEB80AE4A0087FDC2 | sha512: 5065EAF0132B89398C6DEA78004E2F3E27EA514575A3DC1C8C91F4841EBF543046602CF81EF3B670BC428B2DC111BCD6A56BD4B8EF6341ECEB9F6CB170E17C96
tools\Lib\Microsoft.TeamFoundation.TestManagement.Client.dll
md5: 7176F404496E7F1ED5CA1245C97B9508 | sha1: 4392C85425E2C24E3B100246462CA81DBD0FA248 | sha256: 119BED4A465B2005635E24254889D15D1AA3CD6ACED21888EAB98A834AAB6B11 | sha512: 5A15195266ECCE203C6C40D48564361D30FB2EF9102E34759D63F242C71F14F1BF481C7A5DBB16C858D9573217B978D0644BF5128AC8C228891B7C42B3D164C8
tools\Lib\Microsoft.TeamFoundation.TestManagement.Common.dll
md5: F5D4AAAF3BE471D09D6F3B7B48E7022C | sha1: C132AF1AFAD923B9C8379314713F08FEEA575E0D | sha256: F2D07C64BA7BF1B1E3E73B29643674DF176322363CA6BA20A7C1DF12986B7FF9 | sha512: BECD304C37AA9E2C5E228E0838A2334B54D8D881766B333D25323192E1CAD1FA3284087EA7077207255AF921A54C43F9D6F1B7B676D7438C6C46497FE41AB4BB
tools\TeamProject\TeamProject.psm1
<#
.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])]
    Param
    (
        [Parameter(Position=0, ParameterSetName='Get by project')]
        [object] 
        $Project = '*',

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

		[Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

		[Parameter()]
		[objectl]
		$Credential
    )

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

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

        if (($Project -is [uri]) -or ([System.Uri]::IsWellFormedUriString($Project, [System.UriKind]::Absolute)))
        {
			$tpc = Get-TfsTeamProjectCollection $Collection -Credential $Credential
            $css = $tpc.GetService([type]'Microsoft.TeamFoundation.Server.ICommonStructureService')

            $projInfo = $css.GetProject([string] $Project)
            $Project = $projInfo.Name
        }

		if ($Project -is [string])
		{
			$tpc = Get-TfsTeamProjectCollection $Collection -Credential $Credential
			$wiStore = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')

			return _GetAllProjects $tpc | ? Name -Like $Project | % { $wiStore.Projects[$_.Name] }
		}

		if ($Project -eq $null)
		{
			if ($global:TfsProjectConnection)
			{
				return $global: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() | ? Status -eq WellFormed
}
<#
.SYNOPSIS
    Creates a new team project. 

#>
Function New-TfsTeamProject
{
    [CmdletBinding(DefaultParameterSetName='Get by project')]
    [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
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection $Collection
        $template = Get-TfsProcessTemplate -Collection $tpc -Name $ProcessTemplate
        $client = Get-TfsHttpClient '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 = Get-TfsHttpClient '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()

        return Get-TfsTeamProject -Project $Project -Collection $Collection
    }
}

tools\Team\Team.psm1
Function _GetTeam
{
    param
    (
        [Parameter()]
        [string] 
        $ProjectName,
    
        [Parameter()]
        [string] 
        $Name
    )

    Begin
    {
        $tpc = Get-TfsTeamProjectCollection -Current
        $teamService = $tpc.GetService([type]"Microsoft.TeamFoundation.Client.TfsTeamService")
    }

    Process
    {
        $teamProject = Get-TfsTeamProject $projectName
        $team = ($teamService.QueryTeams($teamProject.Uri) | where Name -eq $name)

        return $team
    }
}

Function _CreateTeam
{
    param
    (
    )

    Process
    {
        $teamService = $tpc.GetService([type]"Microsoft.TeamFoundation.Client.TfsTeamService")
        return $teamService.CreateTeam($teamProject.Uri, $Name, $Description, $null)
    }
}

Function _SetTeamSettings
{
    param
    (
        $team, 
        
        [string[]]
        $teamFieldValues        
    )
}

function _GetTfsTeamSettingsConfigurationService {
    Param(
        [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection] $TfsCollection
        )
    return $TfsCollection.GetService([ Microsoft.TeamFoundation.ProcessConfiguration.Client.TeamSettingsConfigurationService]);
} 
 
function _AddTfsTeamField {
Param(
       [parameter(Mandatory=$true)][Microsoft.TeamFoundation.Client.TfsTeamProjectCollection] $TfsCollection,
       [parameter(Mandatory=$true)][Microsoft.TeamFoundation.Server.ProjectInfo] $TfsTeamProject,
       [parameter(Mandatory=$true)][Microsoft.TeamFoundation.Client.TeamFoundationTeam] $TfsTeam,
       [parameter(Mandatory=$true)][String] $TeamFieldValue
       )
 
    $TfsTeamConfigService = Get-TfsTeamSettingsConfigurationService $TfsCollection
    $TfsTeamConfig = $TfsTeamConfigService.GetTeamConfigurations([Guid[]]($TfsTeam.Identity.TeamFoundationId))
 
    $newTeamFieldValue = New-Object Microsoft.TeamFoundation.ProcessConfiguration.Client.TeamFieldValue
    $newTeamFieldValue.Value = $TeamFieldValue
 
    $TfsTeamConfig.TeamSettings.TeamFieldValues = [Microsoft.TeamFoundation.ProcessConfiguration.Client.TeamFieldValue[]]($newTeamFieldValue)
    $TfsTeamConfig.TeamSettings.BacklogIterationPath = "$($TfsTeamProject.Name)" 
    #$TfsTeamConfig.TeamSettings.IterationPaths = [string[]]("$($TfsTeamProject.Name)")
 
    $TfsTeamConfigService.SetTeamSettings($TfsTeam.Identity.TeamFoundationId,$TfsTeamConfig.TeamSettings)
} 
<#

.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(DefaultParameterSetName="Get by name")]
    [OutputType([Microsoft.TeamFoundation.Client.TeamFoundationTeam])]
    param
    (
        [Parameter(Position=0, ParameterSetName="Get by name")]
        [Alias("Name")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Client.TeamFoundationTeam])})] 
        [SupportsWildcards()]
        [object]
        $Team = '*',

        [Parameter(Position=0, ParameterSetName="Get default team")]
        [switch]
        $Default,

        [Parameter()]
        [switch]
        $IncludeMembers,

        [Parameter()]
        [Microsoft.TeamFoundation.Framework.Common.MembershipQuery]
        $QueryMembership = [Microsoft.TeamFoundation.Framework.Common.MembershipQuery]::Direct,

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

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($Team -is [Microsoft.TeamFoundation.Client.TeamFoundationTeam])
        {
            return $Team
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $tpc = $tp.Store.TeamProjectCollection
        $teamService = $tpc.GetService([type]'Microsoft.TeamFoundation.Client.TfsTeamService')

        if ($Default)
        {
            $teams = @($teamService.GetDefaultTeam($tp.Uri, $null))
        }
        else
        {
            $teams = $teamService.QueryTeams([string]$tp.Uri) | ? Name -like $Team
        }

        foreach($t in $teams)
        {
            if ($IncludeMembers)
            {
                $members = $t.GetMembers($tpc, $QueryMembership)
                $t | Add-Member -Name 'Members' -MemberType ([System.Management.Automation.PSMemberTypes]::NoteProperty) -Value $members -PassThru

            }
            else
            {
                $t | Add-Member -Name 'Members' -MemberType ([System.Management.Automation.PSMemberTypes]::NoteProperty) -Value ([Microsoft.TeamFoundation.Framework.Client.TeamFoundationIdentity[]] @()) -PassThru
            }
        }
    }
}
<#

.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()]
    [OutputType([Microsoft.TeamFoundation.Client.TeamFoundationTeam])]
    param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("Name")]
        [string] 
        $Team,
    
        [Parameter()]
        [string] 
        $Description,
    
        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Passthru
    )

    Process
    {
        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $tpc = $tp.Store.TeamProjectCollection
        $teamService = $tpc.GetService([type]"Microsoft.TeamFoundation.Client.TfsTeamService")

        $newTeam = $teamService.CreateTeam($tp.Uri, $Team, $Description, $null)

        if ($Passthru)
        {
            return $team
        }
    }
}
<#

.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.Client.TeamFoundationTeam])]
    param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [Alias("Name")]
        [ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Client.TeamFoundationTeam])})] 
        [SupportsWildcards()]
        [object]
        $Team = '*',

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection

        if ($PSCmdlet.ShouldProcess($t.Name, 'Delete team'))
        {
            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
            $tpc = $tp.Store.TeamProjectCollection
            $identityService = $tpc.GetService([type]'Microsoft.TeamFoundation.Framework.Client.IIdentityManagementService')

            $identityService.DeleteApplicationGroup($t.Identity.Descriptor)
        }
    }
}
<#

.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
{
    [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
    )

    Process
    {
        Set-TfsTeam -Team $Team -NewName $NewName -Project $Project -Collection $Collection
    }
}
<#

.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.Client.TeamFoundationTeam
    System.String
#>
Function Set-TfsTeam
{
    [CmdletBinding(DefaultParameterSetName="Get by name")]
    [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()]
        [switch]
        $Default,

        [Parameter()]
        [string]
        $NewName,

        [Parameter()]
        [string]
        $Description,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    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)
        {
            $t.Name = $NewName
        }

        if ($PSBoundParameters.ContainsKey('Description'))
        {
            $t.Description = $Description
        }

        if ($Default)
        {
            $teamService.SetDefaultTeam($t)
        }

        $teamService.UpdateTeam($t)

        return $t
    }
}

tools\TfsCmdlets.Format.ps1xml
 
tools\TfsCmdlets.psd1
@{
    Author = 'Igor Abade V. Leite'
    CompanyName = 'Igor Abade V. Leite'
    Copyright = '(c) 2014 Igor Abade V. Leite. All rights reserved.'
    Description = 'PowerShell Cmdlets for TFS and VSTS'
    RootModule = 'TfsCmdlets.psm1'
    FunctionsToExport = '*-Tfs*'
    GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'
    HelpInfoURI = 'https://github.com/igoravl/tfscmdlets/wiki/'
    ModuleVersion = '1.0.0'
    PowerShellVersion = '3.0'
    TypesToProcess = "TfsCmdlets.Types.ps1xml"
    FormatsToProcess = "TfsCmdlets.Format.ps1xml"
    ScriptsToProcess = 'Startup.ps1'

    NestedModules = @('Admin\Admin.psm1','AreaIteration\AreaIteration.psm1','ConfigServer\ConfigServer.psm1','Connection\Connection.psm1','Git\Git.psm1','GlobalList\GlobalList.psm1','ObjectHelper\ObjectHelper.psm1','ProcessTemplate\ProcessTemplate.psm1','Team\Team.psm1','TeamProject\TeamProject.psm1','TeamProjectCollection\TeamProjectCollection.psm1','WorkItem\WorkItem.psm1','WorkItemQuery\WorkItemQuery.psm1','XamlBuild\XamlBuild.psm1')

    FileList = @('chocolateyInstall.ps1','chocolateyUninstall.ps1','Startup.ps1','TfsCmdlets.Format.ps1xml','TfsCmdlets.psd1','TfsCmdlets.psm1','TfsCmdlets.Types.ps1xml','TfsCmdletsShell.ico')

    PrivateData = @{ 
        Tags = @('TfsCmdlets', 'TFS', 'PowerShell')
        Branch = 'master'
        Commit = @'
a3432c8e5b2c50f8386854f11e9fda1761052121
'@
        Build = '1.0.0-alpha.9+14.master'
        PreRelease = 'alpha9'
        LicenseUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/LICENSE.md'
        ProjectUri = 'https://github.com/igoravl/tfscmdlets/'
        IconUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/TfsCmdlets/resources/TfsCmdlets_Icon_32.png'
        ReleaseNotes = 'See https://github.com/igoravl/tfscmdlets/wiki/ReleaseNotes' 
        TfsClientVersion = 'Microsoft.TeamFoundationServer.ExtendedClient 14.102.0'
    }
}

tools\TfsCmdlets.psm1
Set-Alias tfsrv Connect-TfsConfigurationServer
Set-Alias tftpc Connect-TfsTeamProjectCollection
Set-Alias tftp  Connect-TfsTeamProject
Set-Alias gtftpc Get-TfsTeamProjectCollection
Set-Alias gtftp  Get-TfsTeamProject

tools\TfsCmdlets.Types.ps1xml
 
tools\TfsCmdletsShell.ico
 
tools\WorkItem\WorkItem.psm1
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
}
<#

.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 Add-TfsWorkItemLink
{
    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
    Creates a copy of a work item, optionally changing its type

.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-TfsWorkItem
{
    [CmdletBinding()]
    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('None', 'Original', 'Copy')]
        [string]
        $Passthru = 'None',

        [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
    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()]
        [SupportsWildcards()]
        [string] 
        $Name = "*",

        [Parameter()]
        [switch]
        $IncludeGlobalLists,

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

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $types = Get-TfsWorkItemType -Name $Name -Project $Project -Collection $Collection

        foreach($type in $types)
        {
            $type.Export($IncludeGlobalLists)
        }
    }
}
<#

.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]
        $Filter,

        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by text")]
        [string]
        $Text,

        [Parameter()]
        [hashtable]
        $Macros,

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

        [Parameter()]
        [object]
        $Collection
    )

    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" {
				Write-Verbose "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
    }

	Write-Verbose "Get-TfsWorkItem: Running query $QueryText"

    $wis = $store.Query($QueryText, $Macros)

    foreach($wi in $wis)
    {
        $wi
    }
}
<#

.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"' | % { Write-Output "WI $($_.Id): $($_.Title)"; Get-TfsWorkItemHistory -WorkItem $_ } 

.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
    System.Int32
#>
Function Get-TfsWorkItemHistory
{
    [CmdletBinding()]
    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 | % {
            $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 | ? IsChangedInRevision -eq $true | % {
        $result[$_.ReferenceName] =  [PSCustomObject] @{
            NewValue = $_.Value;
            OriginalValue = $_.OriginalValue
        }
    }

    return $result
}
<#

.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
{
    [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
{
    [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
    }
}
<#

.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 | ? 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()]
    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)
    }
}
<#

.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()]
    [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
    )

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

        $wi.Save()

        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("ID: $id", "Destroy workitem"))
            {
                $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 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()]
    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

        foreach($fldName in $Fields.Keys)
        {
            $wi.Fields[$fldName].Value = $Fields[$fldName]
        }

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

        return $wi
    }
}

tools\WorkItemQuery\WorkItemQuery.psm1
Function _FindQueryFolder($folder, $parent)
{
    Write-Verbose "_FindQueryFolder: Searching for $folder under $($parent.Path)"

    if ($folder -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder])
    {
        Write-Verbose "_FindQueryFolder: Returning folder immediately, since it's a QueryFolder object"
        return $folder
    }

    $folders = $parent | ? {$_ -Is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder]}

    foreach($f in $folders)
    {
        if (($f.Path -like $folder) -or ($f.Name -like $folder))
        {
            Write-Verbose "_FindQueryFolder: Found folder `"$($f.Path)`" matching `"$folder`""
            return @{$f.Name = $f}
        }
    }

    foreach($f in $folders)
    {
        Write-Verbose "_FindQueryFolder: Starting recursive search"

        $result = _FindQueryFolder $folder $f

        if ($result)
        {
            return $result
        }
    }
}

Function _FindQuery($path, $parent)
{
    Write-Verbose "_FindQuery: Searching for $path under $($parent.Path)"

    foreach($item in $parent)
    {
        if (($item -Is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition]) -and (($item.Path -like $path) -or ($item.Name -like $path)))
        {
            # Search immediate children

            Write-Verbose "_FindQuery: Found local query `"$($item.Path)`" matching `"$path`""
            $item
        }
        elseif ($item -Is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder])
        {
            # Search descendants recursively

            Write-Verbose "_FindQuery: Starting recursive search"
            _FindQuery $path $item
        }
        else
        {
            Write-Verbose "_FindQuery: Skipped `"$($item.Path)`" since it doesn't match $path"
        }
    }
}

Function _NormalizeQueryPath($Path, $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)
    }

    if ($newPath -notlike "$ProjectName*")
    {
        $newPath = "$ProjectName/$newPath"
    }

    return $newPath
}
<#

.SYNOPSIS
    Exports a saved work item query to XML.

.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 Export-TfsWorkItemQuery
{
    [CmdletBinding()]
    [OutputType([xml])]
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [string] 
        $Query = "*",

		[Parameter()]
		[string]
		$Folder,
    
		[Parameter()]
		[string]
		$Destination,
    
		[Parameter()]
		[string]
		$Encoding = "UTF-8",
    
        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($Destination -and (-not (Test-Path $Destination -PathType Container)))
        {
            throw "Invalid destination path $Destination"
        }

		$queries = Get-TfsWorkItemQuery -Query $Query -Folder $Folder -Project $Project -Collection $Collection
        
        if (-not $queries)
        {
            throw "Query path `"$Query`" is invalid or missing."
        }

		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)
			{
				$xml
			}
            else
            {
			    $queryPath = $q.Path.Substring($q.Path.IndexOf('/')+1)
                $fileName = Join-Path $Destination "$queryPath.wiql" 
                $filePath = Split-Path $fileName -Parent

                if (-not (Test-Path $filePath -PathType Container))
                {
                    md $filePath -Force | Out-Null
                }

			    $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()]
        $Folder,

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

        [Parameter()]
        [object]
        $Collection
    )

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

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

        if ($Folder)
        {
            if (($Folder -is [string]) -and ($Folder -notlike "$($tp.Name)/*"))
            {
                $Folder = _NormalizeQueryPath $Folder $tp.Name
            }
			
            Write-Verbose "Get-TfsWorkItemQuery: Limiting search to folder $Folder"
            
            $folders = (_FindQueryFolder $Folder $tp.QueryHierarchy)

            if (-not $folders)
            {
                throw "Query folder $Folder is invalid or missing. Be sure you provided the full path (e.g. 'Shared Queries/Current Iteration') instead of just the folder name ('Current Iteration')"
            }

            $root = $folders.Values[0]
        }
        else
        {
			Write-Verbose "Get-TfsWorkItemQuery: -Folder argument missing. Searching entire team project"
            $root = $tp.QueryHierarchy
        }

        return _FindQuery $Query $root
    }
}
<#
.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 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-TfsWorkItemQuery
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition])]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [Alias("Name")]
        [Alias("Path")]
        [string]
        $Query,

        [Parameter()]
        [string]
        $Folder,

        [Parameter()]
        [string]
        $Definition,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
        $tpc = $tp.Store.TeamProjectCollection
        $store = $tp.Store

		$Query = _NormalizeQueryPath "$Folder/$Query" $tp.Name
		$folderPath = (Split-Path $Query -Parent) -replace ('\\', '/')
		$queryName = (Split-Path $Query -Leaf)

		Write-Verbose "New-TfsWorkItemQuery: Creating query '$queryName' in folder '$folderPath'"

		$folder = (_FindQueryFolder $folderPath $tp.QueryHierarchy $true)

		if (-not $folder)
		{
			throw "Invalid or non-existent work item query folder $folderPath."
		}

        if ($Definition -match "select \*")
        {
            Write-Warning "Queries containing 'SELECT *' may not work in Visual Studio. Consider replacing * with a list of fields."
        }

		$q = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition' -ArgumentList $queryName, $Definition
		$folder.Values[0].Add($q)

		$tp.QueryHierarchy.Save()

		return $q
    }
}
<#
.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
    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()]
    [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
    {
        Set-TfsWorkItemQuery -Query $Query -NewName $NewName -Project $Project -Collection $Collection
    }
}
<#

.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()]
    [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)
        {
            $q.Name = $NewName
        }

        if ($Definition)
        {
            $q.QueryText = $Definition
        }

        $q.Project.QueryHierarchy.Save()

		return $q
    }
}

tools\XamlBuild\XamlBuild.psm1
<#

.SYNOPSIS
    Gets information about one or more XAML Build agents.

.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 Get-TfsXamlBuildAgent
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.Build.Client.IBuildAgent])]
    Param
    (
        [Parameter(Position=0)]
        [ValidateScript({$_ -is [string] -or $_ -is [Microsoft.TeamFoundation.Build.Client.IBuildAgent]})]
        [ValidateNotNullOrEmpty()]
        [Alias("Name")]
        [object] 
        $BuildAgent = "*",

        [Parameter(Position=0, ValueFromPipeline=$true)]
        [ValidateScript({$_ -is [string] -or $_ -is [Microsoft.TeamFoundation.Build.Client.IBuildController]})]
        [ValidateNotNullOrEmpty()]
        [Alias("Controller")]
        [object] 
        $BuildController = "*",

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($BuildAgent -is [Microsoft.TeamFoundation.Build.Client.IBuildAgent])
        {
            return $BuildAgent
        }

        $controllers = Get-TfsXamlBuildController -BuildController $BuildController -Collection $Collection

        foreach($controller in $controllers)
        {
            $controller.Agents | Where Name -Like $BuildAgent
        }		
    }
}
<#

.SYNOPSIS
    Gets information about one or more XAML Build controllers.

.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 Get-TfsXamlBuildController
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.Build.Client.IBuildController])]
    Param
    (
        [Parameter(Position=0)]
        [ValidateScript({$_ -is [string] -or $_ -is [Microsoft.TeamFoundation.Build.Client.IBuildController]})]
        [ValidateNotNullOrEmpty()]
        [Alias("Name")]
        [object] 
        $BuildController = "*",

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

    Process
    {
        if ($BuildController -is [Microsoft.TeamFoundation.Build.Client.IBuildController])
        {
            return $BuildController

        }

        $tpc = Get-TfsTeamProjectCollection $Collection

        $buildServer = $tpc.GetService([type]'Microsoft.TeamFoundation.Build.Client.IBuildServer')
        $buildControllers = $buildServer.QueryBuildControllers()
        
        return $buildControllers | Where Name -Like $BuildController
    }
}
<#

.SYNOPSIS
    Gets one or more XAML Build definitions.

.PARAMETER BuildDefinition
    Uses this parameter to filter for an specific Build Defintion.
    If suppress, cmdlet will show all queue builds.

.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-TfsBuildQueue -BuildDefinition "My Build Definition" -Project "My Team Project"
    Get all queued builds given a definition name and a team project name

.EXAMPLE
    Get-TfsBuildQueue
    Get all queued builds, regardless of definition name or team project name

#>
Function Get-TfsXamlBuildDefinition
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.Build.Client.IBuildDefinition])]
    Param
    (
        [Parameter(Position=0)]
        [ValidateScript({$_ -is [string] -or $_ -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition]})]
        [ValidateNotNullOrEmpty()]
        [Alias("Name")]
        [object] 
        $BuildDefinition = "*",

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

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($BuildDefinition -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition])
        {
            return $BuildDefinition
        }

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

        $buildServer = $tpc.GetService([type]'Microsoft.TeamFoundation.Build.Client.IBuildServer')
        $buildDefs = $buildServer.QueryBuildDefinitions($tpName)
        
        return $buildDefs | Where Name -Like $BuildDefinition
    }
}
<#

.SYNOPSIS
    Gets information about queued XAML Builds.

.PARAMETER BuildDefinition
    Uses this parameter to filter for an specific Build Defintion.
    If suppress, cmdlet will show all queue builds.

.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-TfsBuildQueue -BuildDefinition "My Build Definition" -Project "My Team Project"
    Get all queued builds given a definition name and a team project name

.EXAMPLE
    Get-TfsBuildQueue
    Get all queued builds, regardless of definition name or team project name

#>
Function Get-TfsXamlBuildQueue
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.Build.Client.IQueuedBuild])]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [ValidateScript({$_ -is [string] -or $_ -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition]})]
        [ValidateNotNullOrEmpty()]
        [object] 
        $BuildDefinition = "*",

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($BuildDefinition -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition])
        {
            $buildDefName = $BuildDefinition.Name
        }
        else
        {
            $buildDefName = $BuildDefinition
        }

        if ($Project)
        {
            $tp = Get-TfsTeamProject $Project $Collection
            $tpName = $tp.Name
            $tpc = $tp.Store.TeamProjectCollection
        }
        else
        {
            $tpName = "*"
            $tpc = Get-TfsTeamProjectCollection $Collection
        }

        $buildServer = $tpc.GetService([type]'Microsoft.TeamFoundation.Build.Client.IBuildServer')
        $query = $buildServer.CreateBuildQueueSpec($tpName, $buildDefName)
        
        $buildServer.QueryQueuedBuilds($query).QueuedBuilds
    }
}
<#
.SYNOPSIS
   Sets up an additional build service in the current computer

.DESCRIPTION

   In Team Foundation Server, the Build Service is a Windows Service that is associated with a particular TFS Team Project Collection (since 2010). 
   
   Each Build Service support zero to one (0..1) Build Controllers and zero to n (0..n) Build Agents. 
   
   Each Build Agent is associated to a specific Build Controller but an Agent and its corresponding Controller don�t need to be on the same machine. 
   
   This topology lets you configure a continuous integration build that queues its builds on the Build Controller you�ve specified which then farms out the heavy lifting to any of the n agents it manages. This gives you an easy way to load balance your builds across a set of machines.
   
   There is a potential down-side, however, in that each build service can only service one particular project collection and you cannot install more than one build service in any given computer.

   This script allows you work around that limitation, setting up more than one build service in the same machine.

.NOTES
	
	This is not supported and should not be used in production environments.
#>
Function New-TfsXamlBuildService
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $CollectionName,

        [Parameter()]
        [string]
        $BuildServiceName = "TFSBuildServiceHost.2013",

        [Parameter()]
        [string]
        $ComputerName = $env:COMPUTERNAME,

        [Parameter()]
        [ValidateRange(1,65535)]
        [int]
        $Port = 9191,

        [Parameter(Mandatory=$true)]
        [System.Management.Automation.Credential()]
        [System.Management.Automation.PSCredential]
        $ServiceCredential = (Get-Credential),

        [Parameter()]
        [switch]
        $Force
    )

    Begin
    {
        if ($ComputerName -eq "localhost")
        {
            $ComputerName = $env:COMPUTERNAME
        }
        $tpc = Get-TfsTeamProjectCollection -Current
        $buildServer = $tpc.GetService([type]"Microsoft.TeamFoundation.Build.Client.IBuildServer")
    }

    Process
    {
        $ToolsVersion = 12
        $EnvVarName = "TFSBUILDSERVICEHOST.2013"
        $BuildEndpointTemplate = "Build/v5.0/Services"

        if (-not $TfsInstallationPath) 
        {
            $TfsInstallationPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\TeamFoundationServer\12.0").InstallPath
        }

        if (-not $BuildServiceName)
        {
            $BuildServiceName = "TfsBuildService-$collectionName"
        }

        $ServiceBinPath = "$TfsInstallationPath\Tools\TfsBuildServiceHost.exe /NamedInstance:$BuildServiceName"
        $ServiceDisplayName = "Visual Studio Team Foundation Build Service Host ($collectionName)"


        _CreateService $BuildServiceName $ServiceDisplayName $ServiceBinPath $Force.IsPresent
        _RegisterBuildServiceHost $TfsInstallationPath $Force.IsPresent
        _CreateBuildController
        _CreateBuildAgent
    }
}

#======================
# Helper methods
#======================

Function _CreateService
{
    Param
    (
        $BuildServiceName,
        $ServiceDisplayName,
        $ServiceBinPath,
        $Force
    )

    if (Get-Service $BuildServiceName -ErrorAction SilentlyContinue)
    {
        if (-not $Force)
        {
            throw "Build Service $BuildServiceName is already registered. To re-register a build service, use the -Force switch"
        }

        sc.exe delete $BuildServiceName | Out-Null
    }

    $svc = New-Service -Name $BuildServiceName -DisplayName $ServiceDisplayName -BinaryPathName $ServiceBinPath
    
    sc.exe failure $BuildServiceName reset= 86400 actions= restart/60000 | Out-Null
}

Function _RegisterBuildServiceHost
{
    Param
    (
        $TfsInstallationPath,
        $Force
    )

    _LoadPrivateAssemblies $TfsInstallationPath

    $flags = [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::SetProperty -bor [System.Reflection.BindingFlags]::Static
    [Microsoft.TeamFoundation.Build.Config.BuildServiceHostProcess].InvokeMember("NamedInstance", $flags, $null, $null, [object[]] $BuildServiceName)

    if ($buildServer.QueryBuildServiceHosts($BuildServiceName).Length -ne 0)
    {
        if (-not $Force)
        {
            throw "Build Service $BuildServiceName is already registered. To re-register a build service, use the -Force switch"
        }
        
        [Microsoft.TeamFoundation.Build.Config.BuildServiceHostUtilities]::Unregister($true, $true)
    }

    $port = _GetNextAvailablePort
    $endpoint = "http://$env:COMPUTERNAME:$port/$BuildEndpointTemplate"
    $serviceHost = $buildServer.CreateBuildServiceHost($BuildServiceName, $endpoint)
    $serviceHost.Save()

    $userName = $ServiceCredential.UserName
    $password = $ServiceCredential.GetNetworkCredential().Password

    [Microsoft.TeamFoundation.Build.Config.BuildServiceHostUtilities]::Register($serviceHost, $userName, $password)
}

Function _GetNextAvailablePort
{
    $RegistryPath = "HKLM:\SOFTWARE\Microsoft\VisualStudio\$ToolsVersion.0\TeamFoundation\Build"
    $PortsTaken = Get-ChildItem -Path $RegistryPath | Get-ItemProperty -Name Endpoint | ForEach { [uri] $_.Endpoint } | Select -ExpandProperty Port

    $StartPort = 9191
    $MaxPorts = $StartPort + $PortsTaken.Length

    for ($i = $StartPort; $i -le $MaxPorts; $i++)
    { 
        if ($PortsTaken -notcontains $i)
        {
            $Port = $i
            break
        }
    }

    return $Port
}

Function _LoadPrivateAssemblies
{
    Param
    (
        $TfsInstallationPath
    )

    $AssemblyPath = "$TfsInstallationPath\Tools\Microsoft.TeamFoundation.Build.Config.dll"
    Add-Type -Path $AssemblyPath
}

Function _GetRegValue
{
    Param
    (
        $KeyPath, $ValueName, $ComputerName
    )

    Process
    {
        if ((-not $ComputerName) -or ($ComputerName -eq $env:COMPUTERNAME))
        {
            return Get-ChildItem -Path $KeyPath | Get-ItemProperty -Name $ValueName
        }

        $KeyMapping = @{
            HKCU = "CurrentUser";
            HKLM = "LocalMachine"
        }

        $RootKey = ($KeyPath -split ":\")[0]
        $Path = ($KeyPath -split ":\")[1]
        
        $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($KeyMapping[$RootKey], $ComputerName)
        $RegKey= $Reg.OpenSubKey($Path)
        $Value = $RegKey.GetValue($ValueName)

        $RegKey.Close()
        $Reg.Close()

        return $Value
    }
}
<#

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

    Process
    {

        $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\Startup.ps1
$binDir = (Join-Path $PSScriptRoot 'lib')
$assemblyList = ''

foreach($a in Get-ChildItem $binDir)
{
     $assemblyList += "{""$($a.BaseName)"", @""$($a.FullName)""},`r`n"
}

if (-not ([System.Management.Automation.PSTypeName]'TfsCmdlets.AssemblyResolver').Type)
{
    Add-Type -ErrorAction SilentlyContinue -Language CSharp -TypeDefinition @"
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Reflection;

    namespace TfsCmdlets
    {
        public class AssemblyResolver
        {
            private static bool IsVerbose = ("$VerbosePreference" == "Continue");

            public static readonly Dictionary<string, string> PrivateAssemblies = new Dictionary<string, string>
            {
                $assemblyList
            };

            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()
            {
                AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
                {
                    try
                    {
                        var assemblyName = e.Name.Split(',')[0];
                        var isInternal = PrivateAssemblies.ContainsKey(assemblyName);

                        if (IsVerbose) Log("[INFO ] [" + (isInternal? "Internal": "External") + "] " + assemblyName, e);

                        return PrivateAssemblies.ContainsKey(assemblyName)
                            ? LoadAssembly(assemblyName)
                            : null;
                    }
                    catch(Exception ex)
                    {
                        LogError(ex);
                        return null;
                    }
                };
            }

            private static Assembly LoadAssembly(string 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.fff") + "] " + message;

                LogEntries.Add(message, data);
            }

            private static void LogError(Exception ex)
            {
                Log("[ERROR] " + ex.Message, ex);
            }
        }
    }
"@
}

[TfsCmdlets.AssemblyResolver]::Register()

# Initialize Shell

if ($Host.UI.RawUI.WindowTitle -eq "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 ""

    @'
Function Prompt
{
    Process
    {
        $tfsPrompt = ''

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

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

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

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

            $tfsPrompt = "[$tfsPrompt] "
        }

        "TFS $($tfsPrompt)$($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
    }
}
'@ | Invoke-Expression

}

# Load basic TFS client assemblies
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.Common.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.Client.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.WorkItemTracking.Client.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.Build.Client.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.Git.Client.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.VersionControl.Client.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.Core.WebApi.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.TeamFoundation.SourceControl.WebApi.dll')
Add-Type -Path (Join-Path $BinDir 'Microsoft.VisualStudio.Services.WebApi.dll')

tools\ProcessTemplate\ProcessTemplate.psm1
<#
.SYNOPSIS
    Exports a process template definition to 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
	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 -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)]
        [SupportsWildcards()]
        [string]
        $Name = "*",

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

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

        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
{
    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\ObjectHelper\ObjectHelper.psm1
#
# _InvokeGenericMethod.ps1
#

function Invoke-GenericMethod
{
    <#
    .Synopsis
       Invokes Generic methods on .NET Framework types
    .DESCRIPTION
       Allows the caller to invoke a Generic method on a .NET object or class with a single function call.  Invoke-GenericMethod handles identifying the proper method overload, parameters with default values, and to some extent, the same type conversion behavior you expect when calling a normal .NET Framework method from PowerShell.
    .PARAMETER InputObject
       The object on which to invoke an instance generic method.
    .PARAMETER Type
       The .NET class on which to invoke a static generic method.
    .PARAMETER MethodName
       The name of the generic method to be invoked.
    .PARAMETER GenericType
       One or more types which are specified when calling the generic method.  For example, if a method's signature is "string MethodName<T>();", and you want T to be a String, then you would pass "string" or ([string]) to the Type parameter of Invoke-GenericMethod.
    .PARAMETER ArgumentList
       The arguments to be passed on to the generic method when it is invoked.  The order of the arguments must match that of the .NET method's signature; named parameters are not currently supported.
    .EXAMPLE
       Invoke-GenericMethod -InputObject $someObject -MethodName SomeMethodName -GenericType string -ArgumentList $arg1,$arg2,$arg3

       Invokes a generic method on an object.  The signature of this method would be something like this (containing 3 arguments and a single Generic type argument):  object SomeMethodName<T>(object arg1, object arg2, object arg3);
    .EXAMPLE
       $someObject | Invoke-GenericMethod -MethodName SomeMethodName -GenericType string -ArgumentList $arg1,$arg2,$arg3

       Same as example 1, except $someObject is passed to the function via the pipeline.
    .EXAMPLE
       Invoke-GenericMethod -Type SomeClass -MethodName SomeMethodName -GenericType string,int -ArgumentList $arg1,$arg2,$arg3

       Invokes a static generic method on a class.  The signature of this method would be something like this (containing 3 arguments and two Generic type arguments):  static object SomeMethodName<T1,T2> (object arg1, object arg2, object arg3);
    .INPUTS
       System.Object
    .OUTPUTS
       System.Object
    .NOTES
       Known issues:

       Ref / Out parameters and [PSReference] objects are currently not working properly, and I don't think there's a way to fix that from within PowerShell.  I'll have to expand on the
       PSGenericTypes.MethodInvoker.InvokeMethod() C# code to account for that.
    #>

    [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 = Get-GenericMethod @params

        if ($null -eq $method)
        {
            Write-Error "No matching method was found"
            return
        }

        # I'm not sure why, but PowerShell appears to be passing instances of PSObject when $argList contains generic types.  Instead of calling
        # $method.Invoke here from PowerShell, I had to write the PSGenericMethods.MethodInvoker.InvokeMethod helper code in C# to enumerate the
        # argument list and replace any instances of PSObject with their BaseObject before calling $method.Invoke().

        return [PSGenericMethods.MethodInvoker]::InvokeMethod($method, $object, $argList)

    } # process

} # function Invoke-GenericMethod

function Get-GenericMethod
{
    [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 (Test-GenericMethodParameters -MethodInfo $method -ArgumentList ([ref]$argList) -GenericType $GenericType -WithCoercion:$WithCoercion)
        {
            $ArgumentList.Value = $argList
            return $method.MakeGenericMethod($GenericType)
        }
    }

    if (-not $WithCoercion)
    {
        $null = $PSBoundParameters.Remove('WithCoercion')
        return Get-GenericMethod @PSBoundParameters -WithCoercion
    }

} # function Get-GenericMethod

function Test-GenericMethodParameters
{
    [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 Test-GenericMethodParameters

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 = Resolve-RuntimeType @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
    )

    $argValue = $ArgumentList[$Index.Value]
    $argType = Get-Type $argValue

    $isByRef = $RuntimeType.IsByRef
    if ($isByRef)
    {
        if ($ArgumentList[$Index.Value] -isnot [ref]) { return $false }

        $RuntimeType = $RuntimeType.GetElementType()
        $argValue = $argValue.Value
        $argType = Get-Type $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 Resolve-RuntimeType
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [Type]
        $ParameterType,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $RuntimeType,

        [Parameter(Mandatory = $true)]
        [Type[]]
        $GenericType
    )

    if ($ParameterType.IsByRef)
    {
        $elementType = Resolve-RuntimeType -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 = Resolve-RuntimeType -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((Resolve-RuntimeType -ParameterType $argument -RuntimeType $RuntimeType -GenericType $GenericType))
        }

        $definition = $ParameterType
        if (-not $definition.IsGenericTypeDefinition)
        {
            $definition = $definition.GetGenericTypeDefinition()
        }

        return $definition.MakeGenericType($runtimeArguments.ToArray())
    }
    else
    {
        return $ParameterType
    }
}

function Get-Type($object)
{
    if ($null -eq $object) { return $null }
    return $object.GetType()
}

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;
            }
        }
    }
'@
}
<#

.SYNOPSIS
    Gets an Team Foundation Server REST API client object.

.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 Get-TfsHttpClient
{
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $Type,

        [Parameter()]
        [object] 
        $Collection
    )

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

        return Invoke-GenericMethod -InputObject $tpc -MethodName GetClient -GenericType $Type
    }
}

tools\Lib\System.Web.Http.dll
md5: A4B4BD54ED5690E50CB51DB9BFE6EAC0 | sha1: CC2FA76EA2C2BEF2C9A810E17F3B2056D5CFA06F | sha256: 1666E476E6532B3114F0A1B8CD3BA433052F04229AFEF040D79AB8156F1CEEE2 | sha512: 1C821AB1EF444B447D0FD01783B61EBCDA789A9E2CB11C5668B6BA2BF36A3C9F41FAD4EF2C6C94DC56B4F56FD4E17D04A52B6E2F5FB9C70B7608242186C6513A
tools\Lib\System.Net.Http.Formatting.dll
md5: 0FC2047E361B79AC15755B1ED400F819 | sha1: 638F36DCC3A8131B8BEBDFB3A0930A764AA9984B | sha256: 76EA4B2D47BB238C1F2AC0C62F1BE4D34BC71397662E3760EA0C684EC4A429C0 | sha512: 3BE94E64E45B7369C37DE381DEBC6BF19D216E470EC4C01778FA1B8B7AE99E5CD230FE896BDBDC693CF889A744FA1C0234E86052D2FE92E29C73F47D6D8EF57D
tools\Lib\System.IdentityModel.Tokens.Jwt.dll
md5: E3B1BB3989E2E1D51C091DE0DFA5BD49 | sha1: 75C364B96D7C224E69DCCF36B8496143BE58EDE4 | sha256: 9B51335056D251F9567D40A08B770D2B80A2B2D39A413275DE305E2034F2B245 | sha512: F6914A76080078FAAA6300A6A1D19D652A02D9E264ADFC4A9E1D8DDF212895A5CCF54AB3345AC6AD1247B6D2B3BBA1732655BD95551C9C4058BA0DA8EF1C7F41
tools\Lib\Newtonsoft.Json.dll
md5: 5E02DDAF3B02E43E532FC6A52B04D14B | sha1: 67F0BD5CFA3824860626B6B3FFF37DC89E305CEC | sha256: 78BEDD9FCE877A71A8D8FF9A813662D8248361E46705C4EF7AFC61D440FF2EEB | sha512: 38720CACBB169DFC448DEEF86AF973EAFEFA19EAEB48C55C58091C9D6A8B12A1F90148C287FAAAA01326EC47143969AD1B54EE2B81018E1DE0B83350DC418D1C
tools\Lib\Microsoft.WITDataStore64.dll
md5: 5DD86F9B016AA1F438C33A4AF8C643E0 | sha1: DEED61C1286D9307355D0E366E7CDAB0B001FD28 | sha256: A9B5D80730F14619B6B9356DF227F149DB0DF430C4EDA123C42729DA90714CB2 | sha512: 8E0947A7776339EFE61A08A39C6C4F66E595923D71EA63C9FE550116C6AFAB048ACFE43C671B5838B6DB7C0CAE751809F0D2FC13E2C0287B4BEB06FE6500C0EE
tools\Lib\Microsoft.WITDataStore32.dll
md5: 3D1D43B9ED047EE7B5330E9D2BEC0CF8 | sha1: 24B418F03C7DCF01C6BEA48B33A5DA1C5886D88B | sha256: 81F177A69CFAA75205C59C9B518E74B99FBF4C188A488E965368808FC1CEE47D | sha512: 69C471BAB81EAA0143C9DF005FD33D445C8892379FF4D4BC33B9722306D686EBCD1220ECB2E550C1E7F54E7269F958924B2E3BEFEF2DE0B091381965B38313D3
tools\Lib\Microsoft.VisualStudio.Services.WebApi.dll
md5: 530C5502207BCC57A815017ED0FBA42B | sha1: 88CBF51C69B80CEF3486D8DEDCBC617A6FF8F0A5 | sha256: 2F48EE220092198F9DB8E1C16134E3CDE8EB47FEF7A0EF0CEF84844584D3D290 | sha512: BF62307CE14C48F6B80A0CAB765AF3ACC1D50A32ED2B06BD9663AC2B5350BE619B21AFE321342FB66AB79C8D8CE9A089543C4A948E19384121C9A677422B79A7
tools\Lib\Microsoft.VisualStudio.Services.Common.dll
md5: 3433D63842D0C97539CE64A29375D874 | sha1: 3EE70B85FFA1EF5305F90766EB763177829E5436 | sha256: 9C7B024973AB2BE3DE43BBA8608D51F4448CC7D27545E55D83A209284BE27E11 | sha512: DB18D0EE128BC7E93DF7DFD30564A807998D97D512A3F9AE0B89A37725B779158CD35FE3B32252E575E2205CFE951B3B1D16A7E29B19252825A5A5052DA6EE01
tools\Lib\Microsoft.VisualStudio.Services.Client.dll
md5: 2795AC6305205E08ACC396CB812A796E | sha1: 2DEDBF8CA18798850CAB51B6593AE706C10A16CB | sha256: DC5F1C7F35698D176E769864BFCCB9C76F1A5E87B867BD88D776AF1C3DA032A9 | sha512: 6E0612245AF0E49C6991F20493FD97870F4E41882D8817FDA55FAC70674ED7838BCD5ECA8830D94730EDFB448414942F2CC046486231748642EC35783A3AE693
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll
md5: 86208DDC3CAA6A12D89D215417219848 | sha1: CC9B0C7D5072DC9799C5E0BFEAC44BBD18E825D1 | sha256: A78E5738C64D32F947548007F592491DA6C9DF84EC81642DD6BDDCD30FA18AE4 | sha512: D3C154CCD2FF5B46D7C96790AB5011D1AA98EA9FB50A173C708CBD89054830A4792E7C4553E71E67ACA96369558D900798116B093C3F43BEB130A4D0843A81A5
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll
md5: E6A045EF8F64B37E4AC9349E5C561D34 | sha1: 8AEB569C107842676DAA50D850938AF1BAE41FAA | sha256: 16B56A5D8D4EA2D1013A0EC739CC1BB93D446B3E53E985E25769C0728B9BA083 | sha512: F521CAE563D1A2AEECA0516B8EA83F5425BF467C26017DDC13183AEFB8F9D26A602C737C4929B4DD00FC3D27C69666F8FF43D3253B003E11F542A2605A2270E3
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.Common.dll
md5: EA587A647075C61DFE499E54AD674CA2 | sha1: C410D30C7246E1698D774DC2E2968E32B5F0B317 | sha256: 08A3C2A676D61381AD36E7475E391C09C77D57B236550593FE25C0F581D382D0 | sha512: B3812E2219835601A6A826959EF2940550923B6A25B1DE911901C96FC7C6F02691D49145944F225EB0D2A92D2506FCA02C190A822ED91C9F537DB5E04303A5D4
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll
md5: 4313ADCFE1545DB64128B04B6E4A61CC | sha1: 9546F95D39FA1575937D2A63E41742FD02C1915B | sha256: FE5F083B15BF531D513702AAF13329E54E63162E87FE6736AEA5A143B8388679 | sha512: 8061C7B42D3052E4CEB95B49D40475437AA83D2D5EBA310A22538BD422A84101F4DB7A91911EEE787F394E9DE8E03F34F91B2AA1CED2C814A1383A49D02EDE9C
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
md5: 566B081758DBAD1CAC6E59E57C43DF59 | sha1: DF948292E0918D40D5D307CE54609F1ED14B5CEC | sha256: BB80453812405B7EA7A7DED22DBF963BCF4DE3EE57F08892503B204D6532D8AD | sha512: 14E2847930E4CE7EC26EEAD5104F4C0FB4EE7AA612F8042BC06A678643792B740285514E45A2FAA19BE5CA949BB3DC2A864FF3D1ABC3FBD889BFD29AC1EF9AFE
tools\Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll
md5: 6A4F4F49B4B5B35A07E35DB7FB5598CB | sha1: 5C366B03469B802829EED60460082658C6FC601C | sha256: 083860C692EF3218B6CB8F4B5550E2EC00DC52ABF0AD40ADDA1AB31C42FC10CA | sha512: 0CE21121170EB4C6CE73202D9B5B6F822EF90922B58DCEE48D9C16D4F960FF0BB99F80CEBBA01AF7805FF8E1182A656689D8EFC62C34275E461E1FEAA9A71595
tools\Lib\Microsoft.TeamFoundation.Work.WebApi.dll
md5: 04F43933A66D956E65BCC1999F4DA415 | sha1: B610F98E213B49D74405820EEB9E27FBEEC0711C | sha256: C9E131B07A29F486BFB0BFB04E8C668CCD62339216AEB9EF43A4ED8CF4CD7D77 | sha512: 9DFD3AE3E0A85FE6804ACE24320524E4A27F9C1B2DBCADD108B87C3C93E6D3D0F61CBDE610A40003013CC9696B3461264BDAB04400FA7DA722257708E77EAA43
tools\Lib\Microsoft.TeamFoundation.VersionControl.Common.Integration.dll
md5: A2B4EA35BB895F625D987D646BA161F1 | sha1: 9EA0628453BCDDD0113927F768271E7F7233C0A1 | sha256: 865E3B335F0970434E23ACAC02794FD5F798EFBD04DA86F1E06AEB4FD09E1705 | sha512: 5CB21B3A2C368A12ADA73BD266D1730B8C719291AA3EFD9DC45385DD68170713FB1680BAF5A547B6D51A8241A5500C6255E0CC1043356F490AD6B4B00273C2F3
tools\Lib\Microsoft.TeamFoundation.VersionControl.Common.dll
md5: 4219C2C8BA932855B4E269FAD5B67E22 | sha1: A63651AF7349CDF759EC6A77BCB7F56875768500 | sha256: 540AAFF712D3F872F5591CD7AF350AFCD6D4C9A36F4FAA15406259272912DD1D | sha512: 3BD8EB851C22F2DE8209895DEB4084ED2892BB759159200597383EEE8C8B7877A64BB0D5A85AA89D58C4BF75C39292AC1F473268D9404CB1C4229FFF563101B1
tools\Lib\Microsoft.TeamFoundation.VersionControl.Client.dll
md5: 17F60063883EC7C74B08F42CEA290E9F | sha1: C1D5A33091B57CB79B6F703C4ABED89C23025610 | sha256: 3F981D542445D323D8D3703552F543FC5A8EA46C47AEE5F112FB34BF0036D1A2 | sha512: 9CDFB68312FF244C84C0795C543813593BB2E79B18A46BA21056A800E06BE2BA08023A7E5F6AF3744EB370458DB24EFD77352CFECC02EEBBE88999EAAAD2C2C1
tools\Lib\Microsoft.TeamFoundation.TestManagement.WebApi.dll
md5: 7E8BB9D5F832CEB3BB8B8844149F8406 | sha1: 225FB89A13EB07EE2CCCB5FA0CE4F51687B67E3D | sha256: E848AB3939CDFFC8A91B0AEDAE23C4139509FC890192FD7934B1324CFF1CF4B8 | sha512: C06A2EC209247B5E2445F4B98BEAE1E015F137065123119B8A1A986A46ECD039AE143004897D295C1CBB1421294BE5AF032F9AA56DE833B764A0C33912976450
tools\TeamProjectCollection\TeamProjectCollection.psm1
<#

.SYNOPSIS
    Detaches a team project collection database from 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.

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

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

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.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.TfsConfigurationServer
    System.String
    System.Uri
#>
Function Dismount-TfsTeamProjectCollection
{
	[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[object] 
		$Collection,

		[Parameter(ValueFromPipeline=$true)]
		[object] 
		$Server,
	
		[Parameter()]
		[string]
		$Reason,
	
		[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, "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)]
        [SupportsWildcards()]
        [string]
        $Name = "*"
    )

    Process
    {
        return [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetProjectCollections() | ? DisplayName -Like $Name
    }
}
<#
.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 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

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

	Process
	{
        if ($Current)
        {
            return $Global:TfsTpcConnection
        }

		if ($Collection -is [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])
		{
			return $Collection
		}

		if ($Collection -is [Uri])
		{
			return _GetCollectionFromUrl $Collection $Credential
		}

		if ($Collection -is [string])
		{
			if ([Uri]::IsWellFormedUriString($Collection, [UriKind]::Absolute))
			{
				return _GetCollectionFromUrl ([Uri] $Collection) $Credential
			}

			if (-not [string]::IsNullOrWhiteSpace($Collection))
			{
				return _GetCollectionFromName $Collection $Server $Credential
			}

			$Collection = $null
		}

		if ($Collection -eq $null)
		{
			if ($Global:TfsTpcConnection)
			{
				return $Global:TfsTpcConnection
			}
		}

		throw "No TFS connection information available. Either supply a valid -Collection argument or use Connect-TfsTeamProjectCollection prior to invoking this cmdlet."
	}
}

# =================
# Helper Functions
# =================

Function _GetCollectionFromUrl([uri] $Url, $Credential)
{
	$cred = Get-TfsCredential -Credential $Credential

	return New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList $Url, $cred
}


Function _GetCollectionFromName($Name, $Server, $Credential)
{
	$cred = Get-TfsCredential -Credential $Credential

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

	$filter = [Guid[]] @([Microsoft.TeamFoundation.Framework.Common.CatalogResourceTypes]::ProjectCollection)
	
	$collections = $configServer.CatalogNode.QueryChildren($filter, $false, [Microsoft.TeamFoundation.Framework.Common.CatalogQueryOptions]::IncludeParents) 
	$collections = $collections | Select -ExpandProperty Resource | ? DisplayName -like $Name

	if ($collections.Count -eq 0)
	{
		throw "Invalid or non-existent Team Project Collection(s): $Name"
	}

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

		$tpc
	}
}
<#

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

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

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

For 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
{
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[string]
		$Name,

		[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 $Name" -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(),
				$Name,
				$Description,
				"~/$Name/")

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

			return Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Name
		}
		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 $Name")
	}
}
<#

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

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

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

For 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
{
	Param
	(
		[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
		[string]
		$Name,

		[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
	)

	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]'

		$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 $Name" -PercentComplete 0

			$start = Get-Date

			$tpcJob = $tpcService.QueueCreateCollection(
				$Name,
				$Description, 
				$Default.ToBool(),
				"~/$Name/",
				[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 | ? JobId -eq $tpcJob.JobId

				if (($jobDetail -eq $null) -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 $Name : "
					}
				
					return Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Name
				}
			}
		}
		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 $Name")
	}
}
<#

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

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

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

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

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

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

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

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

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

For 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
{
	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
	{
		throw "Not implemented"
	}
}


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.5.1 48 Monday, August 22, 2022 Approved
TfsCmdlets 2.5.0 45 Wednesday, August 3, 2022 Approved
TfsCmdlets 2.4.1 54 Thursday, July 21, 2022 Approved
TfsCmdlets 2.4.0 75 Monday, May 23, 2022 Approved
TfsCmdlets 2.3.2 49 Wednesday, May 18, 2022 Approved
TfsCmdlets 2.3.1 58 Saturday, April 9, 2022 Approved
TfsCmdlets 2.3.0 50 Sunday, April 3, 2022 Approved
TfsCmdlets 2.2.1 58 Friday, February 11, 2022 Approved
TfsCmdlets 2.2.0 50 Saturday, February 5, 2022 Approved
TfsCmdlets 2.1.4 75 Tuesday, November 30, 2021 Approved
TfsCmdlets 2.1.3 52 Thursday, November 25, 2021 Approved
TfsCmdlets 2.1.2 71 Friday, September 10, 2021 Approved
TfsCmdlets 2.1.1 62 Wednesday, September 8, 2021 Approved
TfsCmdlets 2.0.0 64 Tuesday, August 3, 2021 Approved
TfsCmdlets 2.0.0-rc0005 72 Sunday, April 18, 2021 Exempted
TfsCmdlets 2.0.0-rc0004 72 Monday, April 5, 2021 Exempted
TfsCmdlets 2.0.0-rc0003 55 Friday, February 19, 2021 Exempted
TfsCmdlets 2.0.0-rc0002 61 Tuesday, December 1, 2020 Exempted
TfsCmdlets 2.0.0-beta0015 70 Tuesday, July 21, 2020 Exempted
TfsCmdlets 2.0.0-beta0014 51 Sunday, July 19, 2020 Exempted
TfsCmdlets 2.0.0-beta0013 57 Saturday, July 18, 2020 Exempted
TfsCmdlets 2.0.0-beta0010 137 Thursday, September 12, 2019 Exempted
TfsCmdlets 2.0.0-beta0009 82 Tuesday, September 10, 2019 Exempted
TfsCmdlets 2.0.0-beta0008 90 Friday, September 6, 2019 Exempted
TfsCmdlets 2.0.0-beta0004 103 Thursday, August 29, 2019 Exempted
TfsCmdlets 1.0.0.894-beta1 376 Thursday, April 6, 2017 Exempted
TfsCmdlets 1.0.0-alpha9 321 Saturday, December 24, 2016 Exempted
TfsCmdlets 1.0.0-alpha7 285 Thursday, October 22, 2015 Exempted
TfsCmdlets 1.0.0-alpha6 265 Thursday, October 22, 2015 Exempted
TfsCmdlets 1.0.0-alpha5 242 Thursday, September 10, 2015 Exempted
TfsCmdlets 1.0.0-alpha4 226 Friday, September 4, 2015 Exempted
TfsCmdlets 1.0.0-alpha3 297 Thursday, September 3, 2015 Exempted
TfsCmdlets 1.0.0-alpha1 296 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