Downloads:
4,896
Downloads of v 2.0.0-beta0004:
117
Last Update:
29 Aug 2019
Package Maintainer(s):
Software Author(s):
- Igor Abade V. Leite
Tags:
tfscmdlets tfs vsts powershell azure azuredevops devops alm teamfoundationserver- Software Specific:
- Software Site
- Software License
- Package Specific:
- Possible Package Source
- Package outdated?
- Package broken?
- Contact Maintainers
- Contact Site Admins
- Software Vendor?
- Report Abuse
- Download
TfsCmdlets
This is a prerelease version of TfsCmdlets.
- 1
- 2
- 3
2.0.0-beta0004 | Updated: 29 Aug 2019
- Software Specific:
- Software Site
- Software License
- Package Specific:
- Possible Package Source
- Package outdated?
- Package broken?
- Contact Maintainers
- Contact Site Admins
- Software Vendor?
- Report Abuse
- Download
Downloads:
4,896
Downloads of v 2.0.0-beta0004:
117
Maintainer(s):
Software Author(s):
- Igor Abade V. Leite
TfsCmdlets 2.0.0-beta0004
This is a prerelease version of TfsCmdlets.
Legal Disclaimer: Neither this package nor Chocolatey Software, Inc. are affiliated with or endorsed by Igor Abade V. Leite. The inclusion of Igor Abade V. Leite trademark(s), if any, upon this webpage is solely to identify Igor Abade V. Leite goods or services and not for commercial purposes.
- 1
- 2
- 3
Some Checks Have Failed or Are Not Yet Complete
Not All Tests Have Passed
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:
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
Option 1: Cached Package (Unreliable, Requires Internet - Same As Community)-
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
-
Open Source
-
Download the package:
Download - Follow manual internalization instructions
-
-
Package Internalizer (C4B)
-
Run: (additional options)
choco download tfscmdlets --internalize --version=2.0.0-beta0004 --pre --source=https://community.chocolatey.org/api/v2/
-
For package and dependencies run:
choco push --source="'INTERNAL REPO URL'"
- Automate package internalization
-
Run: (additional options)
3. Copy Your Script
choco upgrade tfscmdlets -y --source="'INTERNAL REPO URL'" --version="'2.0.0-beta0004'" --prerelease [other options]
See options you can pass to upgrade.
See best practices for scripting.
Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.
If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:
choco upgrade tfscmdlets -y --source="'INTERNAL REPO URL'" --version="'2.0.0-beta0004'" --prerelease
$exitCode = $LASTEXITCODE
Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
Exit 0
}
Exit $exitCode
- name: Install tfscmdlets
win_chocolatey:
name: tfscmdlets
version: '2.0.0-beta0004'
source: INTERNAL REPO URL
state: present
allow_prerelease: yes
See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.
chocolatey_package 'tfscmdlets' do
action :install
source 'INTERNAL REPO URL'
version '2.0.0-beta0004'
options '--prerelease'
end
See docs at https://docs.chef.io/resource_chocolatey_package.html.
cChocoPackageInstaller tfscmdlets
{
Name = "tfscmdlets"
Version = "2.0.0-beta0004"
Source = "INTERNAL REPO URL"
chocoParams = "--prerelease"
}
Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.
package { 'tfscmdlets':
ensure => '2.0.0-beta0004',
install_options => ['--prerelease'],
provider => 'chocolatey',
source => 'INTERNAL REPO URL',
}
Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.
4. If applicable - Chocolatey configuration/installation
See infrastructure management matrix for Chocolatey configuration elements and examples.
This package is exempt from moderation. While it is likely safe for you, there is more risk involved.
PowerShell Cmdlets for Azure DevOps and Team Foundation Server
<#
.SYNOPSIS
Gets the installation path of a given Team Foundation Server component.
.DESCRIPTION
Many times a Team Foundation Server admin needs to retrieve the location where TFS is actually installed. That can be useful, for instance, to locate tools like TfsSecurity or TfsServiceControl. That information is recorded at setup time, in a well-known location in the Windows Registry of the server where TFS is installed.
.PARAMETER ComputerName
The machine name of the server where the TFS component is installed. It must be properly configured for PowerShell Remoting in case it's a remote machine. Optionally, a System.Management.Automation.Runspaces.PSSession object pointing to a previously opened PowerShell Remote session can be provided instead.
When omitted, defaults to the local machine where the script is being run
.PARAMETER Component
Indicates the TFS component whose installation path is being searched for. For the main TFS installation directory, use BaseInstallation.
When omitted, defaults to BaseInstallation.
.PARAMETER Version
The TFS version number, in the format '##.#'. For TFS 2015, use '14.0'
.PARAMETER Credential
The user credentials to be used to access a remote machine. Those credentials must have the required permission to execute a PowerShell Remote session on that computer and also the permission to access the Windows Registry.
.EXAMPLE
Get-TfsInstallationPath -Version 15.0
Gets the root folder (the BaseInstallationPath) of TFS in the local server where the cmdlet is being run
.EXAMPLE
Get-TfsInstallationPath -Computer SPTFSSRV -Version 14.0 -Component SharepointExtensions -Credentials (Get-Credentials)
Gets the location where the SharePoint Extensions have been installed in the remote server SPTFSSRV, prompting for admin credentials to be used for establishing a PS Remoting session to the server
#>
Function Get-TfsInstallationPath
{
[CmdletBinding()]
[OutputType('string')]
Param
(
[Parameter()]
[object]
[Alias('Session')]
$ComputerName,
[Parameter()]
[ValidateSet('BaseInstallation', 'ApplicationTier', 'SharePointExtensions', 'TeamBuild', 'Tools', 'VersionControlProxy')]
[string]
$Component = 'BaseInstallation',
[Parameter(Mandatory=$true)]
[ValidateSet('11.0','12.0','14.0','15.0')]
[string]
$Version,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
$scriptBlock = _NewScriptBlock -EntryPoint '_GetInstallationPath' -Dependency '_TestRegistryValue', '_GetRegistryValue'
return _InvokeScriptBlock -ScriptBlock $scriptBlock -Computer $Computer -Credential $Credential -ArgumentList $Version, $Component
}
}
<#
.SYNOPSIS
Gets information about a configuration server.
.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.
.PARAMETER Current
Returns the configuration server specified in the last call to Connect-TfsConfigurationServer (i.e. the "current" configuration server)
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Start-TfsIdentitySync
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[CmdletBinding()]
Param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[object]
$Server,
[Parameter()]
[switch]
$Wait,
[Parameter()]
[object]
$Credential
)
Process
{
$srv = Get-TfsConfigurationServer -Server $Server -Credential $Credential
if($srv.Count -ne 1)
{
throw "Invalid or non-existent configuration server $Server"
}
$jobSvc = $srv.GetService([type]'Microsoft.TeamFoundation.Framework.Client.ITeamFoundationJobService')
$syncJobId = [guid]'544dd581-f72a-45a9-8de0-8cd3a5f29dfe'
$syncJobDef = $jobSvc.QueryJobs() | Where-Object { $_.JobId -eq $syncJobId }
if ($syncJobDef)
{
_Log "Queuing job '$($syncJobDef.Name)' with high priority now"
$success = ([bool] $jobSvc.QueueJobNow($syncJobDef, $true))
if (-not $success)
{
throw "Failed to queue synchronization job"
}
if($Wait.IsPresent)
{
do
{
_Log "Waiting for the job to complete"
Start-Sleep -Seconds 5
$status = $jobSvc.QueryLatestJobHistory($syncJobId)
_Log "Current job status: $($status.Result)"
} while($status.Result -eq 'None')
return $result
}
}
else
{
throw "Could not find Periodic Identity Synchronization job definition (id $syncJobId). Unable to start synchronization process."
}
}
}
Function _GetInstallationPath($Version, $Component)
{
$rootKeyPath = "HKLM:\Software\Microsoft\TeamFoundationServer\$Version"
if ($Component -eq 'BaseInstallation')
{
$componentPath = $rootKeyPath
}
else
{
$componentPath = "$rootKeyPath\InstalledComponents\$Component"
}
if (-not (_TestRegistryValue -Path $rootKeyPath -Value 'InstallPath'))
{
throw "Team Foundation Server is not installed in computer $env:COMPUTERNAME"
}
if (-not (_TestRegistryValue -Path $componentPath -Value 'InstallPath'))
{
throw "Team Foundation Server component '$Component' is not installed in computer $env:COMPUTERNAME"
}
return _GetRegistryValue -Path $componentPath -Value 'InstallPath'
}
@{
Description = 'This module contains advanced administration cmdlets to support remote administration of some features of Team Foundation Server that, otherwise, would require an administrator to be logged in to a TFS Application Tier console'
ModuleVersion = '0.0.0'
RootModule = 'Admin.psm1'
PrivateData = @{
FriendlyName = 'Administration'
}
}
<#
.SYNOPSIS
Gets one or more Work Item Areas from a given Team Project.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.EXAMPLE
Get-TfsArea
Returns all area paths in the currently connected Team Project (as defined by a previous call to Connect-TfsTeamProject)
.EXAMPLE
Get-TfsArea 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
Returns information on an area path called 'Fabrikam Web Team' in a team project called 'Fabrikam Fiber'
.EXAMPLE
Get-TfsArea '\**\Support' -Project Tailspin
Performs a recursive search and returns all area paths named 'Support' that may exist in a team project called Tailspin
#>
Function Get-TfsArea
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Position=0)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[SupportsWildcards()]
[object]
$Area = '\**',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
return _GetCssNodes -Node $Area -Scope Area -Project $Project -Collection $Collection
}
}
<#
.SYNOPSIS
Moves a Work Item Area from its parent area to another one in the same Team Project.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER Destination
Specifies the name, URI or path of an Area Path that will become the new parent of the given source area
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Server.NodeInfo
System.String
System.Uri
#>
Function Move-TfsArea
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Area,
[Parameter(Position=1l)]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Destination,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$node = Get-TfsArea -Area $Area -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent area $Area"
}
$destinationNode = Get-TfsArea -Area $Destination -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent destination area $Destination"
}
$cssService = _GetCssService -Project $Project -Collection $Collection
$cssService.MoveBranch($node.Uri, $destinationNode.Uri)
$node = $cssService.GetNode($node.Uri)
if ($Passthru)
{
return $node
}
}
}
<#
.SYNOPSIS
Creates a new Work Item Area in the given Team Project.
.PARAMETER Area
Specifies the path of the new Area. When supplying a path, use a backslash ("\") between the path segments. Leading and trailing backslashes are optional. The last segment in the path will be the area name.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function New-TfsArea
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[string]
$Area,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
if($PSCmdlet.ShouldProcess($Area, 'Create Area Path'))
{
$node = _NewCssNode -Path $Area -Scope Area -Project $Project -Collection $Collection
if ($Passthru)
{
return $node
}
}
}
}
<#
.SYNOPSIS
Deletes one or more Work Item Areas.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER MoveTo
Specifies the new area path for the work items currently assigned to the area being deleted, if any. When omitted, defaults to the root area
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Remove-TfsArea
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Area,
[Parameter(Position=1)]
[Alias("NewPath")]
[ValidateScript({ ($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo]) })]
[object]
$MoveTo = '\',
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$areas = Get-TfsArea -Area $Area -Project $Project -Collection $Collection | Sort-Object -Property Path -Descending
foreach($item in $areas)
{
$projectName = $item.Path.Split("\")[1]
if (-not ($PSCmdlet.ShouldProcess($projectName, "Delete Area '$($item.RelativePath)' and move orphaned work items to area '$MoveTo'")))
{
continue
}
_DeleteCssNode -Node $item -MoveToNode $MoveTo -Scope Area -Project $projectName -Collection $Collection
}
}
}
<#
.SYNOPSIS
Renames a Work Item Area.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER NewName
Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Area parameter, Rename-TfsArea generates an error. To rename and move an item, use the Move-TfsArea cmdlet.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Rename-TfsArea
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[Alias("Path")]
[object]
$Area,
[Parameter(Position=1)]
[string]
$NewName,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$result = Set-TfsArea -Area $Area -NewName $NewName -Project $Project -Collection $Collection
if ($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Modifies the name and/or the position of a Work Item Area.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER NewName
Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-Tfsarea generates an error. To rename and move an item, use the Move-Tfsarea cmdlet.
.PARAMETER MoveBy
Reorders an area by moving it either up or down inside its parent. A positive value moves an area down, whereas a negative one moves it up.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Set-TfsArea
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[Alias("Path")]
[object]
$Area,
[Parameter()]
[string]
$NewName,
[Parameter()]
[int]
$MoveBy,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$node = Get-TfsArea -Area $Area -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent area $Area"
}
$cssService = _GetCssService -Project $Project -Collection $Collection
if ($NewName)
{
if ($PSCmdlet.ShouldProcess($Area, "Rename area to $NewName"))
{
$cssService.RenameNode($node.Uri, $NewName)
}
}
if ($MoveBy)
{
if ($PSCmdlet.ShouldProcess($Area, "Reorder area by moving it $MoveBy positions (negative is up, positive is down)"))
{
$cssService.ReorderNode($node.Uri, $MoveBy)
}
}
return $cssService.GetNode($node.Uri)
}
}
<#
.SYNOPSIS
Determines whether the specified Areas Paths exist.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.EXAMPLE
Test-TfsArea 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
Returns $true if an area path called 'Fabrikam Web Team' exists in a team project called 'Fabrikam Fiber'
#>
Function Test-TfsArea
{
[CmdletBinding()]
[OutputType('bool')]
Param
(
[Parameter(Position=0)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[SupportsWildcards()]
[object]
$Area = '\**',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
try
{
return [bool] (_GetCssNodes -Node $Area -Scope Area -Project $Project -Collection $Collection)
}
catch
{
Write-Warning "Error testing path: $_"
return $false
}
}
}
Function _GetCssNodes($Node, $Scope, $Project, $Collection)
{
Process
{
if ($Node -is [Microsoft.TeamFoundation.Server.NodeInfo])
{
_Log "Input item is of type NodeInfo; returning input item immediately, without further processing."
return $Node
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$projectName = $tp.Name
$cssService = _GetCssService -Collection $tpc
if ($node -is [uri])
{
_Log "Getting node by URL [$node]"
return $cssService.GetNode($node)
}
$rootPath = _NormalizeCssNodePath -Project $projectName -Scope $Scope -Path '' -IncludeTeamProject -IncludeScope
$rootNodeUri = $cssService.GetNodeFromPath("$rootPath").Uri
_Log "Retrieving Nodes XML from root path [$rootPath]"
$rootElement = $cssService.GetNodesXml(@($rootNodeUri), $true)
$nodePaths = $rootElement.SelectNodes('//@Path') | Select-Object -ExpandProperty '#text'
$fullPath = _NormalizeCssNodePath -Project $projectName -Scope $Scope -Path $Node -IncludeScope -IncludeTeamProject -IncludeLeadingBackslash
$matchingPaths = $nodePaths | Where-Object { _Log "Evaluating '$_' against pattern '$fullPath' == $($_ -like $fullPath)" -Caller (_GetLogCallStack); $_ -like $fullPath }
return $matchingPaths | Foreach-Object { _Log "Returning node from path [$_]" -Caller (_GetLogCallStack); $cssService.GetNodeFromPath($_) }
}
}
Function _DeleteCssNode($Node, $Scope, $MoveToNode, $Project, $Collection)
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$newNode = _GetCssNodes -Node $MoveToNode -Scope $Scope -Project $Project -Collection $Collection
_Log "Moving work items from deleted node [$($Node.Path)] to node [$($newNode.Path)]"
$cssService = _GetCssService -Collection $tpc
$cssService.DeleteBranches($Node.Uri, $newNode.Uri)
}
Function _NewCssNode ($Project, $Path, $Scope, $Collection, $StartDate, $FinishDate)
{
Process
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$projectName = $tp.Name
_Log "Creating $Scope node [$Path] in project $projectName"
$cssService = _GetCssService -Collection $tpc
try
{
$fullPath = _NormalizeCssNodePath -Project $projectName -Scope $Scope -Path $Path -IncludeTeamProject -IncludeScope
$parentPath = Split-Path $fullPath -Parent
$nodeName = Split-Path $fullPath -Leaf
$parentNode = $cssService.GetNodeFromPath($parentPath)
}
catch
{
_Log "Parent node [$parentPath] does not exist. Creating recursively..."
$parentNode = _NewCssNode -Project $Project -Path $parentPath -Scope $Scope -Collection $Collection
}
if ($StartDate -or $FinishDate)
{
_Log "Iteration date(s) were provided as Start = [$StartDate], Finish = [$FinishDate]. Creating iteration with supplied dates"
$cssService = _GetCssService -Collection $tpc -Version 4
$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri, $StartDate, $FinishDate)
}
else
{
if($Scope -eq 'Iteration')
{
_Log "Iteration date(s) were not provided. Creating iteration without dates"
}
$nodeUri = $cssService.CreateNode($nodeName, $parentNode.Uri)
}
return $cssService.GetNode($nodeUri)
}
}
Function _NormalizeCssNodePath
{
Param
(
[Parameter(Mandatory=$true)]
[string]
$Project,
[ValidateSet('Area', 'Iteration')]
[string]
$Scope,
[Parameter(Mandatory=$true)]
[AllowEmptyString()]
[string]
$Path,
[switch]
$IncludeScope,
[switch]
$ExcludePath,
[switch]
$IncludeLeadingBackslash,
[switch]
$IncludeTrailingBackslash,
[switch]
$IncludeTeamProject
)
_Log "Normalizing path '$Path' with arguments $(_DumpObj $PSBoundParameters)"
$newPath = ''
if ($IncludeLeadingBackslash) { $newPath += '\' }
if ($IncludeTeamProject) { $newPath += $Project + '\' }
if ($IncludeScope) { $newPath += $Scope + '\' }
if(-not $ExcludePath.IsPresent)
{
$Path = $Path.Trim(' ', '\')
if ($Path -like "$Project\$Scope\*")
{
$Path = $Path.Substring("$Project\$Scope\".Length)
}
if ($Path -like "$Project\*")
{
$Path = $Path.Substring($Path.IndexOf('\'))
}
elseif ($Path -eq $Project)
{
$Path = ''
}
$newPath += $Path
}
if ($newPath.EndsWith('\') -and (-not $IncludeTrailingBackslash.IsPresent))
{
$newPath = $newPath.TrimEnd('\')
}
_Log "Normalized path: $newPath"
return $newPath -replace '\\{2,}', '\'
}
Function _GetCssService($Collection, $Version)
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
return $tpc.GetService([type]"Microsoft.TeamFoundation.Server.ICommonStructureService$Version")
}
@{
Description = 'This module contains cmdlets to mantain Areas and Iterations, hierarchical fields in TFS used to classify work items and to enable Backlogs and Boards'
ModuleVersion = '0.0.0'
RootModule = 'AreaIteration.psm1'
PrivateData = @{
FriendlyName = 'Areas and Iterations'
}
}
<#
.SYNOPSIS
Gets one or more Work Item Iterations from a given Team Project.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsIteration
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Position=0)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[SupportsWildcards()]
[object]
$Iteration = '\**',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
return _GetCssNodes -Node $Iteration -Scope Iteration -Project $Project -Collection $Collection
}
}
<#
.SYNOPSIS
Moves a Work Item Iteration from its parent iteration to another one in the same Team Project.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER Destination
Specifies the name, URI or path of an Iteration Path that will become the new parent of the given source iteration
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Server.NodeInfo
System.String
System.Uri
#>
Function Move-TfsIteration
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Iteration,
[Parameter(Position=1)]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Destination,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$node = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent iteration $Iteration"
}
$destinationNode = Get-TfsIteration -Iteration $Destination -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent destination iteration $Destination"
}
$cssService = _GetCssService -Project $Project -Collection $Collection
$cssService.MoveBranch($node.Uri, $destinationNode.Uri)
$node = $cssService.GetNode($node.Uri)
if ($Passthru)
{
return $node
}
}
}
<#
.SYNOPSIS
Creates a new Work Item Iteration in the given Team Project.
.PARAMETER Iteration
Specifies the path of the new Iteration. When supplying a path, use a backslash ("\") between the path segments. Leading and trailing backslashes are optional. The last segment in the path will be the iteration name.
.PARAMETER StartDate
Specifies the start of a timed iteration, such as a sprint. Enter a string that represents the date and time, such as "12/01/2015" or a DateTime object, such as one from a Get-Date command. When omitted, no start date is set.
.PARAMETER FinishDate
Specifies the end of a timed iteration, such as a sprint. Enter a string that represents the date and time, such as "12/01/2015" or a DateTime object, such as one from a Get-Date command. When omitted, no finish date is set.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function New-TfsIteration
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[string]
$Iteration,
[Parameter()]
[DateTime]
$StartDate,
[Parameter()]
[DateTime]
$FinishDate,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
if($PSCmdlet.ShouldProcess($Iteration, 'Create iteration path'))
{
$node = _NewCssNode -Path $Iteration -Scope Iteration -Project $Project -Collection $Collection -StartDate $StartDate -FinishDate $FinishDate
if ($Passthru)
{
return $node
}
}
}
}
<#
.SYNOPSIS
Deletes one or more Work Item Iterations.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER MoveTo
Specifies the new iteration path for the work items currently assigned to the iteration being deleted, if any. When omitted, defaults to the root iteration
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Remove-TfsIteration
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[SupportsWildcards()]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[object]
$Iteration,
[Parameter(Position=1)]
[Alias("NewPath")]
[ValidateScript({ ($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo]) })]
[object]
$MoveTo = '\',
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$iterations = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection | Sort-Object -Property Path -Descending
foreach($i in $iterations)
{
$projectName = $i.Path.Split("\")[1]
if (-not ($PSCmdlet.ShouldProcess($projectName, "Delete Iteration '$($i.RelativePath)' and move orphaned work items to iteration '$MoveTo'")))
{
continue
}
_DeleteCssNode -Node $i -MoveToNode $MoveTo -Scope Iteration -Project $projectName -Collection $Collection
}
}
}
<#
.SYNOPSIS
Renames a Work Item Iteration.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER NewName
Specifies the new name of the iteration. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Iteration parameter, Rename-TfsIteration generates an error. To rename and move an item, use the Move-TfsIteration cmdlet.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Rename-TfsIteration
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[Alias("Path")]
[object]
$Iteration,
[Parameter(Position=1)]
[string]
$NewName,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$result = Set-TfsIteration -Iteration $Iteration -NewName $NewName -Project $Project -Collection $Collection
if ($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Modifies the name, position and/or the dates of a Work Item Iteration.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER NewName
Specifies the new name of the iteration. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the Iteration parameter, Rename-TfsIteration generates an error. To rename and move an item, use the Move-TfsIteration cmdlet.
.PARAMETER MoveBy
Reorders an iteration by moving it either up or down inside its parent. A positive value moves an iteration down, whereas a negative one moves it up.
.PARAMETER StartDate
Sets the start date of the iteration. To clear the start date, set it to $null. Note that when clearing a date, both must be cleared at the same time (i.e. setting both StartDate and FinishDate to $null)
.PARAMETER FinishDate
Sets the finish date of the iteration. To clear the finish date, set it to $null. Note that when clearing a date, both must be cleared at the same time (i.e. setting both StartDate and FinishDate to $null)
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Set-TfsIteration
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[SupportsWildcards()]
[object]
$Iteration,
[Parameter()]
[string]
$NewName,
[Parameter()]
[int]
$MoveBy,
[Parameter()]
[Nullable[DateTime]]
$StartDate,
[Parameter()]
[Nullable[DateTime]]
$FinishDate,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$node = Get-TfsIteration -Iteration $Iteration -Project $Project -Collection $Collection
if (-not $node)
{
throw "Invalid or non-existent iteration $Iteration"
}
$cssService = _GetCssService -Project $Project -Collection $Collection
$cssService4 = _GetCssService -Project $Project -Collection $Collection -Version 4
if ($NewName)
{
if ($PSCmdlet.ShouldProcess($Iteration, "Rename iteration to $NewName"))
{
$cssService.RenameNode($node.Uri, $NewName)
}
}
if ($MoveBy)
{
if ($PSCmdlet.ShouldProcess($Area, "Reorder iteration by moving it $MoveBy positions (negative is up, positive is down)"))
{
$cssService.ReorderNode($node.Uri, $MoveBy)
}
}
if ($StartDate -or $FinishDate)
{
if (-not $PSBoundParameters.ContainsKey("StartDate"))
{
$StartDate = $node.StartDate
}
if (-not $PSBoundParameters.ContainsKey("FinishDate"))
{
$FinishDate = $node.FinishDate
}
if ($PSCmdlet.ShouldProcess($Area, "Set iteration start and finish dates to $StartDate and $FinishDate, respectively"))
{
[void]$cssService4.SetIterationDates($node.Uri, $StartDate, $FinishDate)
}
}
return $cssService.GetNode($node.Uri)
}
}
<#
.SYNOPSIS
Determines whether the specified Iterations Paths exist.
.PARAMETER Iteration
Specifies the name, URI or path of an Iteration. Wildcards are permitted. If omitted, all Iterations in the given Team Project are returned.nnTo supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.nnWhen supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node).
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.EXAMPLE
Test-TfsIteration 'Fabrikam Web Team' -Project 'Fabrikam Fiber'
Returns $true if an iteration path called 'Fabrikam Web Team' exists in a team project called 'Fabrikam Fiber'
#>
Function Test-TfsIteration
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Server.NodeInfo')]
Param
(
[Parameter(Position=0)]
[Alias("Path")]
[ValidateScript({($_ -is [string]) -or ($_ -is [uri]) -or ($_ -is [Microsoft.TeamFoundation.Server.NodeInfo])})]
[SupportsWildcards()]
[object]
$Iteration = '\**',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
try
{
return [bool] (_GetCssNodes -Node $Iteration -Scope Iteration -Project $Project -Collection $Collection)
}
catch
{
Write-Warning "Error testing path: $_"
return $false
}
}
}
$InstallPath = Join-Path $($env:ChocolateyInstall) 'lib\TfsCmdlets'
$ToolsDir = Join-Path $InstallPath 'Tools'
if ($env:PSModulePath -like "*$ToolsDir*")
{
Write-Output "TfsCmdlets: Removing installation directory from PSModulePath environment variable"
$NewModulePath = $Env:PSModulePath.Replace($ToolsDir, '').Replace(';;', ';')
SETX @('PSModulePath', $NewModulePath, '/M')
}
$ShortcutTargetDir = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs"
$ShortcutName = 'Azure DevOps Shell'
$ShortcutFilePath = "$ShortcutTargetDir\$ShortcutName.lnk"
if (Test-Path $ShortcutFilePath)
{
Write-Output "TfsCmdlets: Removing Start Menu shortcut file"
Remove-Item $ShortcutFilePath
}
<#
.SYNOPSIS
Gets information about a configuration server.
.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.
.PARAMETER Current
Returns the configuration server specified in the last call to Connect-TfsConfigurationServer (i.e. the "current" configuration server)
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Get-TfsConfigurationServer
{
[CmdletBinding(DefaultParameterSetName='Get by server')]
[OutputType('Microsoft.TeamFoundation.Client.TfsConfigurationServer')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Position=0, ParameterSetName='Get by server', Mandatory=$true)]
[AllowNull()]
[object]
$Server,
[Parameter(Position=0, ParameterSetName="Get current")]
[switch]
$Current,
[Parameter(Position=1, ParameterSetName='Get by server')]
[object]
$Credential
)
Process
{
if ($Current.IsPresent -or (-not $Server))
{
return $script:TfsServerConnection
}
if ($Server -is [Microsoft.TeamFoundation.Client.TfsConfigurationServer])
{
return $Server
}
$cred = Get-TfsCredential -Credential $Credential
if (($Server -is [Uri]) -or ([Uri]::IsWellFormedUriString($Server, [UriKind]::Absolute)))
{
return New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList ([Uri] $Server), $cred
}
if ($Server -is [string] -and (-not [string]::IsNullOrWhiteSpace($Server)))
{
$serverNames = Get-TfsRegisteredConfigurationServer -Server $Server
foreach($s in $serverNames)
{
Write-Output (New-Object Microsoft.TeamFoundation.Client.TfsConfigurationServer -ArgumentList $s.Uri, $cred)
}
return
}
throw 'No TFS connection information available. Either supply a valid -Server argument or use Connect-TfsConfigurationServer prior to invoking this cmdlet.'
}
}
<#
.SYNOPSIS
Gets the configuration server database connection string.
.PARAMETER Computer
Specifies the name of a Team Foundation Server application tier from which to retrieve the connection string
.PARAMETER Version
Specifies the version of the Team Foundation Server being queried. Valid values are '12.0' (TFS 2013), '14.0' (TFS 2015), '15.0' (TFS 2017)
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
#>
Function Get-TfsConfigurationServerConnectionString
{
[CmdletBinding()]
[OutputType('string')]
Param
(
[Parameter()]
[string]
[Alias('Session')]
$Computer,
[Parameter()]
[ValidateSet('12.0', '14.0', '15.0')]
[string]
$Version,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
$scriptBlock = _NewScriptBlock -EntryPoint '_GetConnectionString' -Dependency 'Get-InstallationPath', '_TestRegistryValue', '_GetRegistryValue'
return _InvokeScriptBlock -ScriptBlock $scriptBlock -Computer $Computer -Credential $Credential -ArgumentList $Version
}
}
Function _GetConnectionString($Version)
{
$path = Get-InstallationPath -Version $Version -Component ApplicationTier
$webConfigPath = Join-Path $path 'Web Services/Web.config'
$webConfig = [xml] (Get-Content $webConfigPath)
return (Select-Xml -Xml $webConfig -XPath '/configuration/appSettings/add[@key="applicationDatabase"]/@value').Node.Value
}
<#
.SYNOPSIS
Gets one or more Team Foundation Server addresses registered in the current computer.
.PARAMETER Name
Specifies the name of a registered server. When omitted, all registered servers are returned. Wildcards are permitted.
.INPUTS
System.String
#>
Function Get-TfsRegisteredConfigurationServer
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Client.RegisteredConfigurationServer' )]
Param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[Alias('Name')]
[string]
$Server = "*"
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
}
Process
{
if(($Server -eq "localhost") -or ($Server -eq "."))
{
$Server = $env:COMPUTERNAME
}
return [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetConfigurationServers() | Where-Object Name -Like $Server
}
}
@{
Description = 'This module contains cmdlets to administer server-wide features of Team Foundation Server'
ModuleVersion = '0.0.0'
RootModule = 'ConfigServer.psm1'
PrivateData = @{
FriendlyName = 'Configuration Server'
}
}
<#
.SYNOPSIS
Connects to a configuration server.
.PARAMETER Server
#Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.DESCRIPTION
The Connect-TfsConfigurationServer function connects to a TFS configuration server. Functions that operate on a server level (as opposed to those operation on a team project collection level) will use by default a connection opened by this function.
.NOTES
A TFS Configuration Server represents the server that is running Team Foundation Server. On a database level, it is represented by the Tfs_Configuration database. Operations that should be performed on a server level (such as setting server-level permissions) require a connection to a TFS configuration server. Internally, this connection is represented by an instance of the Microsoft.TeamFoundation.Client.TfsConfigurationServer class and is kept in a PowerShell global variable caled TfsServerConnection.
.EXAMPLE
Connect-TfsConfigurationServer -Server http://vsalm:8080/tfs
Connects to the TFS server specified by the URL in the Server argument
.EXAMPLE
Connect-TfsConfigurationServer -Server vsalm
Connects to a previously registered TFS server by its user-defined name "vsalm". For more information, see Get-TfsRegisteredConfigurationServer
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
.LINK
Microsoft.TeamFoundation.Client.TfsConfigurationServer
.LINK
https://blogs.msdn.microsoft.com/taylaf/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes/
#>
Function Connect-TfsConfigurationServer
{
[CmdletBinding(DefaultParameterSetName="Explicit credentials")]
[OutputType('Microsoft.TeamFoundation.Client.TfsConfigurationServer')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateNotNull()]
[object]
$Server,
[Parameter(ParameterSetName="Explicit credentials")]
[object]
$Credential,
[Parameter(ParameterSetName="Prompt for credentials", Mandatory=$true)]
[switch]
$Interactive,
[Parameter()]
[switch]
$Passthru
)
Process
{
if ($PSCmdlet.ParameterSetName -eq 'Prompt for credentials')
{
$Credential = (Get-TfsCredential -Interactive)
}
$configServer = Get-TfsConfigurationServer -Server $Server -Credential $Credential
if (-not $configServer)
{
throw "Error connecting to TFS"
}
$script:TfsTeamConnection = $null
$script:TfsProjectConnection = $null
$script:TfsTpcConnection = $null
$script:TfsServerConnection = $configServer
if ($Passthru)
{
return $configServer
}
}
}
<#
.SYNOPSIS
Connects to a team project.
.DESCRIPTION
The Connect-TfsTeamProject cmdlet "connects" (initializes a Microsoft.TeamFoundation.WorkItemTracking.Client.Project object) to a TFS Team Project. That connection is subsequently kept in a global variable to be later reused until it's closed by a call to Disconnect-TfsTeamProject.
Cmdlets in the TfsCmdlets module that require a team project object to be provided via their -Project argument in order to access a TFS project will use the connection opened by this cmdlet as their "default project". In other words, TFS cmdlets (e.g. New-TfsArea) that have a -Project argument will use the connection provided by Connect-TfsTeamProject by default.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.EXAMPLE
Connect-TfsTeamProject -Project FabrikamFiber
Connects to a project called FabrikamFiber in the current team project collection (as specified in a previous call to Connect-TfsTeamProjectCollection)
.EXAMPLE
Connect-TfsTeamProject -Project FabrikamFiber -Collection http://vsalm:8080/tfs/FabrikamFiberCollection
Connects to a project called FabrikamFiber in the team project collection specified in the given URL
#>
Function Connect-TfsTeamProject
{
[CmdletBinding(DefaultParameterSetName="Explicit credentials")]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateNotNull()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter(ParameterSetName="Explicit credentials")]
[object]
$Credential,
[Parameter(ParameterSetName="Prompt for credentials", Mandatory=$true)]
[switch]
$Interactive,
[Parameter()]
[switch]
$Passthru
)
Process
{
if ($Interactive.IsPresent)
{
$Credential = (Get-TfsCredential -Interactive)
}
$tp = (Get-TfsTeamProject -Project $Project -Collection $Collection -Credential $Credential | Select-Object -First 1)
if (-not $tp)
{
throw "Error connecting to team project $Project"
}
$script:TfsTeamConnection = $null
$script:TfsProjectConnection = $tp
$script:TfsTpcConnection = $tp.Store.TeamProjectCollection
$script:TfsServerConnection = $script:TfsTpcConnection.ConfigurationServer
if ($Passthru)
{
return $tp
}
}
}
<#
.SYNOPSIS
Connects to a team project collection.
.DESCRIPTION
The Connect-TfsTeamProjectCollection cmdlet "connects" (initializes a Microsoft.TeamFoundation.Client.TfsTeamProjectCollection object) to a TFS Team Project Collection. That connection is subsequently kept in a global variable to be later reused until it's closed by a call to Disconnect-TfsTeamProjectCollection.
Most cmdlets in the TfsCmdlets module require a TfsTeamProjectCollection object to be provided via their -Collection argument in order to access a TFS instance. Those cmdlets will use the connection opened by Connect-TfsTeamProjectCollection as their "default connection". In other words, TFS cmdlets (e.g. New-TfsWorkItem) that have a -Collection argument will use the connection provided by Connect-TfsTeamProjectCollection by default.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.PARAMETER Interactive
Prompts for user credentials. Can be used for any Azure DevOps account - the proper login dialog is automatically selected. Should only be used in an interactive PowerShell session (i.e., a PowerShell terminal window), never in an unattended script (such as those executed during an automated build).
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.EXAMPLE
Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection
Connects to a collection called "DefaultCollection" in a TF server called "tfs" using the cached credentials of the logged-on user
.EXAMPLE
Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection -Interactive
Connects to a collection called "DefaultCollection" in a Team Foundation server called "tfs", firstly prompting the user for credentials (it ignores the cached credentials for the currently logged-in user). It's equivalent to the command:
PS> Connect-TfsTeamProjectCollection -Collection http://tfs:8080/tfs/DefaultCollection -Credential (Get-TfsCredential -Interactive)
.LINK
Get-TfsTeamProjectCollection
.LINK
https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsteamprojectcollection.aspx
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Connect-TfsTeamProjectCollection
{
[CmdletBinding(DefaultParameterSetName="Cached credentials")]
[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateNotNull()]
[object]
$Collection,
[Parameter(ParameterSetName="Cached credentials")]
[switch]
$Cached,
[Parameter(ParameterSetName="User name and password", Mandatory=$true, Position=1)]
[string]
$UserName,
[Parameter(ParameterSetName="User name and password", Position=2)]
[securestring]
$Password,
[Parameter(ParameterSetName="Credential object", Mandatory=$true)]
[ValidateNotNull]
[object]
$Credential,
[Parameter(ParameterSetName="Personal Access Token", Mandatory=$true)]
[Alias('Pat')]
[string]
$PersonalAccessToken,
[Parameter(ParameterSetName="Prompt for credential", Mandatory=$true)]
[switch]
$Interactive,
[Parameter()]
[object]
$Server,
[Parameter()]
[switch]
$Passthru
)
Begin
{
if ($PSVersionTable.PSEdition -ne 'Desktop') { throw "This cmdlet requires does not work in PowerShell Core. It uses TFS Client Object Model, which only works in Windows PowerShell" }
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
}
Process
{
$tpc = $null
if ($Collection -is [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])
{
_Log "Collection argument is of type TfsTeamProjectCollection. Reusing object."
$tpc = $Collection
}
else
{
_Log "Connecting with $($PSCmdlet.ParameterSetName)"
if ($PSBoundParameters.ContainsKey('Collection')) { [void] $PSBoundParameters.Remove('Collection') }
if ($PSBoundParameters.ContainsKey('Server')) { [void] $PSBoundParameters.Remove('Server') }
if ($PSBoundParameters.ContainsKey('Passthru')) { [void] $PSBoundParameters.Remove('Passthru') }
$creds = Get-TfsCredential @PSBoundParameters
$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Creds
if (-not $tpc -or ($tpc.Count -ne 1))
{
throw "Invalid or non-existent team project collection $Collection"
}
try
{
_Log "Calling TfsTeamProjectCollection.EnsureAuthenticated()"
$tpc.EnsureAuthenticated()
}
catch
{
throw "Error connecting to team project collection $Collection ($_)"
}
}
$script:TfsTeamConnection = $null
$script:TfsProjectConnection = $null
$script:TfsTpcConnection = $tpc
$script:TfsServerConnection = $tpc.ConfigurationServer
$script:AzDevTeamConnection = $null
$script:AzDevProjectConnection = $null
_Log "Connected to $($tpc.Uri)"
if ($Passthru)
{
return $tpc
}
}
}
<#
.SYNOPSIS
Disconnects from the currently connected configuration server.
.DESCRIPTION
The Disconnect-TfsConfigurationServer cmdlet removes the global variable set by Connect-TfsConfigurationServer. Therefore, cmdlets relying on a "default server" as provided by "Get-TfsConfigurationServer -Current" will no longer work after a call to this cmdlet, unless their -Server argument is provided or a new call to Connect-TfsConfigurationServer is made.
.EXAMPLE
Disconnect-TfsConfigurationServer
Disconnects from the currently connected TFS configuration server
#>
Function Disconnect-TfsConfigurationServer
{
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
Param
(
)
Process
{
Disconnect-TfsTeamProjectCollection
if ($script:TfsServerConnection)
{
Remove-Variable -Name TfsServerConnection -Scope Script
}
}
}
<#
.SYNOPSIS
Disconnects from the currently connected team project.
.DESCRIPTION
The Disconnect-TfsTeamProject cmdlet removes the global variable set by Connect-TfsTeamProject . Therefore, cmdlets relying on a "default project" as provided by "Get-TfsTeamProject -Current" will no longer work after a call to this cmdlet, unless their -Project argument is provided or a new call to Connect-TfsTeamProject is made.
.EXAMPLE
Disconnect-TfsTeamProject
Disconnects from the currently connected TFS team project
#>
Function Disconnect-TfsTeamProject
{
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
Param
(
)
Process
{
if ($script:TfsProjectConnection)
{
Remove-Variable -Name TfsProjectConnection -Scope Script
}
}
}
<#
.SYNOPSIS
Disconnects from the currently connected team project collection.
.DESCRIPTION
The Disconnect-TfsTeamProjectCollection cmdlet removes the global variable set by Connect-TfsTeamProjectCollection. Therefore, cmdlets relying on a "default collection" as provided by "Get-TfsTeamProjectCollection -Current" will no longer work after a call to this cmdlet, unless their -Collection argument is provided or a new call to Connect-TfsTeamProjectCollection is made.
.EXAMPLE
Disconnect-TfsTeamProjectCollection
Disconnects from the currently connected TFS team project collection
#>
Function Disconnect-TfsTeamProjectCollection
{
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
Param
(
)
Process
{
Disconnect-TfsTeamProject
if ($script:TfsTpcConnection)
{
Remove-Variable -Name TfsTpcConnection -Scope Script
}
}
}
<#
.SYNOPSIS
Provides credentials to use when you connect to a Team Foundation Server or Visual Studio Team Services account.
.DESCRIPTION
.NOTES
.INPUTS
#>
Function Get-TfsCredential
{
[CmdletBinding(DefaultParameterSetName="Cached credentials")]
[OutputType('Microsoft.TeamFoundation.Client.TfsClientCredentials')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(ParameterSetName="Cached credentials")]
[switch]
$Cached,
[Parameter(ParameterSetName="User name and password", Mandatory=$true, Position=1)]
[string]
$UserName,
[Parameter(ParameterSetName="User name and password", Position=2)]
[securestring]
$Password,
[Parameter(ParameterSetName="Credential object", Mandatory=$true)]
[AllowNull()]
[object]
$Credential,
[Parameter(ParameterSetName="Personal Access Token", Mandatory=$true)]
[Alias('Pat')]
[string]
$PersonalAccessToken,
[Parameter(ParameterSetName="Prompt for credential", Mandatory=$true)]
[switch]
$Interactive
)
Process
{
$parameterSetName = $PSCmdlet.ParameterSetName
if (($parameterSetName -eq 'Credential object') -and (-not $Credential))
{
$parameterSetName = 'Cached Credentials'
}
$allowInteractive = $false
switch($parameterSetName)
{
'Cached Credentials' {
$fedCred = New-Object 'Microsoft.TeamFoundation.Client.CookieCredential' -ArgumentList $true
$winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $true
}
'User name and password' {
$netCred = New-Object 'System.Net.NetworkCredential' -ArgumentList $UserName, $Password
$fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
$winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
}
'Credential object' {
if ($Credential -is [Microsoft.TeamFoundation.Client.TfsClientCredentials])
{
return $Credential
}
if($Credential -is [pscredential])
{
$netCred = $Credential.GetNetworkCredential()
}
elseif ($Credential -is [System.Net.NetworkCredential])
{
$netCred = $Credential
}
else
{
throw "Invalid argument Credential. Supply either a PowerShell credential (PSCredential object) or a System.Net.NetworkCredential object."
}
$fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
$winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
}
'Personal Access Token' {
$netCred = New-Object 'System.Net.NetworkCredential' -ArgumentList 'dummy-pat-user', $PersonalAccessToken
$fedCred = New-Object 'Microsoft.TeamFoundation.Client.BasicAuthCredential' -ArgumentList $netCred
$winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $netCred
}
'Prompt for credential' {
$fedCred = New-Object 'Microsoft.TeamFoundation.Client.CookieCredential' -ArgumentList $false
$winCred = New-Object 'Microsoft.TeamFoundation.Client.WindowsCredential' -ArgumentList $false
$allowInteractive = $true
}
else {
throw "Invalid parameter set $($PSCmdlet.ParameterSetName)"
}
}
return New-Object 'Microsoft.TeamFoundation.Client.TfsClientCredentials' -ArgumentList $winCred, $fedCred, $allowInteractive
}
}
@{
Description = 'This module contains cmdlets used to connect to and disconnect from Team Foundation Server objects (servers, collections and projects)'
ModuleVersion = '0.0.0'
RootModule = 'Connection.psm1'
PrivateData = @{
FriendlyName = 'Connection'
}
}
<#
.SYNOPSIS
Gets information from one or more branches in a Git repository.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsGitBranch
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitBranchStats')]
Param
(
[Parameter()]
[Alias('RefName')]
[SupportsWildcards()]
[object]
$Branch = '*',
[Parameter(ValueFromPipeline=$true)]
[SupportsWildcards()]
[object]
$Repository,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
}
Process
{
if((-not $Repository) -and $Project)
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$Repository = $tp.Name
}
$repos = Get-TfsGitRepository -Repository $Repository -Project $Project -Collection $Collection
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
$client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc
foreach($repo in $repos)
{
if($repo.Size -eq 0)
{
Write-Verbose "Repository $($repo.Name) is empty. Skipping."
continue
}
$task = $client.GetBranchesAsync($tp.Name,$repo.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving branches from repository '$($repo.Name)'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
Write-Output $result | Where-Object name -Like $Branch | `
Add-Member -Name 'Project' -MemberType NoteProperty -Value $repo.ProjectReference.Name -PassThru | `
Add-Member -Name 'Repository' -MemberType NoteProperty -Value $repo.Name -PassThru | `
Sort-Object Project, Repository
}
}
}
<#
.SYNOPSIS
Gets information from one or more Git repositories in a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsGitBranchPolicy
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Policy.WebApi.PolicyConfiguration')]
Param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[SupportsWildcards()]
[object]
$Repository = '*',
[Parameter()]
[Alias('RefName')]
[AllowNull()]
[object]
$Branch = 'master',
[Parameter()]
[object]
$PolicyType,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
}
Process
{
if($Repository.ProjectReference.Name) {$Project = $Repository.ProjectReference.Name}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc
if($Branch -and ($Branch -notlike 'refs/*'))
{
$Branch = "refs/heads/$Branch"
}
$policyTypeId = $null
if($PolicyType)
{
$policy = Get-TfsPolicyType -Type $PolicyType -Project $tp -Collection $tpc
if(-not $policy)
{
throw "Invalid or non-existent policy type '$PolicyType'"
}
$policyTypeId = $PolicyType.Id
}
$repos = Get-TfsGitRepository -Repository $Repository -Project $tp -Collection $tpc
foreach($repo in $repos)
{
$task = $client.GetPolicyConfigurationsAsync($tp.Name, $repo.Id, $Branch, $policyTypeId); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving branch policy configurations for repository '$($repo.Name)'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
return $result.PolicyConfigurations
}
}
@{
Description = 'This module contains cmdlets used to administer Git repositories in Team Foundation Server'
ModuleVersion = '0.0.0'
RootModule = 'Git.psm1'
PrivateData = @{
FriendlyName = 'Git Repositories'
}
}
<#
.SYNOPSIS
Gets information from one or more Git repositories in a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsGitRepository
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias('Name')]
[object]
$Repository = '*',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
}
Process
{
if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository]) { _Log "Input item is of type Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository; returning input item immediately, without further processing."; return $Repository }
if(_TestGuid($Repository))
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
$client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc
$task = $client.GetRepositoryAsync($guid); $result = $task.Result; if($task.IsFaulted) { throw "Error getting repository with ID $guid" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return $result
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient' -Collection $tpc
$task = $client.GetRepositoriesAsync($tp.Name); $result = $task.Result; if($task.IsFaulted) { throw "Error getting repository '$Repository'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return $result | Where-Object Name -Like $Repository
}
}
<#
.SYNOPSIS
Creates a new Git repository in a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function New-TfsGitRepository
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
Param
(
[Parameter(Mandatory=$true)]
[Alias('Name')]
[string]
$Repository,
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Common'
}
Process
{
if($PSCmdlet.ShouldProcess($Repository, 'Create Git repository'))
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
#$tpc = $tp.Store.TeamProjectCollection
$gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'
$tpRef = [Microsoft.TeamFoundation.Core.WebApi.TeamProjectReference] @{Id = $tp.Guid; Name = $tp.Name}
$repoToCreate = [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository] @{Name = $Repository; ProjectReference = $tpRef}
$task = $gitClient.CreateRepositoryAsync($repoToCreate, $tp.Name)
$result = $task.Result
if ($Passthru)
{
return $result
}
}
}
}
<#
.SYNOPSIS
Deletes one or more Git repositories from a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository
System.String
#>
Function Remove-TfsGitRepository
{
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
Param
(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[SupportsWildcards()]
[Alias('Name')]
[object]
$Repository,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
}
Process
{
if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
{
$Project = $Repository.ProjectReference.Name
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
#$tpc = $tp.Store.TeamProjectCollection
$gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'
if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
{
$reposToDelete = @($Repository)
}
else
{
$reposToDelete = Get-TfsGitRepository -Name $Repository -Project $Project -Collection $Collection
}
foreach($repo in $reposToDelete)
{
if ($PSCmdlet.ShouldProcess($repo.Name, "Delete Git repository from Team Project $($tp.Name)"))
{
$gitClient.DeleteRepositoryAsync($repo.Id).Wait()
}
}
}
}
<#
.SYNOPSIS
Renames a Git repository in a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.INPUTS
Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository
System.String
#>
Function Rename-TfsGitRepository
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository')]
Param
(
[Parameter(Mandatory=$true, ValueFromPipeline=$true, Position=0)]
[object]
$Repository,
[Parameter(Mandatory=$true, Position=1)]
[string]
$NewName,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.SourceControl.WebApi'
}
Process
{
if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
{
$Project = $Repository.ProjectReference.Name
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
#$tpc = $tp.Store.TeamProjectCollection
$gitClient = _GetRestClient -Type 'Microsoft.TeamFoundation.SourceControl.WebApi.GitHttpClient'
if ($Repository -is [Microsoft.TeamFoundation.SourceControl.WebApi.GitRepository])
{
$reposToRename = @($Repository)
}
else
{
$reposToRename = Get-TfsGitRepository -Name $Repository -Project $Project -Collection $Collection
}
foreach($repo in $reposToRename)
{
if ($PSCmdlet.ShouldProcess($repo.Name, "Rename Git repository in Team Project $($tp.Name) to $NewName"))
{
$task = $gitClient.RenameRepositoryAsync($repo, $NewName)
$task.Wait()
if ($Passthru)
{
return $task.Result
}
}
}
}
}
<#
.SYNOPSIS
Exports the contents of one or more Global Lists to XML.
.DESCRIPTION
This cmdlets generates an XML containing one or more global lists and their respective items, in the same format used by witadmin. It is functionally equivalent to 'witadmin exportgloballist'
.PARAMETER Name
Specifies the name of the global list to be exported. Wildcards are supported; when used, they result in a single XML containing all the matching global lists.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
.EXAMPLE
Export-TfsGlobalList | Out-File 'gl.xml'
Exports all global lists in the current project collection to a file called gl.xml.
.EXAMPLE
Export-TfsGlobalList -Name 'Builds - *'
Exports all build-related global lists (with names starting with 'Build - ') and return the resulting XML document
.NOTES
To export or list global lists, you must be a member of the Project Collection Valid Users group or have your View collection-level information permission set to Allow.
#>
Function Export-TfsGlobalList
{
[CmdletBinding()]
[OutputType('string')]
Param
(
[Parameter(Position=0)]
[Alias('Name')]
[SupportsWildcards()]
[string]
$GlobalList = "*",
[Parameter(ValueFromPipeline=$true)]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$tpc = Get-TfsTeamProjectCollection $Collection
$store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
$xml = [xml] $store.ExportGlobalLists()
$procInstr = $xml.CreateProcessingInstruction("xml", 'version="1.0"')
[void] $xml.InsertBefore($procInstr, $xml.DocumentElement)
$nodesToRemove = $xml.SelectNodes("//GLOBALLIST")
foreach($node in $nodesToRemove)
{
if (([System.Xml.XmlElement]$node).GetAttribute("name") -notlike $GlobalList)
{
[void]$xml.DocumentElement.RemoveChild($node)
}
}
return $xml.OuterXml
}
}
<#
.SYNOPSIS
Gets the contents of one or more Global Lists.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Get-TfsGlobalList
{
[CmdletBinding()]
[OutputType('PSCustomObject')]
Param
(
[Parameter()]
[Alias('Name')]
[SupportsWildcards()]
[string]
$GlobalList = "*",
[Parameter(ValueFromPipeline=$true)]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$xml = [xml](Export-TfsGlobalList @PSBoundParameters)
foreach($listNode in $xml.SelectNodes("//GLOBALLIST"))
{
$list = [PSCustomObject] [ordered] @{
Name = $listNode.GetAttribute("name")
Items = @()
}
foreach($itemNode in $listNode.SelectNodes("LISTITEM"))
{
$list.Items += $itemNode.GetAttribute("value")
}
$list
}
}
}
<#
.SYNOPSIS
Imports one or more Global Lists from an XML document
.DESCRIPTION
This cmdletsimports an XML containing one or more global lists and their respective items, in the same format used by witadmin. It is functionally equivalent to 'witadmin importgloballist'
.PARAMETER InputObject
XML document object containing one or more global list definitions
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.Xml.XmlDocument
.EXAMPLE
Get-Content gl.xml | Import-GlobalList
Imports the contents of an XML document called gl.xml to the current project collection
.NOTES
To import global lists, you must be a member of the Project Collection Administrators security group
#>
Function Import-TfsGlobalList
{
[CmdletBinding(ConfirmImpact='Medium')]
Param
(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[Alias("Xml")]
[object]
$InputObject,
[Parameter()]
[switch]
$Force,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$tpc = Get-TfsTeamProjectCollection $Collection
$store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
if ($InputObject -is [xml])
{
$doc = $InputObject.OuterXml
}
else
{
$doc = $InputObject
}
if (-not $Force)
{
$existingLists = Get-TfsGlobalList -Collection $tpc
$listsInXml = ([xml]($InputObject)).SelectNodes('//*/@name')."#text"
foreach($list in $existingLists)
{
if ($list.Name -in $listsInXml)
{
Throw "Global List '$($list.Name)' already exists. To overwrite an existing list, use the -Force switch."
}
}
}
[void] $store.ImportGlobalLists($doc)
}
}
<#
.SYNOPSIS
Creates a new Global List.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String / System.String[]
#>
Function New-TfsGlobalList
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('PSCustomObject')]
Param
(
[Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')]
[Alias('Name')]
[string]
$GlobalList,
[Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Items')]
[string[]]
$Items,
[Parameter()]
[switch]
$Force,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
[xml] $xml = Export-TfsGlobalList -Collection $Collection
# Checks whether the global list already exists
$list = $xml.SelectSingleNode("//GLOBALLIST[@name='$GlobalList']")
if ($null -ne $list)
{
if ($Force.IsPresent)
{
if ($PSCmdlet.ShouldProcess($GlobalList, 'Overwrite existing global list'))
{
[void] $list.ParentNode.RemoveChild($list)
}
}
else
{
Throw "Global List $GlobalList already exists. To overwrite an existing list, use the -Force switch."
}
}
if($PSCmdlet.ShouldProcess($GlobalList, 'Create global list'))
{
# Creates the new list XML element
$list = $xml.CreateElement("GLOBALLIST")
$list.SetAttribute("name", $GlobalList)
# Adds the item elements to the list
foreach($item in $Items)
{
$itemElement = $xml.CreateElement("LISTITEM")
[void] $itemElement.SetAttribute("value", $item)
[void]$list.AppendChild($itemElement)
}
# Appends the new list to the XML obj
[void] $xml.DocumentElement.AppendChild($list)
Import-TfsGlobalList -Xml $xml -Collection $Collection
$list = Get-TfsGlobalList -Name $GlobalList -Collection $Collection
if ($Passthru)
{
return $list
}
}
}
}
<#
.SYNOPSIS
Deletes one or more Global Lists.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function Remove-TfsGlobalList
{
[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
Param
(
[Parameter(ValueFromPipelineByPropertyName='Name')]
[Alias('Name')]
[SupportsWildcards()]
[string]
$GlobalList = "*",
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$tpc = Get-TfsTeamProjectCollection $Collection
$store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
$lists = Get-TfsGlobalList -Name $GlobalList -Collection $Collection
$listsToRemove = @()
foreach($list in $lists)
{
if ($PSCmdlet.ShouldProcess($list.Name, "Remove global list"))
{
$listsToRemove += $list
}
}
if ($listsToRemove.Length -eq 0)
{
return
}
$xml = [xml] "<Package />"
foreach($list in $listsToRemove)
{
$elem = $xml.CreateElement("DestroyGlobalList");
$elem.SetAttribute("ListName", "*" + $list.Name);
$elem.SetAttribute("ForceDelete", "true");
[void]$xml.DocumentElement.AppendChild($elem);
}
$returnElem = $null
$store.SendUpdatePackage($xml.DocumentElement, [ref] $returnElem, $false)
}
}
<#
.SYNOPSIS
Changes the name or the contents of a Global List.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function Set-TfsGlobalList
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, ValueFromPipelineByPropertyName='Name')]
[Alias('Name')]
[string]
$GlobalList,
[Parameter(ParameterSetName="Edit list items")]
[string[]]
$Add,
[Parameter(ParameterSetName="Edit list items")]
[string[]]
$Remove,
[Parameter(ParameterSetName="Rename list", Mandatory=$true)]
[string]
$NewName,
[Parameter(ParameterSetName="Edit list items")]
[switch]
$Force,
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$xml = [xml] (Export-TfsGlobalList -Name $GlobalList -Collection $Collection)
# Retrieves the list
$list = $xml.SelectSingleNode("//GLOBALLIST")
$newList = $false
if ($null -eq $list)
{
if (-not $Force.IsPresent)
{
throw "Global list name $GlobalList is invalid or non-existent. Either check the name or use -Force to create a new list."
}
# Creates the new list XML element
$list = $xml.CreateElement("GLOBALLIST")
[void] $list.SetAttribute("name", $GlobalList)
[void] $xml.DocumentElement.AppendChild($list)
$newList = $true
}
if ($PSCmdlet.ParameterSetName -eq "Rename list")
{
if($PSCmdlet.ShouldProcess($GlobalList, "Rename global list to $NewName"))
{
$list.SetAttribute("name", $NewName)
Import-TfsGlobalList -Xml $xml -Collection $Collection
Remove-TfsGlobalList -Name $GlobalList -Collection $Collection -Confirm:$false
}
return Get-TfsGlobalList -Name $NewName -Collection $Collection
}
foreach($item in $Add)
{
if (-not $newList)
{
# Checks if the element exists (prevents duplicates)
$existingItem = $list.SelectSingleNode("LISTITEM[@value='$item']")
if ($null -ne $existingItem) { continue }
}
if($PSCmdlet.ShouldProcess($GlobalList, "Add item '$item' to global list"))
{
$isDirty = $true
$itemElement = $xml.CreateElement("LISTITEM")
[void] $itemElement.SetAttribute("value", $item)
[void]$list.AppendChild($itemElement)
}
}
if (-not $newList)
{
foreach($item in $Remove)
{
$existingItem = $list.SelectSingleNode("LISTITEM[@value='$item']")
if ($existingItem -and $PSCmdlet.ShouldProcess($GlobalList, "Remove item '$item' from global list"))
{
$isDirty = $true
[void]$list.RemoveChild($existingItem)
}
}
}
# Saves the list back to TFS
if($isDirty)
{
Import-TfsGlobalList -Xml $xml -Collection $Collection -Force
}
return Get-TfsGlobalList -Name $GlobalList -Collection $Collection
}
}
@{
Description = 'This module contains cmdlets to mantain Team Foundation Server global lists'
ModuleVersion = '0.0.0'
RootModule = 'GlobalList.psm1'
PrivateData = @{
FriendlyName = 'Global Lists'
}
}
Function Get-TfsRestClient
{
[CmdletBinding()]
[OutputType('Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase')]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string]
$Type,
[Parameter()]
[object]
$Collection
)
Process
{
return _GetRestClient @PSBoundParameters
}
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
PS C:> <example usage>
Explanation of what the example does
.INPUTS
Inputs (if any)
.OUTPUTS
Output (if any)
.NOTES
General notes
#>
Function Invoke-TfsRestApi
{
[CmdletBinding()]
Param
(
[Parameter(Position=0, Mandatory=$true, ParameterSetName="Library call")]
[Alias("Name")]
[Alias("API")]
[string]
$Operation,
[Parameter(ParameterSetName="Library call")]
[Alias("Client")]
[Alias("Type")]
[string]
$ClientType,
[Parameter(ParameterSetName="Library call")]
[object[]]
$ArgumentList,
[Parameter(ParameterSetName="Library call")]
[string]
$ErrorMessage,
[Parameter(ParameterSetName="Library call")]
[object]
$Collection,
[Parameter()]
[switch]
$AsTask
)
End
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
$client = _GetRestClient $ClientType -Collection $tpc
$task = $client.$Operation.Invoke($ArgumentList)
if ($AsTask)
{
return $task
}
$result = $task.Result; if($task.IsFaulted) { throw $Message + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return $result
}
}
<#
.SYNOPSIS
Short description
.DESCRIPTION
Long description
.EXAMPLE
PS C:> <example usage>
Explanation of what the example does
.INPUTS
Inputs (if any)
.OUTPUTS
Output (if any)
.NOTES
General notes
#>
Function Get-TfsIdentity
{
[CmdletBinding()]
Param
(
[Parameter(Position=0,Mandatory=$true)]
[object]
$Identity,
[Parameter()]
[switch]
$QueryMembership,
[Parameter(ValueFromPipeline=$true)]
[object]
$Collection
)
Process
{
if ($Identity -is [Microsoft.VisualStudio.Services.Identity.Identity]) { _Log "Input item is of type Microsoft.VisualStudio.Services.Identity.Identity; returning input item immediately, without further processing."; return $Identity }
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
$client = _GetRestClient 'Microsoft.VisualStudio.Services.Identity.Client.IdentityHttpClient' -Collection $tpc
if($QueryMembership.IsPresent)
{
$qm = [Microsoft.VisualStudio.Services.Identity.QueryMembership]::Direct
}
else
{
$qm = [Microsoft.VisualStudio.Services.Identity.QueryMembership]::None
}
if(_TestGuid $Identity)
{
_Log "Finding identity with ID [$Identity] and QueryMembership=$qm"
$task = $client.ReadIdentityAsync([guid]$Identity); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving information from identity [$Identity]" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
else
{
_Log "Finding identity with account name [$Identity] and QueryMembership=$qm"
$task = $client.ReadIdentitiesAsync([Microsoft.VisualStudio.Services.Identity.IdentitySearchFilter]::AccountName, [string]$Identity, 'None', $qm); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving information from identity [$Identity]" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
return $result
}
}
md5: 80519367A8151440E8B3C4CD2D8BF9C8 | sha1: 8904E8F7755DB5DF07894C4A2DBB9028901BD0D2 | sha256: 5DFA652B6F95F1BB2FCD1388666E16D5E34290BE5903839708055AEAC76DBC3A | sha512: 31C7C535CD9BFB23553EAD5C566D51F34481A6AC53D4AE5924049D7899CADF239665B997B71D05BACE574B21FDC12A3306B4E559C5F004FC8D9AFE21CB79FFFD
md5: 3507317B404C0C4DED63BE80019AEF7E | sha1: 9491D0F9E622268052AE6FEF2639B995162FA068 | sha256: A5113FA6F67582631C8203DAF164CCCE5BC842597209DDBD9BBF0E54D94A0A37 | sha512: BC8A1778234DE2A865D879F2412B33A68671BC536811A9801ECCCEDBD8CD2E1092C084CC249D72C30BCFD3206E69901B5B0A163FEC976B312ECB2028A8BC5877
md5: A173BD8F903DF4C0622FCA18590F2EEA | sha1: F55504B1655BF1244878ECE7C0D3781D6E717B01 | sha256: A9B91AF8552ECF30785E46A782FDC9E87D7367C817BCFD9F45886A8CA7D80A12 | sha512: 96E81DA1A2E95D0492439658CA425C03B60A13C09A3418E6439D9CC6DA7FE1D97EF9EDE4F11106487873CBE3D027F9ADE42005167D6BD2438308A399FAD4C00F
md5: 562F424F78331CDEBF4B8A986AE90108 | sha1: 77CCDFEC42295E53EE40C00BBADF4D132F4F8ECB | sha256: 48F7BFEC411E09D89239694CCDDF719F8D58E7FF419C2970AE2E949C2008D3B3 | sha512: 465D1DAB773CDBB1028DFA2B236CC3E151EB74AB2C27BF2E2705A5D95D40F5D2373F73F0C8614A76E49F3D03AFDCB3CED0EE3F33798964CA9F76FBA951249D70
md5: D9067C9A7D93E30C31DF6254E6B4F919 | sha1: 8DECDFC6972A452C7660079A05E19DB75FCB776E | sha256: 47F008C0A3B7B0027E718B3F1D9E9C1219CE917A4DAD86558098F92C66B20640 | sha512: F28E9995CE52B4F12F881DE8266361C47F50342B8330A58F5D7511833FA5D75FB6D3A7E9B51490EB513FC5EC1D3B65A1A443B93CC104A6DA5FD13C9A404525A7
md5: FE7F68B3A4D8ABEED004E42EAD6161C3 | sha1: 101CC0073E98C4A0C1C63DEE0F96503C8227CC84 | sha256: 8A2FED0AA975857CFA03A2E06B649CE2ABA0521660A300D0347A2FCC51E606BB | sha512: 1C28CD6E582AE6E60A99110173B88EB00B55408C70E21B627DD4A2BD128E624EC480DC0D455D69778E4C0957F65241BA0C26B1B5AC6144CDC4C02982CD17D2F5
md5: 66DA4352F325FEA060BDA3F2C48BF5B1 | sha1: C893DE76B0E9B6BA2F341476B2DEAAEE21228D48 | sha256: C2CCE56EDF47414348C8FD76798931270BD754ECD01CE22B5DF8BA7841712169 | sha512: E5539BA7524851C15CC9386D041D75D67C9DBA579FA5B80DACE52B14C069AFF7718210CE161A5AEF45C0D953AFD99607AB3AC9336025194A14970FF754C8AAA8
md5: 095B76522ACF39C9DA549D8E627A843E | sha1: 4C2FA0FA69CF9D81E8FF951C8D471119A416FD10 | sha256: E6A39A0BE0CF95F73FDE2147D0631231C5D38FB3B3AC8E48DC94DD81F28C6E60 | sha512: 6D7FE767B06AAEB7118F3DD4CBD167BFCAFFD1290D57A9C908726E38DA6B6F08A500505D9A9F41750E7F523843BBBDB91DC8746332FF6D9259984A3447A76FBB
md5: 4E21226CAC9B627A0E8D0A625284229D | sha1: E39D333BA2F2875DF18E7727F03E8B984960A247 | sha256: 131C56E9B41CA6E30F7BE36A10E9C6A928C3F9110F19C7F71E596FC165EB7AE2 | sha512: C98AC2C2281035005CA43C8760F16A4129BB556874155F3A6834F0B0C56166A50F6D9C3CBDE527AA1FDF8E8A368920EE4735FEA860C912238A3B5AEA4BCB7D8B
md5: B1DF64773785BF3F479F022D329BA571 | sha1: 9C9B9B61B7CCDE94A5CEA3250CFF02C3563D6743 | sha256: AAA14E60FD885C582CDDF2E238DBE65515B7C3CA048B7178833E2941FF69481D | sha512: AB8BDFEB9DC2D4E08403841891392E020E0836F5C946D8537912B5AC64F89A10BB51393443785D2F8E5DFF59D78AA55A84FE2D0DBEEB2ABC06FFC9C02B54C8C5
md5: C4D3C7723CBCE3C62FEFC04BB401C7F3 | sha1: 239B1DAC5C215448EECB9D294557EF133EE93EBF | sha256: 51B8DB50ABE8B89A8595B8FE6C87EA4EAD04918FAF3EAAE93C5E513659DF4C2A | sha512: 39FCC1AA703873B2FB64D06D92D62637A6ABA5034E43B83E655B25A6DDA1CEF62E06C916655EFCA7768CE41DE39425533342387B1453E6C3BAD93F447F75240A
md5: D58B7340CE76EBAFE80DF1FEFD36C7ED | sha1: 6AFF4A8E7A5F896C0DBCD8FD839426ECE10D32E5 | sha256: 343AC0E5B3F4701E30A49F1D276574311AF3A363E2803B05277CEB92A7EDD8FB | sha512: 193F7D5E8B832EFB61BB364F34BCB12D3330A8923ED37C3CEFBA1FF9FFDF9B7EE7BB38DA518C8AED4E3FFE0FC03EEBEB26503D78159EE9665388A3B55AEA28C4
md5: 8535A0FFDFEE910AC269FC1131E76470 | sha1: BFBDB6D1F65F2FA83A161A3EE8A718CCFE769FA8 | sha256: 10CB0CE7D190062C5C7AFA605DE2965AFFEA9DAF74096AE15D4C47C6EC5CD605 | sha512: C6398D30C74C75C0DF9FDF632506B66AD894E40D583654D61F715D3FA37C8B3479C6A359A6473BBE99D2F1FACB058A78A723BB57BA5188842A0C9150B0AFE150
md5: 12CAEAD48009B54B27BEC9B88A9113F9 | sha1: 86DFB53623D5D80B60C1BE8D029C6919D03B9DEC | sha256: 1E7AB5626DA6EE3D9A0276DD4FAC1C0AE7E11092799913A78F8255B37C172C64 | sha512: F07FC9962D3E792141CF5846034817719FDF1E2DEB1E42DBF5EE5F9A3F060A7266A6118F8CE4294DA3CB4A518B988333896A1181E38377A562D0BCF9D83777E4
md5: 5FE03F8DF08BF8119CAA0C83D5065945 | sha1: 6F133D5369246C33424527727FB1BEA4930C8C84 | sha256: 1D97D8A5B162C1017BE29E945761F1685E3615D8306A7784BB49047622DA15D7 | sha512: FA873719B7C158A66063BB94F2F29EC6BB6F5DDDB1ACBB5C3A91ACA3C0E1A5DAF131F4F6224288A1E84B4124E9A5F22EC00FFBABDE7E60EAAD923BDB3A97986F
md5: 3DD62C06A2E00BDD34D2BF362E033174 | sha1: A15BB001D3E69B1570C96FE012B6D97DDBD26755 | sha256: DCDD58F859EEF9A1B8FFEE256821C6FA93F287E20B0D3F1E23AD0DE69F74E89F | sha512: C9935B84489533A940C1F1FBC78F65339EF56C85CE12B879D2FF9901AB658402A369576E6B9EEFCA03EC1672DA9F0AE0162D6019810C67BF2FBC4E6186E43E01
md5: EA55F17ACC26BDCCB2A4F0C9300C351E | sha1: 4020BBA6697EAEF8CDE19351BF575424B358EF3F | sha256: C664CB4827753C76072C951BB608A4E40EC199858795CE06A60C2FDCA7860385 | sha512: E75F763A87C72F09D6D7F565E9B5BCC367C5F2EE0B5D2A9D067C6B6EC9EC90195A5BED5C73A0DC020153C9E67CBAA2A07B1A6755C0A1619DD5431F24A5958F31
md5: 56CFAF2018EB8CAA6BBDAD375700B0FA | sha1: 5FAC6807C0B0E3C22D638D18C62AACE60DDB8806 | sha256: 753449134A0654BC6F95C35F50E8551E2F68FC28E32C4732857CB04EE221C177 | sha512: 26884AF8A76254AD132AEDF67EECF2A752A04848B65104E09D905C08F3017623347C97F3623ED3B2290CE69F4A48456F525302F745EF70A9D6B108E24E5BC2FA
md5: A6E5235F655B83653E434EB2D747128E | sha1: C662B3B9974203314B8186CB582E75C631316A20 | sha256: E9853776715297F98AF365668CE0E2538FEB5B3BF2D727F1FBCE9A9FF64AA17B | sha512: F131F3D37CAF82B636C919015D05536A901E13639C2709BD4F268B16354A930CA0B7BD1D4A986261E6A11D0DDCF9BB09C081B43AD74AB49315F74ABAC19EE285
md5: E5665D7BFD5E4F3A4B3CF17DB2B84C00 | sha1: 4F07DF25EDA37E8EA60EAE75FB4B2EC841795CAB | sha256: 6605E485608FFEA842E622AFD2D98D44E687C883EF21BC739EEE30323F689BA9 | sha512: 4ACA5329A0FE09C81CCF372D1410B4D3DD3E27CD7140FD0BD4CD2A745765E77BBCBA9F7E86C1F77BB6D201DEDCBBCEAF16791737A372202FCCDB4290E2BF84EE
md5: A8003F17A8C286B3E12EA3956A56DF65 | sha1: 560B502C603814FF14BB72355BD89C4CDA21A529 | sha256: D8E0421A9B52D973A55508B3FD147D431CE9687B0AFFD038E525F107D5D6FA4B | sha512: 5CD9709463E311AF2645F98D16F59C6A08C91A831F5D4A7F251517DE7A6D65D1AA5D1269CB90F34B3EAD46B31411C0BDB8BA8DBABEF18631BA3CFF26BBE0DDF0
md5: 4958632531AF3B043539CC631FAD1C50 | sha1: EA8A82BFE9CB7A0F12EF02929B9AFC2C3A77C87B | sha256: D414BDF5DF71725D3078AEA3E2E442224E384B0651C7860F0E98FC66CCD3DBB7 | sha512: 57A4CA2287F368F49A21F8BCD923B96E42389B0F546C82EE119AF7B19D1F522955B7E9CE735D16CBFE6CF11FF01FB7008F949F45EC87EEDF222025A25618273E
md5: C260C2E9096F70DD79C1D10F6EDBBFC3 | sha1: 6A742B457774804E647E59DA5052DCD6525D14DA | sha256: 249D53BB9B74A4E704A1E62A461781A8567C7B2E10C788DB8F65700FEB30C7FF | sha512: 05E4B10F0C0A119A5A2A830AC6A806F7B7286A3B39C9B978F0AEC4A8C0AD92C39A4FF94410E25E7439EA83574E5FD6389A7B504AC61C77E64AF4D0F3ABF4168B
md5: 2A34B9781B549F83599DE5807E3CC03B | sha1: DF64DB107072BC6D6670ED9065908903F26E1ED6 | sha256: 474AE277BC240A0675B34C9E61C917EB311AA9F2B301DC96A386FA750C5F6C20 | sha512: 461AB388B0A48B895411F39D174F0FFF52D052507F85F0162D14D93B4AA6895E7739B3AE814547E0BB4048CBF89BDB68FE93962F57B58635B58BFCA76A9BB3FA
md5: B500999BF0C3381ECBD533E030AED27F | sha1: C3722E01AD3C34FCE2D553A2112AA2E93CF530A4 | sha256: A2CC011BD17E27CFA9A03649AA0A8019E002AB9371CD43C05B7F0F2A979702EE | sha512: B20B94248C8DA79DE4F163E5484ECB4167FFA6BFA774B97E6A064F2D4E1A693CA7392B41821D7922099856B32169C60A25298A26B725B3B07BBE6B23EA868CCB
md5: C28983921FA421350D468731324F18F0 | sha1: 3E0D9FD991979DA599D939FD11F149725262E1C6 | sha256: 7361F75C9E274AA6D1B4744A02136A504E248D18FA1F4DBE9F6645A3FC1373F3 | sha512: A0D9A5BF002154253E6CEB190626CEFD57035DDCB45607CE21CB13E2B6F3DB273A39EBD0782E203FB6D1376C472F9D0E0BC9A2D73E790806A679B3E12863C6A8
md5: 47E7FD547105D705CAAB4CE252DF0D01 | sha1: 85AA71CB35E232B98FA3A223F73AB9E7C30DB467 | sha256: F791789F10F76A163A7ABC104D9557CDCADFD69D688F6443306EECC7B86E9672 | sha512: 66A4C73586C52000349F0445DF07FAA658161011AC3D15199C705DA17A6FAEED34DD24D18120399097DE560F868E083A70CEF414ADF0DF4A0FCFCE368E20730B
md5: E3D34258E0DEABC4BD1D3C941081F28D | sha1: 4011F02D2F1893A767CDDA0B289779A51D42978E | sha256: 4E5B4A78C30AA75BB65E5AF40FD9404619B73C5E38585D4D89D65A5446929F71 | sha512: 2FD2EC5D19C3E3EFEE36D04FCB9FA2A3A3727C802BD81A70EA57E473ECE8171DE31A0D8184CAE7BF8445075924CBA6C22EE80F355EB475915D4358C877D9BFB3
md5: 7F5D108617BB011E76A8788E33A50D7F | sha1: BD7B1C120C2DFFCC45C5261562DB833AAB8C0802 | sha256: 4BE42F34898BEB8ABB0488E804535A92331567EE3ACC7194CFF6D1F81B43C06F | sha512: C827AF4CA46F9F802CBEDFADDFFD81453AA6FE74618AB12174200FBEB67F21232B7D0B9F04BDAAC7BBC760B6CE1E27DAD8C4878E78630D62DA5D66071B135542
md5: 1F71DDD0D210EB53DA2B6B35017FBA44 | sha1: 8BEDE858EA907FE81EE45E9CE91AE3F0965345A4 | sha256: 592CDC736AAD1B2DAD796358B829666408770741BF526C1C644AE008E5428CB1 | sha512: FA7FF1CE999EEC57F40DD234EA9F488950D054E52712DC6BB1DCC5473A4F05F00E07D63A2BD046F7B824DF80E05026844454A9E2B096570B1AABD44EE848F81E
md5: A413E40D9B8C0422EBD97453EB451564 | sha1: 7F0C9CA4EBEBF9E7EA2A81AE575A17569EB71F50 | sha256: B6F882985010BBE9BC12D421A04090E4400B884938447B4609F56FA90A1D58E8 | sha512: 626683C1CA7DE788F7E97E329CA701CF82F643FBD7FFA05D6E6301C6784FEFB03F9762D3F8353D3DE3B980FDBCDE093E65F771FEF11D02E5D255647CBE482EF8
md5: DC3A490D3B3B810F92778268FC6D0663 | sha1: A61B0742E9A6789BA37E5832438E562758FFB964 | sha256: A9CE50D30A21D9D77F18BE47BB44B6BE3BEC3127ABA0F4F2165AAF8CC1A46227 | sha512: E5F28D274DA40D245B81968A4083E5CD5C30F9FA25782407C93A2691E2C6F0E10A4CAF53C259A9EDF7EB8EAA30E53974D91C9368B7F3236ACADD44FC6CA52BB4
md5: 50C3E618A6E345C69FDF030853FCF146 | sha1: 0E781EF00EFF8FC0C524266CB81C31C44251681B | sha256: 293E446B58D577EAFB6304B04D499CF6B0ED15677124D67F56F388CABD22352B | sha512: D5954DBDC791ECE790332F81F805913BC8DEE461635D477EB1215F4A11A83958C5616FCEA194083C01B9BEE646D88CFD2CD68DCD7D27A2D111DF65610574AFF2
md5: 819E40858E0F4E5EF2D1BC77571691D4 | sha1: 09515D7BA79F32A33F858BA3DD269B8CB6582953 | sha256: 96E9A23BF3A2DE299884B8986FA1D2C5CD642CBE1B417CCA7E77C1FDB3D9C2C6 | sha512: 12CE656FE6C0F198365B8D29EFE7AE42681151D125C9F1A0B931A7D31347E04F9E3B159530044AEBF7316959E9172B86667EC45175772360FC2C6F67C977EB04
md5: 2D8B3EEEFA6B6BABF1A4C8BC268A9039 | sha1: 2FBAE46D4BC388C77B79977D351CC23F9F4662CC | sha256: B786D641283B1A3F39EFDEF1C7C11DCD5AEA52B0A404F4322B70EF66B5F7D700 | sha512: A7A074C4555C9E13749D1F9842FAA17B5E88C6646D5D5CD84A1F6D6DD3E29B7D76C060401ED2169843F3F8E95CE591292DE32B9B373690D5F0D51C21018FD329
md5: 8B704F35928C9EABA9790D18A422DB12 | sha1: 730F04CB2A8B26E38362FD469E4765E862CFA3B3 | sha256: 43AAD918447FD770B01C59FD59B53128EDD2C5A1E5E6EF96B1834C294F62131B | sha512: 8B95F5D3DF4EFC207C808C8047D907A994D1CF1C37C52016E8C526E980033F4863FA830610745177E2689E0FC16DB497FEB52073793B800F663C6F6CB29F3590
md5: B8CDC0A685A53786503D79F62451BFD3 | sha1: 689C58646C87DAAFDBD3EF8867BB3DE884ABEB83 | sha256: E02F5894CBF05B426E3FA565822CB16F35BE471CE896DE9DF94B2AF71D4ADB72 | sha512: 0B5BD9C0A6BD60B113AECA5CAC866302F169764FADE771A0ABA0705EB3C7591FDC94C571979460EEBB70744D212787BFA4232EAA9A157CE2186527F99E359C13
md5: EFDD6854814D24CDCDA4F630C9FED31A | sha1: BC8377AF3302428C9391147F5B2D76E691F0C0DF | sha256: 3F4C00FF172F3B02C9A5ADD74E09B73A6230BC5543D1ED2C7FC9CA35CDA4746E | sha512: 4AF804EAE8D46460E988670C9BAD2B04AED833C42079BE7EE7DF0E227F9F0D146217B788D92C0C7AA18EE48A7648DD0D6552297889FD430C8073D4106665EB39
md5: EAF42C31094DEB3C47FD4A7C94ED8D89 | sha1: 02D25D4ABBF3F4A4B41B9910EFB903BB5590349A | sha256: DCDDB0CA878BB4C9C131C2CAAD1862125CDB55E2E3629562FDA5A601D372B094 | sha512: 2142BE69942FC220ECFF0B4C3C64CADF14B4C86E3CD22396ACFB151FB0A0E2D0CDB75850F448804B89E8AF8DD81D3D8BBC5B7139B1CD51871E4223091BFB4D17
md5: 10207B37C4BAAAF4A07B578AB75C5DD8 | sha1: 547E8E21E246AF890953521C7403015F6D211B49 | sha256: 1FE5BD860623C44FA0204FE5A99073125BF55FC6AC9C94AA12A3FB67DBA8F00D | sha512: 463263C8D542AED5FB234E9D0AD1B3DF184E3EB6B236985B8482105FD783116E4A2414F6AFD5A6FE38474F1F613536080BAEFA2654DBDBF0CD3B02C94B1ABA0B
md5: 81908C18C1CFBDF7BA064718BF5D674B | sha1: C70DF1CAFA171899797434DB5E4442ADEFFC0CA3 | sha256: 0F886E8F3F1F3327083534C3260E4C4728EC7F3D7F325E572F63EC0F61D17320 | sha512: 45667994FA7AC1AD9426EF932094EC2AD58CFDD462BBCB3F275DA783874E61D33B546BB7991013B7778BE5D5F510B42BF9712DACB3529D027C5B87FD308A5055
md5: 5A2F3EEF15F3517AA970A2F43976AC60 | sha1: D3837B2882637689910A9766A387AB8F39B9E7A3 | sha256: 90B28CCEA30A95C99164C15C27FCA223921D45D72778459D74D72DAC7C2A5B56 | sha512: 3E696F527033CD542307A811B699D209257E40623B023836BAB7B298F5632EC5C1A7ABA38EC7AFF55FBCEA177F10B47A0B6B47D8B14A45F7A6F553F3EAF28CF5
md5: BA37627CDFDBDCC442F48AFDCAA6811A | sha1: 4F44326C57B4A84B90D4E6E57A863BED0221ED69 | sha256: 88291AF7D1B54B4231FDEB403DAAA9A32391A673C043B81AC6F867C1B1AE352B | sha512: 7B18EAF7B75B8E2679DDC4F109E3BCDD0167E1ECBA9652EA656FD0C0EBD0F6A8531F0F22404C1FB201FC82B4CF49E0B926C5A1B7A56A18041650712F866B147C
md5: 1598B6C5386F0F26DCF64A07A8A1D2B7 | sha1: EDEBE946D24244D3CED0753C03B78384B2524599 | sha256: A9591361304E8889698D28280E8AA2F5AF2DED77C7FCA69E8E24AA14E98DB223 | sha512: 6ED0D3961117D951BC572D06024AAEF96A1A0678FB8A2C82E6E2151FC09DCCBD11A5E56003B6BA771C2F1359C689DEEECA7EC9508D3E59DB0B5581B658C6C9B9
md5: E2B61A5EACA36367B20926D360297AD9 | sha1: E3460011A507FD1953CC68FBB42A99191ED41AE1 | sha256: 823A9AFB6B1647A292E96A24805EE19C4FBC34759CC8911861C86FC04E33EA80 | sha512: 8A8FBC70F8F77FDD5B77B2D2B318A2D9C6B505DA2B20D5391E83F05CCF8BEAFD95E0D6991833715D1A16F376F7041CB2F8683644EE2BDAD7DAD695CFE42E0D4C
md5: FCA4B1CE2724A487025705355ABF74A7 | sha1: C536E919E0BD6529FBD0D9E3B24A0B1F453CC88E | sha256: AE2147DE3864B337767711772C8B15D33B4EDF5A8970FE64816DD8322710C347 | sha512: F33058F0EB12557DDF02C3A2D3329A93E8DD654B1100DBD8127E5D4A6AE8F1F7B926C9C93E013B0B3BA0BB846A1F75F6B759575DB106B9C10CB0CB02CC39A930
md5: F860586F9DC1D1CD6D02437B618E2FDF | sha1: FCFE18AB9B7E22BD3B55E551C49B89390C39EA54 | sha256: 4C4699D90FA72FCBEC2A6F4B5DC0352EE3363892996ADD1980ECEFAEB08187A8 | sha512: D0EE9F8FF3D7C58AFBB92A52461B05A42D5DB2BF7FECABFF5A41FEAC6ADDAAF92112B89DE4818DC781631FC611C958831CB5245691C47E51D7C0919072734DED
md5: 07BDB928520AF4D376A35E9AC8A92A93 | sha1: B3A0BBB7CEA3259F33FC87A7A741FBB932F2F491 | sha256: 3588873756C2CABF5009FA571DB47DE1D69932890CEE903FA785378CE56B14A1 | sha512: A1CF5D0F1744D9BA6F7F7BECC16C3FFBC6AAE93B1C5ECAB97F0913F2D2B6571640237FD54223BA8F204EA826240D3DD4EFD6262E997C4309AE78272C43DBD192
md5: 16F7009B2417C3FCE6A37F3D000EB9B2 | sha1: CF5456CDBA015327D9A993C9C6BAD05A89C3DF42 | sha256: 385970F99134535EE05A514D864B09E106A93BEC19F1F0C7BFD820D6066F8EF3 | sha512: B0AD52B3327ED0AD76201EC09A100C8B13DBA4205B6431F28823CE2B983BAD20CA425010A5E6E852340E8975B16CFCB24E4DCE3AC6C74A7678C40E8B52D4F47D
md5: 7E96A7E1D9ECCD2A9029AC6150D1BD39 | sha1: 31EEE0BD3AF6C94320BC84DE1112D17EDA69E1FF | sha256: A92EB9BC07F920BFC4841EBC16D19E2FAA45FB340C516ECB86D7E6A2652A6674 | sha512: C80A57F3DDC13EA0E0757911B00AE3155CC671E92ACE4E23B8CD6FCE14623E069AAD6CD0D82A529B82953406A4AB6165FFA489D95C7B430CE6B4DB613EE53831
md5: 3AE1AE10726CD0102C4A85B07030D3B7 | sha1: AC72F6283FB5683F98D30CD6174F162BEF04ECEA | sha256: 6283B6D507880481193CF64028747AA6731598D11B15E4AAE1A794961A5CCA5B | sha512: E2D6C3359872CFE6480F7BD226E2368AE27A24A1F01A98F2B78B29A6815E9C80C2AC790823CA292438C8E959177989968A41ACF9DDF200C9888065F1ACE1C14F
md5: D0A00CC544F89F271D2A48ED9B94F38A | sha1: 5D595582FA73166FEC1658D65D7991629B54820B | sha256: DE94137B22330F0575731BA771EB49CE60655B515C839C78A92E9BCDC0C98F52 | sha512: 69250F1A85C1A1FB4055779DD9EBB6848D76F30BB510D775C9BB5BD43F931393400BE8D6BFDCD795DEAEFAAD1E561CEBF7C7D6FE300FC420C31B096718D5A04B
md5: 07E04FD870CEE6F9994921B5AF243B7F | sha1: 0EA4611EEEE3736963CB718132099624BFEBF460 | sha256: 52CC6DDF77990FBAAAE4DB593F655610652133CEEADB32262C122D8C9EEA1BAD | sha512: 4639A7F77F7A9CAFA38C632332DD5085355623F3D84475374241A64BD110569F504086B479B519E90DDBD471D4A5034239418EBC03277424212E0E6698E64418
md5: 7D9196611D99181E8290484222F62E2C | sha1: 63ABE53F6591F475A06A03DE88E5D190C5FB1C8C | sha256: 6024102A8A0CF02357CDD0AC5F574069EE335A19E9467B3E1DE0F47348CE8354 | sha512: CC5E8467C5B387C0D2420EB5D60279DD93682DD7CA4B594BF5C9FF8136AE7F935AB9EE85AC6CBD832243FC65AA36D7725720C9CF3B3CEE19312D220DB7F95059
md5: 589E1B764C0DC53BF645054960626AB1 | sha1: A5616537CA4E4AD5EB0BEB48863AE65E9EA91080 | sha256: 1C7FA94DE5E727852934387B6B0094ABC16F660C6C91B38FB3F5BC580CFBDC1F | sha512: DFD6924DD7BAF7EB1B8D3CC862FD7FB4A311818EE5684C7A85E3106EAD0F3DAE2A79956AAD9B5404C88A1D2607CAD627D0EFD729E9A9C1C1425B907884FBD1D7
md5: 1982B5586DE16B532074211AB7DA1CA6 | sha1: ED3E73BA41910D32618EBBB5E82BF9E74B51B062 | sha256: A47387C4A098DF3A57B967F1FF8604C7578F75B1481B2B969DF68DCEEF83ADFA | sha512: CBFFC5946773805EC1AE610C222EC8ABC65E39D561BD7E8CC98DC86655C218B5BD0CC15896D1F63FB061E493D7E5B88F26CF41FB5FAA24C4C754ADDE3792FC2B
md5: C3138D9BC26BCD3D225F551ED8C41792 | sha1: 60E5E95F4D0B06978636760F3375D6E23B28530B | sha256: ACEE4E07C74C6E0E10CFD25111D1E2E6A213EF6DB97449551C0E665250C5C3E9 | sha512: 3B8F4974E8755D4875DA125F2F04B7916C4B1F555E033E02A566F6037AC9A642CFFA4F5F36C83310223C41E1F1F44156C1763F241E7167D3E8CAB6F1A84D3177
md5: CA5D421B2E6F5220026702A1AFB7D6B0 | sha1: 3439213DA9870DBCEF63EFAF9F565DC20C6E5F98 | sha256: 36CCF5CF12AC7DB2EE8AAEEC7954C0B3527A9999A24BDDC998CB185033ECCEDC | sha512: EC8D537031FA4D427D6F6EE34CF54E5166CEB337185CAF446A9121903C47532DE483CDCAD8A992F4551B6358C5A836ED36108533B5861804DB5C8929B3B6BFD3
Function Get-AzDevOrganization
{
[CmdletBinding(DefaultParameterSetName='Get by collection')]
[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Position=0, ParameterSetName="Get by organization")]
[object]
$Organization,
[Parameter(Position=0, ParameterSetName="Get current")]
[switch]
$Current,
[Parameter(ParameterSetName="Get by collection")]
[object]
$Credential
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi'
}
Process
{
if ($Current)
{
return $script:AzDevOrganizationConnection
}
}
}
<#
.SYNOPSIS
Gets information from one or more Git repositories in a team project.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsPolicyType
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Policy.WebApi.PolicyType')]
Param
(
[Parameter()]
[SupportsWildcards()]
[Alias("Name")]
[object]
$Type = '*',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Policy.WebApi'
}
Process
{
if ($Type -is [Microsoft.TeamFoundation.Policy.WebApi.PolicyType]) { _Log "Input item is of type Microsoft.TeamFoundation.Policy.WebApi.PolicyType; returning input item immediately, without further processing."; return $Type }
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Policy.WebApi.PolicyHttpClient' -Collection $tpc
$task = $client.GetPolicyTypesAsync($tp.Name); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving policy types" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return $result | Where-Object Display -Like $PolicyType
}
}
<#
.SYNOPSIS
Exports a process template definition to disk.
.DESCRIPTION
This cmdlet offers a functional replacement to the "Export Process Template" feature found in Team Explorer. All files pertaining to the specified process template (work item defininitons, reports, saved queries, process configuration and so on) are downloaded from the given Team Project Collection and saved in a local directory, preserving the directory structure required to later re-import it. This is specially handy to do small changes to a process template or to create a new process template based on an existing one.
.PARAMETER Process
Name of the process template to be exported. Wildcards supported.
.PARAMETER DestinationPath
Path to the target directory where the exported process template (and related files) will be saved.
.PARAMETER NewName
Saves the exported process template with a new name. Useful when exporting a base template which will be used as a basis for a new process template.
.PARAMETER NewDescription
Saves the exported process template with a new description. Useful when exporting a base template which will be used as a basis for a new process template.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.EXAMPLE
Export-TfsProcessTemplate -Process 'Scrum' -DestinationPath C:\PT -Collection http://vsalm:8080/tfs/DefaultCollection
Exports the Scrum process template from the DefaultCollection project collection in the VSALM server, saving the template files to the C:\PT\Scrum directory in the local computer.
.EXAMPLE
Export-TfsProcessTemplate -Process 'Scrum' -DestinationPath C:\PT -Collection http://vsalm:8080/tfs/DefaultCollection -NewName 'MyScrum' -NewDescription 'A customized version of the Scrum process template'
Exports the Scrum process template from the DefaultCollection project collection in the VSALM server, saving the template files to the C:\PT\MyScrum directory in the local computer. Notice that the process template is being renamed from Scrum to MyScrum, so that it can be later reimported as a new process template instead of overwriting the original one.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Export-TfsProcessTemplate
{
[CmdletBinding()]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[object]
$Process = "*",
[Parameter(Mandatory=$true)]
[string]
$DestinationPath,
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
$NewName,
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
$NewDescription,
[Parameter(ValueFromPipeline=$true)]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection $Collection
$processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")
if ($Process -is [Microsoft.TeamFoundation.Server.TemplateHeader])
{
$templates = @($Process)
}
else
{
$templates = Get-TfsProcessTemplate $Process -Collection $Collection
}
if ($NewName -or $NewDescription)
{
$templates = $templates | Select-Object -First 1
}
foreach($template in $templates)
{
if ($NewName)
{
$templateName = $NewName
}
else
{
$templateName = $template.Name
}
$tempFile = $processTemplateSvc.GetTemplateData($template.TemplateId)
$zipFile = "$tempFile.zip"
Rename-Item -Path $tempFile -NewName (Split-Path $zipFile -Leaf)
$outDir = Join-Path $DestinationPath $templateName
New-Item $outDir -ItemType Directory -Force | Out-Null
Expand-Archive -Path $zipFile -DestinationPath $outDir
if ($NewName -or $NewDescription)
{
$ptFile = (Join-Path $outDir "ProcessTemplate.xml")
$ptXml = [xml] (Get-Content $ptFile)
if ($NewName)
{
$ptXml.ProcessTemplate.metadata.name = $NewName
}
if ($NewDescription)
{
$ptXml.ProcessTemplate.metadata.description = $NewDescription
}
$ptXml.Save($ptFile)
}
Remove-Item $zipFile
}
}
}
<#
.SYNOPSIS
Gets information from one or more process templates.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Get-TfsProcessTemplate
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Server.TemplateHeader')]
Param
(
[Parameter(Position=0)]
[Alias('Name')]
[SupportsWildcards()]
[string]
$ProcessTemplate = "*",
[Parameter(ValueFromPipeline=$true)]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection $Collection
$processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")
$templateHeaders = $processTemplateSvc.TemplateHeaders() | Where-Object Name -Like $ProcessTemplate
foreach($templateHeader in $templateHeaders)
{
$templateHeader | Add-Member Collection $tpc.DisplayName -PassThru
}
}
}
<#
.SYNOPSIS
Imports a process template definition from disk.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function Import-TfsProcessTemplate
{
[CmdletBinding(ConfirmImpact='Medium')]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[ValidateScript({Test-Path $_ -PathType Container})]
[string]
$SourcePath,
[Parameter()]
[ValidateSet("Visible")]
[string]
$State = "Visible",
[Parameter()]
[object]
$Collection
)
Process
{
if (-Not (Test-Path (Join-Path $SourcePath "ProcessTemplate.xml")))
{
throw "Invalid path. Source path ""$SourcePath"" must be a directory and must contain a file named ProcessTemplate.xml."
}
$tpc = Get-TfsTeamProjectCollection $Collection
$processTemplateSvc = $tpc.GetService([type]"Microsoft.TeamFoundation.Server.IProcessTemplates")
$tempFile = New-TemporaryFile
$zipFile = "$tempFile.zip"
Rename-Item $tempFile -NewName (Split-Path $zipFile -Leaf)
Compress-Archive -Path "$SourcePath/**" -DestinationPath $zipFile -Force
$ptFile = (Join-Path $SourcePath "ProcessTemplate.xml")
$ptXml = [xml] (Get-Content $ptFile)
$name = $ptXml.ProcessTemplate.metadata.name
$description = $ptXml.ProcessTemplate.metadata.description
$metadata = $ptXml.ProcessTemplate.metadata.OuterXml
$processTemplateSvc.AddUpdateTemplate($name, $description, $metadata, $State, $zipFile);
Remove-Item $zipFile
}
}
@{
Description = 'This module contains cmdlets to support administration of Team Foundation Server process templates'
ModuleVersion = '0.0.0'
RootModule = 'ProcessTemplate.psm1'
PrivateData = @{
FriendlyName = 'Process Templates'
}
}
Function Prompt
{
Process
{
$promptPrefix = 'AzDev'
$tfsPrompt = ''
if ($script:TfsServerConnection)
{
$tfsPrompt = $script:TfsServerConnection.Name
if ($tfsPrompt -like '*.visualstudio.com')
{
$promptPrefix = 'AzDev Services'
$tfsPrompt = $tfsPrompt.SubString(0, $tfsPrompt.IndexOf('.'))
}
elseif ($tfsPrompt -like 'dev.azure.com/*')
{
$promptPrefix = 'AzDev Services'
$tfsPrompt = $tfsPrompt.SubString($tfsPrompt.IndexOf('/'))
}
else
{
$promptPrefix = 'AzDev Server'
if ($script:TfsTpcConnection)
{
$tfsPrompt += "/$($script:TfsTpcConnection.Name)"
}
if ($script:TfsProjectConnection)
{
$tfsPrompt += "/$($script:TfsProjectConnection.Name)"
}
if ($script:TfsTeamConnection)
{
$tfsPrompt += "/$($script:TfsTeamConnection.Name)"
}
}
$tfsPrompt = "[$tfsPrompt] "
}
"$promptPrefix $($tfsPrompt)$($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
}
}
Function Get-TfsServiceHookConsumer
{
[Cmdletbinding()]
[OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Consumer')]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias('Name')]
[Alias('Id')]
[string]
$Consumer = '*',
[Parameter()]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc
$client.GetConsumersAsync().Result | Where-Object {($_Name -Like $Consumer) -or ($_.Id -Like $Consumer)}
}
}
Function Get-TfsServiceHookNotificationHistory
{
Param
(
[Parameter(Position=0, ValueFromPipeline=$true, Mandatory=$true)]
[object]
$Subscription,
[Parameter()]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc
if ($Subscription -is [Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Subscription])
{
$Subscription = $Subscription.Id
}
$client.GetNotifications([guid] $Subscription, $null, $null, $null, $null) | Select-Object -ExpandProperty Result
}
}
Function Get-TfsServiceHookPublisher
{
[Cmdletbinding()]
[OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Publisher')]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias('Name')]
[Alias('Id')]
[string]
$Publisher = '*',
[Parameter()]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc
$client.GetPublishersAsync().Result | Where-Object {($_Name -Like $Publisher) -or ($_.Id -Like $Publisher)}
}
}
Function Get-TfsServiceHookSubscription
{
[Cmdletbinding()]
[OutputType('Microsoft.VisualStudio.Services.ServiceHooks.WebApi.Subscription')]
Param
(
[Parameter(Position=0)]
[Alias('Name')]
[string]
$Subscription = '*',
[Parameter()]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$client = _GetRestClient -Type 'Microsoft.VisualStudio.Services.ServiceHooks.WebApi.ServiceHooksPublisherHttpClient' -Collection $tpc
$client.QuerySubscriptionsAsync().Result
}
}
# Initialize Shell
if ($Host.UI.RawUI.WindowTitle -match "(Azure DevOps Shell*)|(Team Foundation Server Shell*)")
{
# SetConsoleColors
$Host.UI.RawUI.BackgroundColor = "DarkMagenta"
$Host.UI.RawUI.ForegroundColor = "White"
Clear-Host
# ShowBanner
$module = Test-ModuleManifest -Path (Join-Path $PSScriptRoot 'TfsCmdlets.psd1')
Write-Host "TfsCmdlets: $($module.Description)"
Write-Host "Version $($module.PrivateData.Build)"
Write-Host ""
. (Join-Path $PSScriptRoot 'Prompt.ps1')
}
<#
.SYNOPSIS
Gets information about one or more teams.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsTeam
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')]
param
(
[Parameter(Position=0)]
[Alias("Name")]
[SupportsWildcards()]
[object]
$Team = '*',
[Parameter()]
[switch]
$IncludeMembers,
[Parameter()]
[switch]
$IncludeSettings,
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
}
Process
{
if ($Team -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam]) { _Log "Input item is of type Microsoft.TeamFoundation.Core.WebApi.WebApiTeam; returning input item immediately, without further processing."; return $Team }
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TeamHttpClient' -Collection $tpc
$workClient = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient'
if($Team.ToString().Contains('*'))
{
_Log "Get all teams matching '$Team'"
$teams = $client.GetTeamsAsync($tp.Name).Result | Where-Object Name -like $Team
}
else
{
_Log "Get team named '$Team'"
if(_TestGuid $Team)
{
$Team = [guid]$Team
}
$teams = $client.GetTeamAsync($tp.Name, $Team).Result
}
foreach($t in $teams)
{
if ($IncludeMembers.IsPresent)
{
_Log "Retrieving team membership information for team '$($t.Name)'"
$members = $client.GetTeamMembersWithExtendedPropertiesAsync($tp.Name, $t.Name).Result
$t | Add-Member -Name 'Members' -MemberType NoteProperty -Value $members
}
else
{
$t | Add-Member -Name 'Members' -MemberType NoteProperty -Value @()
}
if ($IncludeSettings.IsPresent)
{
_Log "Retrieving team settings for team '$($t.Name)'"
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name
$t | Add-Member -Name 'Settings' -MemberType NoteProperty -Value $workClient.GetTeamSettingsAsync($ctx).Result
}
else
{
$t | Add-Member -Name 'Settings' -MemberType NoteProperty -Value $null
}
}
return $teams
}
}
<#
.SYNOPSIS
Creates a new team.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.INPUTS
System.String
#>
Function New-TfsTeam
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')]
param
(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[Alias("Name")]
[string]
$Team,
[Parameter()]
[string]
$Description,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
}
Process
{
if (-not $PSCmdlet.ShouldProcess($Project, "Create team $Team"))
{
return
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TeamHttpClient'
$result = $client.CreateTeamAsync((New-Object 'Microsoft.TeamFoundation.Core.WebApi.WebApiTeam' -Property @{
Name = $Team
Description = $Description
}), $tp.Name).Result
if ($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Deletes a team.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TeamFoundationTeam
System.String
#>
Function Remove-TfsTeam
{
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
[OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTeam')]
param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[Alias("Name")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])})]
[SupportsWildcards()]
[object]
$Team = '*',
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($Team.ProjectName) {$Project = $Team.ProjectName}; $tpc = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tp = $tpc.Store.TeamProjectCollection
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection
if (-not $PSCmdlet.ShouldProcess($t.Name, 'Delete team'))
{
return
}
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TeamHttpClient'
$task = $client.DeleteTeamAsync($tp.Name, $t.Name)
$result = $task.Result; if($task.IsFaulted) { throw 'Error deleting team' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
}
<#
.SYNOPSIS
Renames a team.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TeamFoundationTeam
System.String
#>
Function Rename-TfsTeam
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.Client.TeamFoundationTeam')]
param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[Alias("Name")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Client.TeamFoundationTeam])})]
[SupportsWildcards()]
[object]
$Team = '*',
[Parameter()]
[string]
$NewName,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$result = Set-TfsTeam -Team $Team -NewName $NewName -Project $Project -Collection $Collection
if ($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Changes the details of a team.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTeam
System.String
#>
Function Set-TfsTeam
{
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")]
[OutputType('Microsoft.TeamFoundation.Client.TeamFoundationTeam')]
param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[Alias("Name")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])})]
[SupportsWildcards()]
[object]
$Team = '*',
[Parameter()]
[switch]
$Default,
[Parameter()]
[string]
$NewName,
[Parameter()]
[string]
$Description,
[Parameter()]
[Alias('TeamFieldValue')]
[string]
$DefaultAreaPath,
[Parameter()]
[hashtable]
$AreaPaths,
[Parameter()]
[string]
$BacklogIteration,
[Parameter()]
[object]
$IterationPaths,
# Default iteration macro
[Parameter()]
[string]
$DefaultIterationMacro, #= '@CurrentIteration'
# Working Days. Defaults to Monday thru Friday
[Parameter()]
[string[]]
$WorkingDays, #= @("monday", "tuesday", "wednesday", "thursday", "friday"),
# Bugs behavior
[Parameter()]
[ValidateSet('AsTasks', 'AsRequirements', 'Off')]
[string]
$BugsBehavior,
[Parameter()]
[hashtable]
$BacklogVisibilities,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
}
Process
{
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection
if ($Project)
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$tpc = $tp.Store.TeamProjectCollection
}
else
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
}
$teamService = $tpc.GetService([type]'Microsoft.TeamFoundation.Client.TfsTeamService')
if ($NewName -and $PSCmdlet.ShouldProcess($Team, "Rename team to '$NewName'"))
{
$isDirty = $true
$t.Name = $NewName
}
if ($PSBoundParameters.ContainsKey('Description') -and $PSCmdlet.ShouldProcess($Team, "Set team's description to '$Description'"))
{
$isDirty = $true
$t.Description = $Description
}
if ($Default -and $PSCmdlet.ShouldProcess($Team, "Set team to project's default team"))
{
$teamService.SetDefaultTeam($t)
}
if($isDirty)
{
$teamService.UpdateTeam($t)
}
# Prepare for the second stage
$client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList @($tp.Name, $t.Name)
# Set Team Field and Area Path settings
$patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValuesPatch'
if($DefaultAreaPath -and $PSCmdlet.ShouldProcess($Team, "Set the team's default area path (team field value in TFS) to $DefaultAreaPath"))
{
if($tpc.IsHostedServer)
{
_Log "Conected to Azure DevOps Server. Treating Team Field Value as Area Path"
$DefaultAreaPath = _NormalizeCssNodePath -Project $tp.Name -Path $DefaultAreaPath -IncludeTeamProject
}
if(-not $AreaPaths)
{
_Log "AreaPaths is empty. Adding DefaultAreaPath (TeamFieldValue) to AreaPaths as default value."
$AreaPaths = @{ $DefaultAreaPath = $true }
}
_Log "Setting default area path (team field) to $DefaultAreaPath"
$patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValuesPatch' -Property @{
DefaultValue = $DefaultAreaPath
}
$values = @()
foreach($a in $AreaPaths.GetEnumerator())
{
$values += New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamFieldValue' -Property @{
Value = _NormalizeCssNodePath -Project $tp.Name -Path $a.Key -IncludeTeamProject
IncludeChildren = $a.Value
}
}
$patch.Values = [Microsoft.TeamFoundation.Work.WebApi.TeamFieldValue[]] $values
$task = $client.UpdateTeamFieldValuesAsync($patch, $ctx)
$result = $task.Result; if($task.IsFaulted) { throw 'Error applying team field value and/or area path settings' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
# Set backlog and iteration path settings
$patch = New-Object 'Microsoft.TeamFoundation.Work.WebApi.TeamSettingsPatch'
$isDirty = $false
if ($BacklogIteration -and $PSCmdlet.ShouldProcess($Team, "Set the team's backlog iteration to $BacklogIteration"))
{
_Log "Setting backlog iteration to $BacklogIteration"
$iteration = Get-TfsIteration -Iteration $BacklogIteration -Project $Project -Collection $Collection
$patch.BacklogIteration = [guid] $iteration.Id
$patch.DefaultIteration = [guid] $iteration.Id
$isDirty = $true
}
if ($DefaultIteration -and $PSCmdlet.ShouldProcess($Team, "Set the team's default iteration to $DefaultIteration"))
{
_Log "Setting default iteration to $DefaultIteration"
$iteration = Get-TfsIteration -Iteration $BacklogIteration -Project $Project -Collection $Collection
$patch.DefaultIteration = [guid] $iteration.Id
$isDirty = $true
}
if ($BacklogVisibilities -and $PSCmdlet.ShouldProcess($Team, "Set the team's backlog visibilities to $(_DumpObj $BacklogVisibilities)"))
{
_Log "Setting backlog iteration to $BacklogVisibilities"
$patch.BacklogVisibilities = _NewDictionary @([string], [bool]) $BacklogVisibilities
$isDirty = $true
}
if ($DefaultIterationMacro -and $PSCmdlet.ShouldProcess($Team, "Set the team's default iteration macro to $DefaultIterationMacro"))
{
_Log "Setting default iteration macro to $DefaultIterationMacro"
$patch.DefaultIterationMacro = $DefaultIterationMacro
$isDirty = $true
}
if ($WorkingDays -and $PSCmdlet.ShouldProcess($Team, "Set the team's working days to $(_DumpObj $WorkingDays)"))
{
_Log "Setting working days to $($WorkingDays|ConvertTo=-Json -Compress)"
$patch.WorkingDays = $WorkingDays
$isDirty = $true
}
if($BugsBehavior -and $PSCmdlet.ShouldProcess($Team, "Set the team's bugs behavior to $(_DumpObj $BugsBehavior)"))
{
_Log "Setting bugs behavior to $(_DumpObj $BugsBehavior)"
$patch.BugsBehavior = $BugsBehavior
$isDirty = $true
}
if($isDirty)
{
$task = $client.UpdateTeamSettingsAsync($patch, $ctx)
$result = $task.Result; if($task.IsFaulted) { throw 'Error applying iteration settings' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
if($Passthru.IsPresent)
{
return $t
}
}
}
@{
Description = 'This module contains cmdlets to maintain Teams'
ModuleVersion = '0.0.0'
RootModule = 'Team.psm1'
PrivateData = @{
FriendlyName = 'Teams'
}
}
Function Add-TfsTeamAdmin
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
[OutputType('TfsCmdlets.TeamAdmins')]
Param
(
# Specifies the board name(s). Wildcards accepted
[Parameter(Position=0)]
[Alias('Name')]
[Alias('User')]
[object]
$Identity,
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$id = Get-TfsIdentity -Identity $Identity -Collection $rpc
$client = _GetRestClient 'TfsCmdlets.TeamAdminHttpClient' -Collection $tpc
_Log "Adding $($id.IdentityType) '$($id.DisplayName) ($($id.Properties['Account']))' to team '$($t.Name)'"
if(-not $PSCmdlet.ShouldProcess($t.Name, "Add administrator '$($id.DisplayName) ($($id.Properties['Account']))'"))
{
return
}
return $client.AddTeamAdmin($tp.Name, $t.Id, $id.Id)
}
}
Function Get-TfsTeamAdmin
{
[CmdletBinding()]
[OutputType('Microsoft.VisualStudio.Services.Identity.Identity')]
Param
(
# Specifies the board name(s). Wildcards accepted
[Parameter(Position=0)]
[SupportsWildcards()]
[object]
$Identity = '*',
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($Team -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTeam])
{
$Project = $Team.ProjectId
}
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection -IncludeMembers
$tpc = Get-TfsTeamProjectCollection -Collection $Collection; if (-not $tpc -or ($tpc.Count -ne 1)) {throw "Invalid or non-existent team project collection $Collection."}
_Log "Returning team admins from team '$($t.Name)'"
foreach($member in $t.Members)
{
if(-not $member.IsTeamAdmin)
{
continue
}
$i = Get-TfsIdentity -Identity $member.Identity.Id -Collection $Collection
if (($i.DisplayName -like $Identity) -or ($i.Properties['Account'] -like $Identity))
{
Write-Output $i | `
Add-Member -Name TeamId -MemberType NoteProperty -Value $t.Id -PassThru | `
Add-Member -Name ProjectId -MemberType NoteProperty -Value $t.ProjectId -PassThru
}
}
}
}
Function Remove-TfsTeamAdmin
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
[OutputType('TfsCmdlets.TeamAdmins')]
Param
(
# Specifies the board name(s). Wildcards accepted
[Parameter(Position=0,ValueFromPipeline=$true)]
[Alias('Name')]
[Alias('User')]
[object]
$Identity,
[Parameter()]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($Identity.TeamId -and $Identity.ProjectId)
{
$Project = $Identity.ProjectId
$t = Get-TfsTeam -Team $Identity.TeamId -Project $Project -Collection $Collection
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
}
else
{
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
}
$id = Get-TfsIdentity -Identity $Identity -Collection $rpc
$client = _GetRestClient 'TfsCmdlets.TeamAdminHttpClient' -Collection $tpc
_Log "Removing $($id.IdentityType) '$($id.DisplayName) ($($id.Properties['Account']))' from team '$($t.Name)'"
if(-not $PSCmdlet.ShouldProcess($t.Name, "Remove administrator '$($id.DisplayName) ($($id.Properties['Account']))'"))
{
return
}
if(-not ([bool] $client.RemoveTeamAdmin($tp.Name, $t.Id, $id.Id).success))
{
throw 'Error removing team administrator'
}
}
}
<#
.SYNOPSIS
Gets information about one or more team projects.
.DESCRIPTION
The Get-TfsTeamProject cmdlets gets one or more Team Project objects (an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.Project) from the supplied Team Project Collection.
.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Server
Specifies either a URL or the name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.
For more details, see the -Server argument in the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.
#>
Function Get-TfsTeamProject
{
[CmdletBinding(DefaultParameterSetName='Get by project')]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
Param
(
[Parameter(Position=0, ParameterSetName='Get by project')]
[object]
$Project = '*',
[Parameter(ValueFromPipeline=$true, Position=1, ParameterSetName='Get by project')]
[object]
$Collection,
[Parameter(Mandatory=$true, ParameterSetName="Get current")]
[switch]
$Current,
[Parameter(ParameterSetName='Get by project')]
[object]
$Credential
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
if ($Current)
{
return $script:TfsProjectConnection
}
if ($Project -is [Microsoft.TeamFoundation.WorkItemTracking.Client.Project]) { _Log "Input item is of type Microsoft.TeamFoundation.WorkItemTracking.Client.Project; returning input item immediately, without further processing."; return $Project }
$tpc = Get-TfsTeamProjectCollection $Collection -Credential $Credential
if(_TestGuid $Project)
{
$Project = [uri] "vstfs:///Classification/TeamProject/$Project"
}
if (($Project -is [uri]) -or ([System.Uri]::IsWellFormedUriString($Project, [System.UriKind]::Absolute)))
{
$css = $tpc.GetService([type]'Microsoft.TeamFoundation.Server.ICommonStructureService')
$projInfo = $css.GetProject([string] $Project)
$Project = $projInfo.Name
}
if ($Project -is [string])
{
$wiStore = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
if($Project.IndexOf('*') -ge 0)
{
return _GetAllProjects $tpc | Where-Object Name -Like $Project | Foreach-Object { $wiStore.Projects[$_.Name] }
}
return $wiStore.Projects[$Project]
}
if ($null -eq $Project)
{
if ($script:TfsProjectConnection)
{
return $script:TfsProjectConnection
}
}
throw "No TFS team project information available. Either supply a valid -Project argument or use Connect-TfsTeamProject prior to invoking this cmdlet."
}
}
Function _GetAllProjects
{
param ($tpc)
$css = $tpc.GetService([type]'Microsoft.TeamFoundation.Server.ICommonStructureService')
return $css.ListAllProjects() | Where-Object Status -eq WellFormed
}
<#
.SYNOPSIS
Creates a new team project.
#>
Function New-TfsTeamProject
{
[CmdletBinding(DefaultParameterSetName='Get by project',ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Project')]
Param
(
[Parameter(Position=0, Mandatory=$true)]
[string]
$Project,
[Parameter(ValueFromPipeline=$true, Position=1)]
[object]
$Collection,
[string]
$Description,
[string]
[ValidateSet('Git', 'TFVC')]
$SourceControl,
[object]
$ProcessTemplate,
[Parameter()]
[switch]
$Passthru
)
Process
{
if($PSCmdlet.ShouldProcess($Project, 'Create team project'))
{
$tpc = Get-TfsTeamProjectCollection $Collection
$template = Get-TfsProcessTemplate -Collection $tpc -Name $ProcessTemplate
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient' -Collection $tpc
$tpInfo = New-Object 'Microsoft.TeamFoundation.Core.WebApi.TeamProject'
$tpInfo.Name = $Project
$tpInfo.Description = $Description
$tpInfo.Capabilities = New-Object 'System.Collections.Generic.Dictionary[[string],System.Collections.Generic.Dictionary[[string],[string]]]'
$tpInfo.Capabilities.Add('versioncontrol', (New-Object 'System.Collections.Generic.Dictionary[[string],[string]]'))
$tpInfo.Capabilities['versioncontrol'].Add('sourceControlType', $SourceControl)
$tpInfo.Capabilities.Add('processTemplate', (New-Object 'System.Collections.Generic.Dictionary[[string],[string]]'))
$tpInfo.Capabilities['processTemplate'].Add('templateTypeId', ([xml]$template.Metadata).metadata.version.type)
# Trigger the project creation
$token = $client.QueueCreateProject($tpInfo).Result
if (-not $token)
{
throw "Error queueing team project creation: $($client.LastResponseContext.Exception.Message)"
}
# Wait for the operation to complete
$operationsClient = _GetRestClient 'Microsoft.VisualStudio.Services.Operations.OperationsHttpClient' -Collection $tpc
$opsToken = $operationsClient.GetOperation($token.Id).Result
while (
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded) -and
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Failed) -and
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Cancelled))
{
Start-Sleep -Seconds 2
$opsToken = $operationsClient.GetOperation($token.Id).Result
}
if ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded)
{
throw "Error creating team project $Project"
}
# Force a metadata cache refresh prior to retrieving the newly created project
$wiStore = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
$wiStore.RefreshCache()
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
if ($Passthru)
{
return $tp
}
}
}
}
<#
.SYNOPSIS
Deletes one or more team projects.
.DESCRIPTION
.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.
#>
Function Remove-TfsTeamProject
{
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
Param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[SupportsWildcards()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Hard,
[Parameter()]
[switch]
$Force
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
$tps = Get-TfsTeamProject -Project $Project -Collection $Collection
if(-not $tps)
{
return
}
foreach($tp in $tps)
{
$tpc = $tp.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient' -Collection $tpc
if($PSCmdlet.ShouldProcess($tp.Name, 'Delete team project'))
{
if((-not $Hard.IsPresent) -or ($Force.IsPresent -or ($PSCmdlet.ShouldContinue('The team project deletion is IRREVERSIBLE and may cause DATA LOSS. Are you sure you want to proceed?'))))
{
$method = (&{if($Hard.IsPresent) {'Hard'} else {'Soft'}})
_Log "$method-deleting team project $($tp.Name)"
$token = $client.QueueDeleteProject($tp.Guid, $Hard.IsPresent).Result
if (-not $token)
{
throw "Error queueing team project deletion: $($client.LastResponseContext.Exception.Message)"
}
# Wait for the operation to complete
$operationsClient = _GetRestClient 'Microsoft.VisualStudio.Services.Operations.OperationsHttpClient' -Collection $tpc
$opsToken = $operationsClient.GetOperation($token.Id).Result
while (
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded) -and
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Failed) -and
($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Cancelled))
{
_Log "Waiting for the queued operation to finish (current status: $($opsToken.Status))"
Start-Sleep -Seconds 1
$opsToken = $operationsClient.GetOperation($token.Id).Result
}
if ($opsToken.Status -ne [Microsoft.VisualStudio.Services.Operations.OperationStatus]::Succeeded)
{
_Log "Queued operation finished with status $($opsToken.Status)"
throw "Error deleting team project ${Project}: $($opsToken.DetailedMessage)"
}
}
}
}
}
}
�@{
Description = 'This module contains cmdlets to maintain and administer Team Projects'
ModuleVersion = '0.0.0'
RootModule = 'TeamProject.psm1'
PrivateData = @{
FriendlyName = 'Team Projects'
}
}
<#
.SYNOPSIS
Detaches a team project collection database from a Team Foundation Server installation
.DESCRIPTION
Before you move a collection, you must first detach it from the deployment of TFS on which it is running. It's very important that you not skip this step. When you detach a collection, all jobs and services are stopped, and then the collection database is stopped. In addition, the detach process copies over the collection-specific data from the configuration database and saves it as part of the team project collection database. This configuration data is what allows the collection database to be attached to a different deployment of TFS. If that data is not present, you cannot attach the collection to any deployment of TFS except the one from which it originated.
If detachment succeeds, the original database connection string is returned. It is required to re-attach the collection to TFS.
.PARAMETER Reason
Speficies a Servicing Message (optional), to provide a message for users who might try to connect to projects in this collection
.PARAMETER Timeout
The maximum period of time this cmdlet should wait for the detach procedure to complete. By default, it waits indefinitely until the collection servicing completes
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server to connect to, or a previously initialized TfsConfigurationServer object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.nnTo connect to a Team Foundation Server instance by using its name, it must have been previously registered.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
.EXAMPLE
Dismount-TfsTeamProjectCollection -Collection http://vsalm:8080/tfs/DefaultCollection -Reason 'Collection DefaultCollecton is down for maintenance'
Detaches the project collection specified by the URL provided in the Collection argument, defining a Maintenance Message to be shown to users when they try to connect to that collection while it is detached
.LINK
https://www.visualstudio.com/en-us/docs/setup-admin/tfs/admin/move-project-collection#1-detach-the-collection
.NOTES
Detaching a collection prevents users from accessing any projects in that collection
#>
Function Dismount-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUsePSCredentialType', '')]
[OutputType('string')]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[object]
$Collection,
[Parameter(ValueFromPipeline=$true)]
[object]
$Server,
[Parameter()]
[string]
$Reason,
[Parameter()]
[timespan]
$Timeout = [timespan]::MaxValue,
[Parameter()]
[object]
$Credential
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Credential
if ($PSCmdlet.ShouldProcess($tpc.Name, "Detach Project Collection"))
{
$configServer = $tpc.ConfigurationServer
$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
$collectionInfo = $tpcService.GetCollection($tpc.InstanceId)
$connectionString = $null
$tpcJob = $tpcService.QueueDetachCollection($collectionInfo, $null, $Reason, [ref] $connectionString)
$collectionInfo = $tpcService.WaitForCollectionServicingToComplete($tpcJob, $Timeout)
return $connectionString
}
}
}
<#
.SYNOPSIS
Gets one or more Team Project Collection addresses registered in the current computer.
.PARAMETER Name
Specifies the name of a registered collection. When omitted, all registered collections are returned. Wildcards are permitted.
.INPUTS
System.String
#>
Function Get-TfsRegisteredTeamProjectCollection
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Client.RegisteredProjectCollection[]')]
Param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[Alias('Name')]
[SupportsWildcards()]
[string]
$Collection = "*"
)
Process
{
$registeredCollections = [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetProjectCollections()
foreach($tpc in $registeredCollections)
{
$tpcName = ([uri]$tpc.Uri).Segments[-1]
if($tpcName -like $Collection)
{
Write-Output $tpc
}
}
}
}
<#
.SYNOPSIS
Gets information about one or more team project collections.
.DESCRIPTION
The Get-TfsTeamProjectCollection cmdlets gets one or more Team Project Collection objects (an instance of Microsoft.TeamFoundation.Client.TfsTeamProjectCollection) from a TFS instance.
Team Project Collection objects can either be obtained by providing a fully-qualified URL to the collection or by collection name (in which case a TFS Configuration Server object is required).
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER Server
Specifies either a URL/name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.
.PARAMETER Current
Returns the team project collection specified in the last call to Connect-TfsTeamProjectCollection (i.e. the "current" project collection)
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
.EXAMPLE
Get-TfsTeamProjectCollection http://
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
.NOTES
Cmdlets in the TfsCmdlets module that operate on a collection level require a TfsConfigurationServer object to be provided via the -Server argument. If absent, it will default to the connection opened by Connect-TfsConfigurationServer.
#>
Function Get-TfsTeamProjectCollection
{
[CmdletBinding(DefaultParameterSetName='Get by collection')]
[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
Param
(
[Parameter(Position=0, ParameterSetName="Get by collection")]
[SupportsWildcards()]
[object]
$Collection = "*",
[Parameter(ValueFromPipeline=$true, ParameterSetName="Get by collection")]
[object]
$Server,
[Parameter(Position=0, ParameterSetName="Get current")]
[switch]
$Current,
[Parameter(ParameterSetName="Get by collection")]
[object]
$Credential
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Client'
}
Process
{
if (($Current.IsPresent -or (-not $Collection)) -and ($script:TfsTpcConnection))
{
return $script:TfsTpcConnection
}
if ($Collection -is [Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])
{
return $Collection
}
$cred = Get-TfsCredential -Credential $Credential
if ($Collection -is [Uri] -or ([Uri]::IsWellFormedUriString($Collection, [UriKind]::Absolute)))
{
return New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList ([uri]$Collection), $cred
}
if ($Collection -is [string])
{
$configServer = Get-TfsConfigurationServer -Server $Server -Credential $cred
if($configServer)
{
$filter = [Guid[]] @([Microsoft.TeamFoundation.Framework.Common.CatalogResourceTypes]::ProjectCollection)
$collections = $configServer.CatalogNode.QueryChildren($filter, $false, [Microsoft.TeamFoundation.Framework.Common.CatalogQueryOptions]::None)
$collections = $collections | Select-Object -ExpandProperty Resource | Where-Object DisplayName -like $Collection
foreach ($tpc in $collections)
{
$collectionId = $tpc.Properties["InstanceId"]
Write-Output $configServer.GetTeamProjectCollection($collectionId)
}
}
$registeredCollection = Get-TfsRegisteredTeamProjectCollection $Collection
if($registeredCollection.Count)
{
foreach($tpc in $registeredCollection)
{
Write-Output (New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList ([uri]$tpc.Uri), $cred)
}
return
}
}
}
}
<#
.SYNOPSIS
Attaches a team project collection database to a Team Foundation Server installation.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
Microsoft.TeamFoundation.Client.TfsConfigurationServer
System.String
System.Uri
#>
Function Mount-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact='Medium')]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[Alias('Name')]
[string]
$Collection,
[Parameter()]
[string]
$Description,
[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
[string]
$DatabaseServer,
[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
[string]
$DatabaseName,
[Parameter(ParameterSetName="Use connection string", Mandatory=$true)]
[string]
$ConnectionString,
[Parameter()]
[ValidateSet("Started", "Stopped")]
[string]
$InitialState = "Started",
[Parameter()]
[switch]
$Clone,
[Parameter()]
[int]
$PollingInterval = 5,
[Parameter()]
[timespan]
$Timeout = [timespan]::MaxValue,
[Parameter(ValueFromPipeline=$true)]
[object]
$Server,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
$configServer = Get-TfsConfigurationServer $Server -Credential $Credential
$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
$servicingTokens = New-Object 'System.Collections.Generic.Dictionary[string,string]'
if ($DatabaseName)
{
$servicingTokens["CollectionDatabaseName"] = $DatabaseName
}
if ($PSCmdlet.ParameterSetName -eq "Use database server")
{
$ConnectionString = "Data source=$DatabaseServer; Integrated Security=true; Initial Catalog=$DatabaseName"
}
try
{
Write-Progress -Id 1 -Activity "Attach team project collection" -Status "Attaching team project collection $Collection" -PercentComplete 0
#$start = Get-Date
# string databaseConnectionString, IDictionary<string, string> servicingTokens, bool cloneCollection, string name, string description, string virtualDirectory)
$tpcJob = $tpcService.QueueAttachCollection(
$ConnectionString,
$servicingTokens,
$Clone.ToBool(),
$Collection,
$Description,
"~/$Collection/")
[void] $tpcService.WaitForCollectionServicingToComplete($tpcJob, $Timeout)
return Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Collection
}
finally
{
Write-Progress -Id 1 -Activity "Attach team project collection" -Completed
}
throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Collection")
}
}
<#
.SYNOPSIS
Creates a new team project collection.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
System.String
#>
Function New-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Client.TfsTeamProjectCollection')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias('Name')]
[string]
$Collection,
[Parameter()]
[string]
$Description,
[Parameter(ParameterSetName="Use database server", Mandatory=$true)]
[string]
$DatabaseServer,
[Parameter(ParameterSetName="Use database server")]
[string]
$DatabaseName,
[Parameter(ParameterSetName="Use connection string", Mandatory=$true)]
[string]
$ConnectionString,
[Parameter()]
[switch]
$Default,
[Parameter()]
[switch]
$UseExistingDatabase,
[Parameter()]
[ValidateSet("Started", "Stopped")]
[string]
$InitialState = "Started",
[Parameter()]
[int]
$PollingInterval = 5,
[Parameter()]
[timespan]
$Timeout = [timespan]::MaxValue,
[Parameter()]
[object]
$Server,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty,
[Parameter()]
[switch]
$Passthru
)
Process
{
if($PSCmdlet.ShouldProcess($Collection, 'Create team project collection'))
{
$configServer = Get-TfsConfigurationServer $Server -Credential $Credential
$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
$servicingTokens = New-Object 'System.Collections.Generic.Dictionary[string,string]'
$servicingTokens["SharePointAction"] = "None"
$servicingTokens["ReportingAction"] = "None"
if ($DatabaseName)
{
$servicingTokens["CollectionDatabaseName"] = $DatabaseName
}
if ($UseExistingDatabase)
{
$servicingTokens["UseExistingDatabase"] = $UseExistingDatabase.ToBool()
}
if ($PSCmdlet.ParameterSetName -eq "Use database server")
{
$ConnectionString = "Data source=$DatabaseServer; Integrated Security=true"
}
try
{
Write-Progress -Id 1 -Activity "Create team project collection" -Status "Creating team project collection $Collection" -PercentComplete 0
$start = Get-Date
$tpcJob = $tpcService.QueueCreateCollection(
$Collection,
$Description,
$Default.ToBool(),
"~/$Collection/",
[Microsoft.TeamFoundation.Framework.Common.TeamFoundationServiceHostStatus] $InitialState,
$servicingTokens,
$ConnectionString,
$null, # Default connection string
$null) # Default category connection strings
while((Get-Date).Subtract($start) -le $Timeout)
{
Start-Sleep -Seconds $PollingInterval
$collectionInfo = $tpcService.GetCollection($tpcJob.HostId, [Microsoft.TeamFoundation.Framework.Client.ServiceHostFilterFlags]::IncludeAllServicingDetails)
$jobDetail = $collectionInfo.ServicingDetails | Where-Object JobId -eq $tpcJob.JobId
if (($null -eq $jobDetail) -or
(($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Queued) -and
($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Running)))
{
if ($jobDetail.Result -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobResult]::Failed -or
$jobDetail.JobStatus -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Failed)
{
throw "Error creating team project collection $Collection : "
}
$tpc = Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Collection
if ($Passthru)
{
return $tpc
}
}
}
}
finally
{
Write-Progress -Id 1 -Activity "Create team project collection" -Completed
}
throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Collection")
}
}
}
<#
.SYNOPSIS
Deletes a team project collection
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Remove-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[object]
$Collection,
[Parameter()]
[object]
$Server,
[Parameter()]
[timespan]
$Timeout = [timespan]::MaxValue,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection -Server $Server -Credential $Credential
if ($PSCmdlet.ShouldProcess($tpc.Name, "Delete Team Project Collection"))
{
Write-Progress -Id 1 -Activity "Delete team project collection" -Status "Deleting $($tpc.Name)" -PercentComplete 0
try
{
$configServer = $tpc.ConfigurationServer
$tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')
$collectionInfo = $tpcService.GetCollection($tpc.InstanceId)
$collectionInfo.Delete()
}
finally
{
Write-Progress -Id 1 -Activity "Delete team project collection" -Completed
}
}
}
}
<#
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Start-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[object]
$Collection,
[Parameter()]
[object]
$Server,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
if($PSCmdlet.ShouldProcess($Collection, 'Start team project collection'))
{
throw "Not implemented"
}
}
}
<#
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.nnType a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.nnTo connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.nnFor more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
#>
Function Stop-TfsTeamProjectCollection
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[object]
$Collection,
[Parameter()]
[string]
$Reason,
[Parameter()]
[object]
$Server,
[Parameter()]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
Process
{
if($PSCmdlet.ShouldProcess($Collection, 'Stop team project collection'))
{
throw "Not implemented"
}
}
}
@{
Description = 'This module contains cmdlets to maintain and administer Team Project Collections'
ModuleVersion = '0.0.0'
RootModule = 'TeamProjectCollection.psm1'
PrivateData = @{
FriendlyName = 'Team Project Collections'
}
}
<#
.SYNOPSIS
Clones a test plan and, optionally, its test suites and test cases
.DESCRIPTION
The Copy-TfsTestPlan copies ("clones") a test plan to help duplicate test suites and/or test cases. Cloning is useful if you want to branch your application into two versions: after copying, the tests for the two versions can be changed without affecting each other.
.EXAMPLE
Copy-TfsTestPlan -TestPlan 'My test plan' -Project 'SourceProject' -Destination 'TargetProject' -NewName 'My new test plan'
.INPUTS
Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan
.OUTPUTS
Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan
.NOTES
When you clone a test suite, the following objects are copied from the source test plan to the destination test plan:
* Test cases (note: Each new test case retains its shared steps. A link is made between the source and new test cases. The new test cases do not have test runs, bugs, test results, and build information);
* Shared steps referenced by cloned test cases;
* Test suites (note: The following data is retained - Names and hierarchical structure of the test suites; Order of the test cases; Assigned testers; Configurations)
* Action Recordings linked from a cloned test case
* Links and Attachments
* Test configuration
The items below are only copied when using -CloneRequirements:
* Requirements-based suites;
* Requirements work items (product backlog items or user stories);
* Bug work items, when in a project that uses the Scrum process template or any other project in which the Bug work item type is in the Requirements work item category. In other projects, bugs are not cloned.
.PARAMETER TestPlan
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER NewName
.PARAMETER DestinationProject
.PARAMETER AreaPath
.PARAMETER IterationPath
.PARAMETER DeepClone
.PARAMETER CopyAllSuites
.PARAMETER CopyAncestorHierarchy
.PARAMETER DestinationWorkItemType
.PARAMETER SuiteIds
.PARAMETER RelatedLinkComment
.PARAMETER Passthru
Returns the results of the command. By default, this cmdlet does not generate any output.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
#>
Function Copy-TfsTestPlan
{
[CmdletBinding()]
[OutputType('Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan')]
Param
(
[Parameter(ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$TestPlan,
[Parameter()]
[object]
$Project,
[Parameter()]
[string]
$NewName,
[Parameter()]
[Alias('Destination')]
[object]
$DestinationProject,
[Parameter()]
[string]
$AreaPath,
[Parameter()]
[string]
$IterationPath,
[Parameter()]
[switch]
$DeepClone,
[Parameter()]
[Alias("Recurse")]
[switch]
$CopyAllSuites,
[Parameter()]
[switch]
$CopyAncestorHierarchy,
[Parameter()]
[switch]
$CloneRequirements,
[Parameter()]
[string]
$DestinationWorkItemType = 'Test Case',
[Parameter()]
[int[]]
$SuiteIds,
[Parameter()]
[string]
$RelatedLinkComment,
[Parameter()]
[ValidateSet('Original', 'Copy', 'None')]
[string]
$Passthru = 'None',
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.TestManagement.WebApi'
$ns = 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
}
Process
{
$plan = Get-TfsTestPlan -TestPlan $TestPlan -Project $Project -Collect $Collection
if(-not $plan)
{
throw "Invalid or non-existent test plan $TestPlan"
}
$destTp = Get-TfsTeamProject -Project $DestinationProject -Collection $Collection
if(-not $destTp)
{
throw "Invalid or non-existent team project $DestinationProject"
}
if (-not $Project)
{
$Project = $plan.Project.Name
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
if(-not $tp)
{
throw "Invalid or non-existent team project $Project"
}
if (-not $NewName)
{
if($tp.Name -ne $destTp.Name)
{
$NewName = $plan.Name
}
else
{
$NewName = "$($plan.Name) (cloned $([DateTime]::Now.ToShortDateString()))"
}
}
if (-not $AreaPath)
{
$AreaPath = $destTp.Name
}
if (-not $IterationPath)
{
$IterationPath = $destTp.Name
}
$tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient "$ns.TestPlanHttpClient" -Collection $tpc
$cloneParams = New-Object "$ns.CloneTestPlanParams" -Property @{
sourceTestPlan = New-Object "$ns.SourceTestPlanInfo" -Property @{
Id = $plan.Id
};
destinationTestPlan = New-Object "$ns.DestinationTestPlanCloneParams" -Property @{
Project = $destTp.Name;
Name = $NewName;
AreaPath = $AreaPath;
Iteration = $IterationPath
};
cloneOptions = New-Object "Microsoft.TeamFoundation.TestManagement.WebApi.CloneOptions" -Property @{
RelatedLinkComment = $RelatedLinkComment;
CopyAllSuites = $CopyAllSuites.IsPresent;
CopyAncestorHierarchy = $CopyAncestorHierarchy;
DestinationWorkItemType = $DestinationWorkItemType;
CloneRequirements = $CloneRequirements;
OverrideParameters = _NewDictionary @([string],[string]) @{
'System.AreaPath' = $AreaPath;
'System.IterationPath' = $IterationPath
}
}
}
$task = $client.CloneTestPlanAsync($cloneParams, $tp.Name, $DeepClone.IsPresent)
$result = $task.Result; if($task.IsFaulted) { throw 'Error cloning test plan' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
$opInfo = $result
do
{
Start-Sleep -Seconds 1
$opInfo = $client.GetCloneInformationAsync($tp.Name, $opInfo.CloneOperationResponse.opId)
}
while ($opInfo.CloneOperationResponse.CloneOperationState -match 'Queued|InProgress')
if ($opInfo.CloneOperationResponse.CloneOperationState -eq 'Failed')
{
throw "Error cloning test plan '$($plan.Name)': $($opInfo.CloneOperationResponse.Message)"
}
else
{
$copy = $opInfo.DestinationTestPlan
}
if ($Passthru -eq 'Original')
{
return $plan
}
if($Passthru -eq 'Copy')
{
return $copy
}
}
}
<#
.SYNOPSIS
Gets the contents of one or more test plans
.DESCRIPTION
.EXAMPLE
Get-TfsTestPlan 'Release 1 - Sprint*' -Project 'Fabrikam'
Returns all test plans from team project 'Fabrikam' whose names start with 'Release 1 - Sprint'
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
.OUTPUTS
Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan
.NOTES
#>
Function Get-TfsTestPlan
{
[CmdletBinding()]
[OutputType('Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan')]
Param
(
# Specifies the test plan name. Wildcards are supported
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias("Id")]
[Alias("Name")]
[object]
$TestPlan = '*',
# Specifices the plan's owner name
[Parameter()]
[string]
$Owner,
# Get only basic properties of the test plan
[Parameter()]
[switch]
$NoPlanDetails,
# Get just the active plans
[Parameter()]
[switch]
$FilterActivePlans,
# Specifies the team project
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
# Specifies the collection / organization
[Parameter()]
[Alias("Organization")]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
}
Process
{
if ($TestPlan -is [Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlan])
{
return $TestPlan
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.TestPlanHttpClient' -Collection $tpc
return $client.GetTestPlansAsync(
$tp.Name, $Owner, $null,
(-not $NoPlanDetails.IsPresent),
$FilterActivePlans.IsPresent).Result | Where-Object Name -like $TestPlan
}
}
Function Remove-TfsTestPlan
{
[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$TestPlan,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.TestManagement.WebApi'
$ns = 'Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi'
}
Process
{
$plan = Get-TfsTestPlan -TestPlan $TestPlan -Project $Project -Collect $Collection
if(-not $plan)
{
throw "Invalid or non-existent test plan $TestPlan"
}
if (-not $Project)
{
$Project = $plan.Project.Name
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
if(-not $tp)
{
throw "Invalid or non-existent team project $Project"
}
$tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient "$ns.TestPlanHttpClient" -Collection $tpc
if ($PSCmdlet.ShouldProcess("Plan $($plan.Id) ('$($plan.Name)')", "Remove test plan"))
{
$task = $client.DeleteTestPlanAsync($tp.Name, $plan.Id)
$result = $task.Result; if($task.IsFaulted) { throw 'Error deleting test plan' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
}
}
#
# Module manifest for module 'TfsCmdlets'
#
# Generated by: Igor Abade V. Leite
#
# Generated on: 29/08/2019
#
@{
# Script module or binary module file associated with this manifest.
RootModule = 'TfsCmdlets.psm1'
# Version number of this module.
ModuleVersion = '2.0.0'
# Supported PSEditions
CompatiblePSEditions = 'Desktop'
# ID used to uniquely identify this module
GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'
# Author of this module
Author = 'Igor Abade V. Leite'
# Company or vendor of this module
CompanyName = 'Igor Abade V. Leite'
# Copyright statement for this module
Copyright = '(c) 2014 Igor Abade V. Leite. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Cmdlets for Azure DevOps and Team Foundation Server'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.1'
# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
ScriptsToProcess = 'Startup.ps1'
# Type files (.ps1xml) to be loaded when importing this module
TypesToProcess = 'TfsCmdlets.Types.ps1xml'
# Format files (.ps1xml) to be loaded when importing this module
FormatsToProcess = 'TfsCmdlets.Format.ps1xml'
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('Admin\Admin.ps1',
'AreaIteration\Area\AreaIteration_Area.ps1',
'AreaIteration\Iteration\AreaIteration_Iteration.ps1',
'AreaIteration\AreaIteration.ps1',
'ConfigServer\ConfigServer.ps1',
'Connection\Connection.ps1',
'Git\Branch\Git_Branch.ps1',
'Git\Policy\Git_Policy.ps1',
'Git\Repository\Git_Repository.ps1',
'GlobalList\GlobalList.ps1',
'Helpers\Helpers.ps1',
'Identity\Identity.ps1',
'Organization\Organization.ps1',
'Policy\Policy.ps1',
'ProcessTemplate\ProcessTemplate.ps1',
'ServiceHook\ServiceHook.ps1',
'Team\TeamAdmin\Team_TeamAdmin.ps1',
'Team\Team.ps1',
'TeamProject\TeamProject.ps1',
'TeamProjectCollection\TeamProjectCollection.ps1',
'TestManagement\TestManagement.ps1',
'Work\Work.ps1',
'WorkItem\History\WorkItem_History.ps1',
'WorkItem\Linking\WorkItem_Linking.ps1',
'WorkItem\Query\WorkItem_Query.ps1',
'WorkItem\Tagging\WorkItem_Tagging.ps1',
'WorkItem\WorkItemType\WorkItem_WorkItemType.ps1',
'WorkItem\WorkItem.ps1',
'XamlBuild\XamlBuild.ps1',
'_Shared\_Shared.ps1')
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Add-TfsTeamAdmin', 'Add-TfsWorkItemLink',
'Connect-TfsConfigurationServer', 'Connect-TfsTeamProject',
'Connect-TfsTeamProjectCollection', 'Copy-TfsTestPlan',
'Copy-TfsWorkItem', 'Disconnect-TfsConfigurationServer',
'Disconnect-TfsTeamProject', 'Disconnect-TfsTeamProjectCollection',
'Dismount-TfsTeamProjectCollection', 'Export-TfsGlobalList',
'Export-TfsProcessTemplate', 'Export-TfsWorkItemQuery',
'Export-TfsWorkItemType', 'Get-AzDevOrganization', 'Get-TfsArea',
'Get-TfsConfigurationServer',
'Get-TfsConfigurationServerConnectionString', 'Get-TfsCredential',
'Get-TfsGitBranch', 'Get-TfsGitBranchPolicy', 'Get-TfsGitRepository',
'Get-TfsGlobalList', 'Get-TfsIdentity', 'Get-TfsInstallationPath',
'Get-TfsIteration', 'Get-TfsPolicyType', 'Get-TfsProcessTemplate',
'Get-TfsRegisteredConfigurationServer',
'Get-TfsRegisteredTeamProjectCollection', 'Get-TfsRestClient',
'Get-TfsServiceHookConsumer',
'Get-TfsServiceHookNotificationHistory',
'Get-TfsServiceHookPublisher', 'Get-TfsServiceHookSubscription',
'Get-TfsTeam', 'Get-TfsTeamAdmin', 'Get-TfsTeamBacklog',
'Get-TfsTeamBoard', 'Get-TfsTeamBoardCardRuleSettings',
'Get-TfsTeamProject', 'Get-TfsTeamProjectCollection',
'Get-TfsTestPlan', 'Get-TfsWorkItem', 'Get-TfsWorkItemHistory',
'Get-TfsWorkItemLink', 'Get-TfsWorkItemLinkEndType',
'Get-TfsWorkItemQuery', 'Get-TfsWorkItemQueryFolder',
'Get-TfsWorkItemTag', 'Get-TfsWorkItemType', 'Import-TfsGlobalList',
'Import-TfsProcessTemplate', 'Import-TfsWorkItemType',
'Invoke-TfsRestApi', 'Mount-TfsTeamProjectCollection', 'Move-TfsArea',
'Move-TfsIteration', 'Move-TfsWorkItem', 'New-TfsArea',
'New-TfsGitRepository', 'New-TfsGlobalList', 'New-TfsIteration',
'New-TfsTeam', 'New-TfsTeamProject', 'New-TfsTeamProjectCollection',
'New-TfsWorkItem', 'New-TfsWorkItemQuery',
'New-TfsWorkItemQueryFolder', 'New-TfsWorkItemTag', 'Remove-TfsArea',
'Remove-TfsGitRepository', 'Remove-TfsGlobalList',
'Remove-TfsIteration', 'Remove-TfsTeam', 'Remove-TfsTeamAdmin',
'Remove-TfsTeamProject', 'Remove-TfsTeamProjectCollection',
'Remove-TfsTestPlan', 'Remove-TfsWorkItem', 'Remove-TfsWorkItemQuery',
'Remove-TfsWorkItemQueryFolder', 'Remove-TfsWorkItemTag',
'Rename-TfsArea', 'Rename-TfsGitRepository', 'Rename-TfsIteration',
'Rename-TfsTeam', 'Rename-TfsWorkItemQuery', 'Rename-TfsWorkItemTag',
'Set-TfsArea', 'Set-TfsGlobalList', 'Set-TfsIteration', 'Set-TfsTeam',
'Set-TfsTeamBoardCardRuleSettings', 'Set-TfsWorkItem',
'Set-TfsWorkItemBoardStatus', 'Set-TfsWorkItemQuery',
'Start-TfsIdentitySync', 'Start-TfsTeamProjectCollection',
'Start-TfsXamlBuild', 'Stop-TfsTeamProjectCollection', 'Test-TfsArea',
'Test-TfsIteration'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()
# Variables to export from this module
# VariablesToExport = @()
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = 'tfsrv', 'tftpc', 'tftp', 'gtftpc', 'gtftp'
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
FileList = 'chocolateyInstall.ps1', 'chocolateyUninstall.ps1', 'Prompt.ps1',
'Startup.ps1', 'TfsCmdlets.Format.ps1xml', 'TfsCmdlets.psd1',
'TfsCmdlets.psm1', 'TfsCmdlets.Types.ps1xml', 'TfsCmdletsShell.ico',
'Admin\Admin.ps1', 'Admin\Admin.psd1',
'AreaIteration\AreaIteration.ps1',
'AreaIteration\AreaIteration.psd1',
'AreaIteration\Area\AreaIteration_Area.ps1',
'AreaIteration\Iteration\AreaIteration_Iteration.ps1',
'ConfigServer\ConfigServer.ps1', 'ConfigServer\ConfigServer.psd1',
'Connection\Connection.ps1', 'Connection\Connection.psd1',
'Git\Branch\Git_Branch.ps1', 'Git\Policy\Git_Policy.ps1',
'Git\Repository\Git.psd1', 'Git\Repository\Git_Repository.ps1',
'GlobalList\GlobalList.ps1', 'GlobalList\GlobalList.psd1',
'Helpers\Helpers.ps1', 'Identity\Identity.ps1',
'Lib\Ben.Demystifier.dll', 'Lib\HtmlAgilityPack.dll',
'Lib\Microsoft.Azure.DevOps.Comments.WebApi.dll',
'Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.dll',
'Lib\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll',
'Lib\Microsoft.IdentityModel.JsonWebTokens.dll',
'Lib\Microsoft.IdentityModel.Logging.dll',
'Lib\Microsoft.IdentityModel.Tokens.dll',
'Lib\Microsoft.TeamFoundation.Build.Client.dll',
'Lib\Microsoft.TeamFoundation.Build.Common.dll',
'Lib\Microsoft.TeamFoundation.Build2.WebApi.dll',
'Lib\Microsoft.TeamFoundation.Client.dll',
'Lib\Microsoft.TeamFoundation.Common.dll',
'Lib\Microsoft.TeamFoundation.Core.WebApi.dll',
'Lib\Microsoft.TeamFoundation.Dashboards.WebApi.dll',
'Lib\Microsoft.TeamFoundation.DeleteTeamProject.dll',
'Lib\Microsoft.TeamFoundation.Diff.dll',
'Lib\Microsoft.TeamFoundation.Discussion.Client.dll',
'Lib\Microsoft.TeamFoundation.DistributedTask.Common.Contracts.dll',
'Lib\Microsoft.TeamFoundation.Git.Client.dll',
'Lib\Microsoft.TeamFoundation.Lab.Client.dll',
'Lib\Microsoft.TeamFoundation.Lab.Common.dll',
'Lib\Microsoft.TeamFoundation.Lab.TestIntegration.Client.dll',
'Lib\Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.dll',
'Lib\Microsoft.TeamFoundation.Policy.WebApi.dll',
'Lib\Microsoft.TeamFoundation.ProjectManagement.dll',
'Lib\Microsoft.TeamFoundation.SharePointReporting.Integration.dll',
'Lib\Microsoft.TeamFoundation.SourceControl.WebApi.dll',
'Lib\Microsoft.TeamFoundation.Test.WebApi.dll',
'Lib\Microsoft.TeamFoundation.TestImpact.Client.dll',
'Lib\Microsoft.TeamFoundation.TestManagement.Client.dll',
'Lib\Microsoft.TeamFoundation.TestManagement.Common.dll',
'Lib\Microsoft.TeamFoundation.TestManagement.WebApi.dll',
'Lib\Microsoft.TeamFoundation.VersionControl.Client.dll',
'Lib\Microsoft.TeamFoundation.VersionControl.Common.dll',
'Lib\Microsoft.TeamFoundation.VersionControl.Common.Integration.dll',
'Lib\Microsoft.TeamFoundation.Wiki.WebApi.dll',
'Lib\Microsoft.TeamFoundation.Work.WebApi.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Common.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Process.WebApi.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll',
'Lib\Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll',
'Lib\Microsoft.VisualStudio.Services.Client.Interactive.dll',
'Lib\Microsoft.VisualStudio.Services.Common.dll',
'Lib\Microsoft.VisualStudio.Services.ServiceHooks.WebApi.dll',
'Lib\Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.dll',
'Lib\Microsoft.VisualStudio.Services.TestResults.WebApi.dll',
'Lib\Microsoft.VisualStudio.Services.WebApi.dll',
'Lib\Microsoft.WITDataStore32.dll',
'Lib\Microsoft.WITDataStore64.dll', 'Lib\Newtonsoft.Json.dll',
'Lib\System.IdentityModel.Tokens.Jwt.dll',
'Lib\System.Net.Http.Formatting.dll', 'Lib\System.Web.Http.dll',
'Lib\System.Web.Http.WebHost.dll', 'Lib\TfsCmdletsLib.dll',
'Organization\Organization.ps1', 'Policy\Policy.ps1',
'ProcessTemplate\ProcessTemplate.ps1',
'ProcessTemplate\ProcessTemplate.psd1',
'ServiceHook\ServiceHook.ps1', 'Team\Team.ps1', 'Team\Team.psd1',
'Team\TeamAdmin\Team_TeamAdmin.ps1', 'TeamProject\TeamProject.ps1',
'TeamProject\TeamProject.psd1',
'TeamProjectCollection\TeamProjectCollection.ps1',
'TeamProjectCollection\TeamProjectCollection.psd1',
'TestManagement\TestManagement.ps1', 'Work\Work.ps1',
'WorkItem\WorkItem.ps1', 'WorkItem\WorkItem.psd1',
'WorkItem\History\WorkItem_History.ps1',
'WorkItem\Linking\WorkItem_Linking.ps1',
'WorkItem\Query\WorkItemQuery.psd1',
'WorkItem\Query\WorkItem_Query.ps1',
'WorkItem\Tagging\WorkItem_Tagging.ps1',
'WorkItem\WorkItemType\WorkItem_WorkItemType.ps1',
'XamlBuild\XamlBuild.ps1', 'XamlBuild\XamlBuild.psd1',
'_cs\DesktopAssemblyResolver.cs', '_Shared\_Shared.ps1'
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
#TfsClientVersion of this module
TfsClientVersion = '16.156.0-preview'
#Branch of this module
Branch = 'releases/v2.0.0'
#Version of this module
Version = '2.0.0-beta.4+3'
#Build of this module
Build = '2.0.0-beta.4+1770.03'
#Commit of this module
Commit = 'c56ea2b401c1fa2ce31d72a4fc7c084535e913c4'
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
Tags = 'TfsCmdlets','TFS','VSTS','PowerShell','Azure','AzureDevOps','DevOps','ALM','TeamFoundationServer'
# A URL to the license for this module.
LicenseUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/LICENSE.md'
# A URL to the main website for this project.
ProjectUri = 'https://github.com/igoravl/tfscmdlets/'
# A URL to an icon representing this module.
IconUri = 'https://raw.githubusercontent.com/igoravl/tfscmdlets/master/TfsCmdlets/resources/TfsCmdlets_Icon_32.png'
# ReleaseNotes of this module
ReleaseNotes = 'See https://github.com/igoravl/tfscmdlets/wiki/ReleaseNotes'
# Prerelease string of this module
Prerelease = 'beta0004'
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
# RequireLicenseAcceptance = $false
# External dependent modules of this module
# ExternalModuleDependencies = @()
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
HelpInfoURI = 'https://github.com/igoravl/tfscmdlets/wiki/'
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}
_Log "Loading module TfsCmdlets from $PSScriptRoot"
# Initialize variables
$script:IsDesktop = ($PSEdition -ne 'Core')
$script:IsCore = -not $script:IsDesktop
# Configure assembly resolver
_RegisterAssemblyResolver
# Load essential assemblies
# TODO - Add strong names to loaded assemblies, to avoid loading 2010 assemblies from GAC
_ImportRequiredAssembly "*"
# _ImportRequiredAssembly 'Newtonsoft.Json'
# _ImportRequiredAssembly 'Microsoft.TeamFoundation.Client'
# _ImportRequiredAssembly 'Microsoft.VisualStudio.Services.WebApi'
# $runspace = [runspacefactory]::CreateRunspace()
# $pipeline = $runspace.CreatePipeline('_ImportRequiredAssembly "*"')
# $pipeline.Input.Close()
# $pipeline.InvokeAsync()
# # Load remaining assemblies asynchronously
# $libPath = Join-Path $PSScriptRoot 'lib'
# # $delegate = [Action[object]] {
# $assemblies = (Get-ChildItem "$libPath/*.dll" -Exclude 'Microsoft.WitDataStore*.*').BaseName
# Write-Verbose "Loading $($assemblies.Count) private assemblies"
# foreach($asm in $assemblies)
# {
# Write-Verbose "Loading assembly $asm from folder $libPath"
# try
# {
# Add-Type -Path (Join-Path $libPath "$asm.dll")
# }
# catch
# {
# Write-Warning ($_.Exception.LoaderExceptions | ConvertTo-Json -Depth 2)
# }
# }
<#
.SYNOPSIS
Gets information about one or more backlogs of the given team.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTeam
System.String
#>
Function Get-TfsTeamBacklog
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration')]
param
(
[Parameter(Position=0)]
[Alias("Name")]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration])})]
[SupportsWildcards()]
[object]
$Backlog = '*',
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
# #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
# #_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi'
}
Process
{
if ($Backlog -is [Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration]) { _Log "Input item is of type Microsoft.TeamFoundation.Work.WebApi.BacklogLevelConfiguration; returning input item immediately, without further processing."; return $Backlog }
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection
if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList @($tp.Name, $t.Name)
if (-not $Backlog.ToString().Contains('*'))
{
_Log "Get backlog '$Backlog'"
$task = $client.GetBacklogAsync($ctx, $Backlog)
$result = $task.Result; if($task.IsFaulted) { throw "Error getting backlog '$Backlog'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
else
{
_Log "Get all backlogs matching '$Backlog'"
$task = $client.GetBacklogsAsync($ctx)
$result = $task.Result; if($task.IsFaulted) { throw 'Error enumerating backlogs' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
$result = $result | Where-Object Name -like $Backlog
}
return $result
}
}
Function Get-TfsTeamBoard
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Work.WebApi.Board')]
Param
(
# Specifies the board name(s). Wildcards accepted
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias('Name')]
[object]
$Board = '*',
[Parameter()]
[switch]
$SkipDetails,
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
}
Process
{
if ($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board]) { _Log "Input item is of type Microsoft.TeamFoundation.Work.WebApi.Board; returning input item immediately, without further processing."; return $Board }
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name
_Log "Getting boards matching '$Board' in team '$($t.Name)'"
$task = $client.GetBoardsAsync($ctx); $result = $task.Result; if($task.IsFaulted) { throw 'Error retrieving team boards' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
$boardRefs = $result | Where-Object Name -like $Board
_Log "Found $($boardRefs.Count) boards matching '$Board' in team '$($t.Name)'"
if($SkipDetails.IsPresent)
{
_Log "SkipDetails switch is present. Returning board references without details"
return $boardRefs
}
foreach($b in $boardRefs)
{
_Log "Fetching details for board '$($b.Name)'"
$task = $client.GetBoardAsync($ctx, $b.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error fetching board data" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
Write-Output $result
}
}
}
Function Get-TfsTeamBoardCardRuleSettings
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings')]
Param
(
[Parameter()]
[SupportsWildcards()]
[object]
$Board = '*',
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
}
Process
{
if($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board])
{
$boards = @($Board.Name)
$Team = ([uri] $b.Links.Links.team.Href).Segments[-1]
$Project = ([uri] $b.Links.Links.project.Href).Segments[-1]
_Log "Getting card rules for board $($Board.Name) in team $Team"
}
elseif ($Board.ToString().Contains('*'))
{
_Log "Getting card rules for boards matching '$Board' in team $Team"
$boards = (Get-TfsTeamBoard -Board $Board -SkipDetails -Team $Team -Project $Project -Collection $Collection).Name
_Log "$($boards.Count) board(s) found matching '$Board'"
}
else
{
_Log "Getting card rules for board $($Board.Name) in team $Team"
$boards = @($Board)
}
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc
foreach($boardName in $boards)
{
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name
_Log "Fetching card rule settings for board $boardName"
$task = $client.GetBoardCardRuleSettingsAsync($ctx,$boardName); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving card rule settings for board '$Board'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
Write-Output $result `
| Add-Member -Name 'Team' -MemberType NoteProperty -Value $t.Name -PassThru `
| Add-Member -Name 'Project' -MemberType NoteProperty -Value $tp.Name -PassThru
}
}
}
Function Set-TfsTeamBoardCardRuleSettings
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings')]
Param
(
[Parameter()]
[object]
$Board,
[Parameter(ParameterSetName="Bulk set")]
[Microsoft.TeamFoundation.Work.WebApi.BoardCardRuleSettings]
$Rules,
[Parameter(ParameterSetName="Set individual rules")]
[string]
$CardStyleRuleName,
[Parameter(ParameterSetName="Set individual rules")]
[string]
$CardStyleRuleFilter,
[Parameter(ParameterSetName="Set individual rules")]
[hashtable]
$CardStyleRuleSettings,
[Parameter(ParameterSetName="Set individual rules")]
[string]
$TagStyleRuleName,
[Parameter(ParameterSetName="Set individual rules")]
[string]
$TagStyleRuleFilter,
[Parameter(ParameterSetName="Set individual rules")]
[hashtable]
$TagStyleRuleSettings,
[Parameter(ValueFromPipeline=$true)]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.VisualStudio.Services.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Work.WebApi'
}
Process
{
Write-Verbose "Getting card rules for team $Team"
if($Board -is [Microsoft.TeamFoundation.Work.WebApi.Board])
{
$boards = @($Board.Name)
$Team = ([uri] $b.Links.Links.team.Href).Segments[-1]
$Project = ([uri] $b.Links.Links.project.Href).Segments[-1]
}
elseif ($Board.ToString().Contains('*'))
{
$boards = (Get-TfsTeamBoard -Board $Board -Team $Team -Project $Project -Collection $Collection).Name
}
else
{
$boards = @($Board)
}
$t = Get-TfsTeam -Team $Team -Project $Project -Collection $Collection; if ($t.Count -ne 1) {throw "Invalid or non-existent team '$Team'."}; if($t.ProjectName) {$Project = $t.ProjectName}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Work.WebApi.WorkHttpClient' -Collection $tpc
foreach($boardName in $boards)
{
$ctx = New-Object 'Microsoft.TeamFoundation.Core.WebApi.Types.TeamContext' -ArgumentList $tp.Name, $t.Name
$task = $client.GetBoardCardRuleSettingsAsync($ctx,$boardName); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving card rule settings for board '$Board'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
Write-Output $result `
| Add-Member -Name 'Team' -MemberType NoteProperty -Value $t.Name -PassThru `
| Add-Member -Name 'Project' -MemberType NoteProperty -Value $tp.Name -PassThru
}
}
}
Function Set-TfsWorkItemBoardStatus
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItem')]
Param
(
[Parameter(ValueFromPipeline=$true, Position=0)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter()]
[object]
$Board,
[Parameter()]
[object]
$Column,
[Parameter()]
[object]
$Lane,
[Parameter()]
[ValidateSet('Doing', 'Done')]
[string]
$ColumnStage,
[Parameter()]
[object]
$Team,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi'
}
Process
{
if ((-not $Column) -and (-not $ColumnStage) -and (-not $Lane))
{
throw 'Supply a value to at least one of the following arguments: Column, ColumnStage, Lane'
}
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
$tp = $WorkItem.Project
$tpc = $WorkItem.Store.TeamProjectCollection
}
else
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$tpc = $tp.Store.TeamProjectCollection
$WorkItem = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
}
$t = Get-TfsTeam -Team $Team -Project $tp -Collection $tpc
$id = [int] $WorkItem.Id
$rev = $WorkItem.Revision
# Get the Kanban board column/lane field info
$b = Get-TfsBoard -Board $Board -Team $t -Project $tp -Collection $tpc
if (-not $b)
{
throw "Invalid or non-existent board '$Board' in team '$Team'"
}
$processMessages = @()
$ops = @(
@{
Operation = 'Test';
Path = '/rev';
Value = $rev.ToString()
}
)
if ($Column)
{
$ops += @{
Operation = 'Add';
Path = "/fields/$($b.Fields.ColumnField.ReferenceName)";
Value = $Column
}
$processMessages += "Board Column='$Column'"
}
if ($Lane)
{
$ops += @{
Operation = 'Add';
Path = "/fields/$($b.Fields.RowField.ReferenceName)";
Value = $Lane
}
$processMessages += "Board Lane='$Lane'"
}
if ($ColumnStage)
{
$ops += @{
Operation = 'Add';
Path = "/fields/$($b.Fields.DoneField.ReferenceName)";
Value = ($ColumnStage -eq 'Done')
}
$processMessages += "Board Stage (Doing/Done)='$ColumnStage'"
}
if ($PSCmdlet.ShouldProcess("$($WorkItem.WorkItemType) $id ('$($WorkItem.Title)')", "Set work item board status: $($processMessages -join ', ')"))
{
$patch = _GetJsonPatchDocument $ops
$client = _GetRestClient 'Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItemTrackingHttpClient' -Collection $tpc
$wi = $client.UpdateWorkItemAsync($patch, $id).Result
return $wi
}
}
}
<#
.SYNOPSIS
Gets the history of changes of a work item.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.EXAMPLE
Get-TfsWorkItem -Filter '[System.WorkItemType] = "Task"' | Foreach-Object { Write-Output "WI $($_.Id): $($_.Title)"; Get-TfsWorkItemHistory -WorkItem $_ }
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
System.Int32
#>
Function Get-TfsWorkItemHistory
{
[CmdletBinding()]
[OutputType('PSCustomObject')]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter()]
[object]
$Collection
)
Process
{
$wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
$latestRev = $wi.Revisions.Count - 1
0..$latestRev | Foreach-Object {
$rev = $wi.Revisions[$_]
[PSCustomObject] @{
Revision = $_ + 1;
ChangedDate = $rev.Fields['System.ChangedDate'].Value
ChangedBy = $rev.Fields['System.ChangedBy'].Value
Changes = _GetChangedFields $wi $_
}
}
}
}
Function _GetChangedFields([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem] $wi, [int] $rev)
{
$result = @{}
$wi.Revisions[$rev].Fields | Where-Object IsChangedInRevision -eq $true | Foreach-Object {
$result[$_.ReferenceName] = [PSCustomObject] @{
NewValue = $_.Value;
OriginalValue = $_.OriginalValue
}
}
return $result
}
<#
.SYNOPSIS
Add a link between two work items
.DESCRIPTION
Add-TfsWorkItemLink permits the creation of a link between two work items. By linking work items and other objects, you can track related work, dependencies, and changes made over time. All links are defined with a specific link type. For example, you can use Parent/Child links to link work items to support a hierarchical tree structure.
.PARAMETER SourceWorkItem
The first work item (the "leftmost") in a link relationship. For instance, in a Parent-Child relationship, that would be the Parent.
.PARAMETER TargetWorkItem
The second work item (the "rightmost") in a link relationship. For instance, in a Parent-Child relationship, that would be the Child.
.PARAMETER EndLinkType
Determines the kind of link to be created. This argument always refer to the Target (or "end") work item, in order to define directionality. In other words, to create a Parent-Child between a Source (parent) and a Target (child) work items, EndLinkType would be "Child". To learn more about the supported link types, see Get-TfsWorkItemLinkEndType.
.PARAMETER Comment
Add a comment to a link. Link comments can be seen in a work item form's "Links" tab.
.PARAMETER SkipSave
Leaves the source work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the source work item object to persist the newly created link.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.EXAMPLE
Add-TfsWorkItemLink -SourceWorkItem 1 -TargetWorkItem 2 -EndLinkType Child
Creates a parent-child relationship between work items with IDs #1 (source, parent) and #2 (target, child)
.LINK
https://www.visualstudio.com/en-us/docs/work/track/link-work-items-support-traceability
.LINK
Get-TfsWorkItemLinkEndType
#>
Function Add-TfsWorkItemLink
{
[CmdletBinding()]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("Id")]
[Alias("From")]
[ValidateNotNull()]
[object]
$SourceWorkItem,
[Parameter(Position=1, Mandatory=$true)]
[Alias("To")]
[ValidateNotNull()]
[object]
$TargetWorkItem,
[Parameter(Position=2, Mandatory=$true)]
[Alias("LinkType")]
[Alias("Type")]
[object]
$EndLinkType,
[Parameter()]
[string]
$Comment,
[switch]
$SkipSave,
[Parameter()]
[object]
$Collection
)
Process
{
$sourceWi = Get-TfsWorkItem -WorkItem $SourceWorkItem -Collection $Collection -Project $Project
$targetWi = Get-TfsWorkItem -WorkItem $TargetWorkItem -Collection $Collection -Project $Project
if ($EndLinkType -isnot [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd])
{
try
{
$EndLinkType = $sourceWi.Store.WorkItemLinkTypes.LinkTypeEnds[$EndLinkType]
}
catch
{
throw "Error retrieving work item link type $EndLinkType`: $_"
}
}
$link = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLink' -ArgumentList $EndLinkType, $targetWi.Id
$link.Comment = $Comment
$i = $sourceWi.WorkItemLinks.Add($link)
if (-not $SkipSave)
{
$sourceWi.Save()
}
return $sourceWi.WorkItemLinks[$i]
}
}
<#
.SYNOPSIS
Gets the links of a work item.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsWorkItemLink
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.Link')]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter()]
[object]
$Collection
)
Process
{
$wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
if ($wi)
{
return $wi.Links
}
}
}
<#
.SYNOPSIS
Gets the work item link end types of a team project collection.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
#>
Function Get-TfsWorkItemLinkEndType
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd')]
Param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
return $tpc.WorkItemStore.WorkItemLinkTypes.LinkTypeEnds
}
}
@{
Description = 'This module contains cmdlets to query, edit and administer work items queries'
ModuleVersion = '0.0.0'
RootModule = 'WorkItemQuery.psm1'
PrivateData = @{
FriendlyName = 'Work Item Query'
}
}
<#
.SYNOPSIS
Exports a saved work item query to XML.
.DESCRIPTION
Work item queries can be exported to XML files (.WIQ extension) in order to be shared and reused. Visual Studio Team Explorer has the ability to open and save WIQ files. Use this cmdlet to generate WIQ files compatible with the format supported by Team Explorer.
.PARAMETER Query
Name of the work item query to be exported. Wildcards are supported.
.PARAMETER Folder
Full path of the folder containing the query(ies) to be exported. Wildcards are supported.
.PARAMETER Destination
Path to the target directory where the exported work item query (WIQL file) will be saved. The original folder structure (as defined in TFS/VSTS) will be preserved.
.PARAMETER Encoding
XML encoding of the generated WIQL files. If omitted, defaults to UTF-8.
.PARAMETER Collection
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
.EXAMPLE
Export-TfsWorkItemQuery
.LINK
https://www.visualstudio.com/en-us/docs/work/reference/process-templates/define-work-item-query-process-template
.NOTES
For queries made against Team Services, the WIQL length must not exceed 32K characters. The system won't allow you to create or run queries that exceed that length.
#>
Function Export-TfsWorkItemQuery
{
[CmdletBinding(DefaultParameterSetName='Export to output stream', SupportsShouldProcess=$true)]
[OutputType('xml')]
Param
(
[Parameter(ValueFromPipeline=$true, Position=0)]
[SupportsWildcards()]
[string]
$Query = "**/*",
[Parameter()]
[ValidateSet('Personal', 'Shared', 'Both')]
[string]
$Scope = 'Both',
[Parameter(ParameterSetName="Export to file", Mandatory=$true)]
[string]
$Destination,
[Parameter(ParameterSetName="Export to file")]
[string]
$Encoding = "UTF-8",
[Parameter(ParameterSetName="Export to file")]
[switch]
$FlattenFolders,
[Parameter(ParameterSetName="Export to file")]
[switch]
$Force,
[Parameter(ParameterSetName="Export to output stream")]
[switch]
$AsXml,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($PSCmdlet.ParameterSetName -eq 'Export to output stream')
{
$Encoding = 'UTF-16'
}
else
{
if (-not (Test-Path $Destination -PathType Container))
{
_Log "Destination path '$Destination' not found."
if ($Force)
{
_Log "-Force switch specified. Creating output directory."
if($PSCmdlet.ShouldProcess($Destination, 'Create output directory'))
{
New-Item $Destination -ItemType Directory | _Log
}
}
else
{
throw "Invalid output path $Destination"
}
}
}
$queries = Get-TfsWorkItemQuery -Query $Query -Scope $Scope -Project $Project -Collection $Collection
if (-not $queries)
{
throw "No work item queries match the specified `"$Query`" pattern supplied."
}
foreach($q in $queries)
{
$xml = [xml]@"
<?xml version="1.0" encoding="$Encoding"?>
<!-- Original Query Path: $($q.Path) -->
<WorkItemQuery Version="1">
<TeamFoundationServer>$($q.Project.Store.TeamProjectCollection.Uri)</TeamFoundationServer>
<TeamProject>$($q.Project.Name)</TeamProject>
<Wiql><![CDATA[$($q.QueryText)]]></Wiql>
</WorkItemQuery>
"@
if (-not $Destination)
{
if ($AsXml)
{
Write-Output $xml
}
else
{
Write-Output $xml.OuterXml
}
continue
}
if ($FlattenFolders)
{
$queryPath = $q.Name
}
else
{
$queryPath = $q.Path.Substring($q.Path.IndexOf('/')+1)
}
$fileName = _GetAbsolutePath (Join-Path $Destination "$queryPath.wiql")
_Log "Exporting query $($q.Name) to path '$fileName'"
if((Test-Path $fileName) -and (-not $Force))
{
throw "File $fileName already exists. To overwrite an existing file, use the -Force switch"
}
if($PSCmdlet.ShouldProcess($fileName, "Save query '$($q.Name)'"))
{
$xml.Save($fileName)
}
}
}
}
<#
.SYNOPSIS
Gets the definition of one or more work item saved queries.
.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsWorkItemQuery
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
Param
(
[Parameter(Position=0)]
[ValidateNotNull()]
[SupportsWildcards()]
[Alias("Path")]
[object]
$Query = '**/*',
[Parameter()]
[ValidateSet('Personal', 'Shared', 'Both')]
[string]
$Scope = 'Both',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($Query -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition2])
{
return $Query
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$qh = $tp.GetQueryHierarchy2($true)
$qh.GetChildrenAsync().Wait()
$rootFolders = ($qh.GetChildren() | Where-Object {$Scope -eq 'Both' -or $_.IsPersonal -eq ($Scope -eq 'Personal')})
$rootFolders | _GetQueriesRecursively | Where-Object {($_.Path -like $Query) -or ($_.Name -like $Query) -or ($_.RelativePath -like $Query)} | Sort-Object ParentPath, Name
}
}
<#
.SYNOPSIS
Gets the definition of one or more work item saved queries.
.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsWorkItemQueryFolder
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder')]
Param
(
[Parameter(Position=0)]
[ValidateNotNull()]
[SupportsWildcards()]
[Alias("Path")]
[object]
$Folder = '**/*',
[Parameter()]
[ValidateSet('Personal', 'Shared', 'Both')]
[string]
$Scope = 'Both',
[Parameter()]
[timespan]
$Timeout = '00:00:10',
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if($Folder -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2])
{
return $Folder
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$qh = $tp.GetQueryHierarchy2($false)
$qh.GetChildrenAsync().Wait()
$qh = $tp.GetQueryHierarchy2($true)
$qh.GetChildrenAsync().Wait()
$rootFolders = ($qh.GetChildren() | Where-Object {$Scope -eq 'Both' -or $_.IsPersonal -eq ($Scope -eq 'Personal')})
$rootFolders | _GetQueryFoldersRecursively | Where-Object {($_.Path -like $Folder) -or ($_.Name -like $Folder)} | Sort-Object ParentPath, Name
}
}
<#
.SYNOPSIS
Create a new work items query in the given Team Project.
.PARAMETER Query
Specifies the path of the new work item query.
When supplying a path, use a slash ("/") between the path segments. Leading and trailing slashes are optional. The last segment in the path will be the query name.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function New-TfsWorkItemQuery
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Name")]
[Alias("Path")]
[string]
$Query,
[Parameter()]
[string]
$Folder,
[Parameter()]
[ValidateSet('Personal', 'Shared')]
[string]
$Scope = 'Personal',
[Parameter(Mandatory=$true)]
[string]
$Definition,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Force,
[Parameter()]
[switch]
$SkipSave,
[Parameter()]
[switch]
$Passthru
)
Begin
{
_RegisterQueryHelper
}
Process
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$qh = $tp.GetQueryHierarchy2($true)
$qh.GetChildrenAsync().Wait()
$rootFolder = ($qh.GetChildren() | Where-Object IsPersonal -eq ($Scope -eq 'Personal'))
$fullPath = _NormalizeQueryPath -Path "$Folder/$Query" -RootFolder $rootFolder.Name -ProjectName $tp.Name
$queryPath = $fullPath.Substring(0, $fullPath.LastIndexOf('/'))
$queryName = $fullPath.Substring($fullPath.LastIndexOf('/')+1)
$relativeQueryPath = $fullPath.Substring($rootFolder.Name.Length + $tp.Name.Length + 2)
$relativeFolderPath = $queryPath.Substring($rootFolder.Name.Length + $tp.Name.Length + 2)
if (-not $PSCmdlet.ShouldProcess($queryName, "Create work item query under folder '$queryPath'"))
{
return
}
_Log "New-TfsWorkItemQuery: Check if query '$relativeQueryPath' exists"
$existingQuery = Get-TfsWorkItemQuery -Query $relativeQueryPath -Scope $Scope -Project $Project -Collection $Collection
if ($existingQuery)
{
if (-not $Force)
{
throw "Work item query '$fullPath' already exists. To overwrite an existing query, use the -Force switch"
}
_Log "New-TfsWorkItemQuery: Existing query '$fullPath' will be overwritten"
$existingQuery.Delete()
$existingQuery.Save()
}
_Log "New-TfsWorkItemQuery: Creating query '$queryName' in folder '$queryPath'"
$queryFolder = Get-TfsWorkItemQueryFolder -Folder $relativeFolderPath -Scope $Scope -Project $Project -Collection $Collection
if (-not $queryFolder)
{
_Log "New-TfsWorkItemQuery: Destination folder $queryFolder not found"
if ($Force)
{
_Log "New-TfsWorkItemQuery: -Force switch specified. Creating missing folder"
$queryFolder = New-TfsWorkItemQueryFolder -Path $queryPath -Project $tp.Name -Passthru
}
else
{
throw "Invalid or non-existent work item query folder $queryPath."
}
}
if ($Definition -match "select \*")
{
Write-Warning "New-TfsWorkItemQuery: Queries containing 'SELECT *' may not work in Visual Studio. Consider replacing * with a list of fields."
}
$q = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition2' -ArgumentList $queryName, $Definition, $queryFolder
if (-not $SkipSave)
{
$q.Save()
}
else
{
_Log "New-TfsWorkItemQuery: -SkipSave switch specified. Newly created query will not be saved."
}
if ($Passthru -or $SkipSave)
{
return $q
}
}
}
<#
.SYNOPSIS
Create a new work items query in the given Team Project.
.PARAMETER Path
Specifies the path of the new work item query folder.
When supplying a path, use a slash ("/") between the path segments. Leading and trailing backslashes are optional. The last segment in the path will be the query name.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.String
#>
Function New-TfsWorkItemQueryFolder
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[string]
[Alias("Name")]
[Alias("Path")]
$Folder,
[Parameter()]
[ValidateSet('Personal', 'Shared')]
[string]
$Scope = 'Personal',
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[switch]
$Passthru
)
Begin
{
_RegisterQueryHelper
}
Process
{
if($PSCmdlet.ShouldProcess($Folder, 'Create work item query folder'))
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
#$tpc = $tp.Store.TeamProjectCollection
#$store = $tp.Store
if ($Scope -eq 'Shared')
{
$rootFolder = 'Shared Queries'
}
else
{
$rootFolder = 'My Queries'
}
$normalizedPath = _NormalizeQueryPath -Path $Folder -RootFolder $rootFolder -ProjectName $tp.Name
_Log "New-TfsWorkItemQueryFolder: Creating folder '$Folder'"
$queryFolder = [TfsCmdlets.QueryHelper]::CreateFolder($tp.QueryHierarchy, $normalizedPath)
if ($Passthru)
{
return $queryFolder
}
}
}
}
<#
.SYNOPSIS
Deletes one or more work item queries from the specified Team Project..
.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Remove-TfsWorkItemQuery
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateNotNull()]
[object]
$Query,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$queries = Get-TfsWorkItemQuery -Query $Query -Project $Project -Collection $Collection
foreach($q in $queries)
{
if ($PSCmdlet.ShouldProcess($q.Path, "Delete Query"))
{
$q.Delete()
}
}
}
}
<#
.SYNOPSIS
Deletes one or more work item queries from the specified Team Project..
.PARAMETER Query
Specifies the path of a saved query. Wildcards are supported.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Remove-TfsWorkItemQueryFolder
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("Path")]
[ValidateNotNull()]
[object]
$Folder,
[Parameter()]
[object]
$Project,
[Parameter()]
[switch]
$Force,
[Parameter()]
[object]
$Collection
)
Process
{
$folder = Get-TfsWorkItemQueryFolder -Folder $Folder -Project $Project -Collection $Collection
if (($folder.Count -ne 0) -and (-not $Force))
{
throw "Folder is not empty. To delete a folder and its contents, use the -Force switch"
}
if ($PSCmdlet.ShouldProcess($folder, "Delete work item query folder"))
{
$folder.Delete()
$folder.Project.Hierarchy.Save()
}
}
}
<#
.SYNOPSIS
Changes the value of a property of an Area.
.PARAMETER Area
Specifies the name, URI or path of an Area. Wildcards are permitted. If omitted, all Areas in the given Team Project are returned.
To supply a path, use a backslash ('\') between the path segments. Leading and trailing backslashes are optional.
When supplying a URI, use URIs in the form of 'vstfs:///Classification/Node/<GUID>' (where <GUID> is the unique identifier of the given node)
.PARAMETER NewName
Specifies the new name of the area. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-Tfsarea generates an error. To rename and move an item, use the Move-Tfsarea cmdlet.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Rename-TfsWorkItemQuery
{
[CmdletBinding(ConfirmImpact='Medium')]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateNotNull()]
[Alias("Path")]
[object]
$Query,
[Parameter()]
[string]
$NewName,
[Parameter()]
[string]
$Definition,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Process
{
$result = Set-TfsWorkItemQuery -Query $Query -NewName $NewName -Project $Project -Collection $Collection -Passthru:$Passthru.IsPresent
if ($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Changes the value of a property of a work item query.
.PARAMETER Query
Specifies the path of a work item saved query.
.PARAMETER NewName
Specifies the new name of the query. Enter only a name, not a path and name. If you enter a path that is different from the path that is specified in the area parameter, Rename-TfsWorkItemQuery generates an error. To rename and move an item, use the Move-TfsWorkItemQuery cmdlet instead.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition
System.String
#>
Function Set-TfsWorkItemQuery
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[ValidateNotNull()]
[Alias("Path")]
[object]
$Query,
[Parameter()]
[string]
$NewName,
[Parameter()]
[string]
$Definition,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$q = Get-TfsWorkItemQuery -Query $Query -Project $Project -Collection $Collection
if (-not $q)
{
throw "Invalid or non-existent work item query $queries"
}
if ($q.Count -ne 1)
{
throw "Ambiguous query name '$Query'. $($q.Count) queries were found matching the specified name/pattern:`n`n - " + ($q -join "`n - ")
}
if ($NewName -and $PSCmdlet.ShouldProcess($Query, "Rename work item query to '$NewName'"))
{
isDirty = $true
$q.Name = $NewName
}
if ($Definition -and $PSCmdlet.ShouldProcess($Query, "Change work item query definition to '$Definition'"))
{
isDirty = $true
$q.QueryText = $Definition
}
if ($isDirty)
{
$q.Project.QueryHierarchy.Save()
}
return $q
}
}
Function _NormalizeQueryPath($Path, $RootFolder, $ProjectName)
{
if([string]::IsNullOrWhiteSpace($Path))
{
return [string]::Empty
}
$newPath = [System.Text.RegularExpressions.Regex]::Replace($Path, '\\+|/{2,}', '/')
if ($newPath.StartsWith("/"))
{
$newPath = $newPath.Substring(1)
}
if ($newPath.EndsWith('/'))
{
$newPath = $newPath.Substring(0, $newPath.Length-1)
}
$pattern = "($ProjectName/)?($RootFolder/)?(.+)"
$match = [regex]::Match($newPath, $pattern)
return "$ProjectName/$RootFolder/$($match.Groups[$match.Groups.Count-1])"
}
Function _RegisterQueryHelper()
{
if (([System.Management.Automation.PSTypeName]'TfsCmdlets.QueryHelper').Type)
{
return
}
Add-Type -Language CSharp -ReferencedAssemblies 'Microsoft.TeamFoundation.WorkItemTracking.Client' `
-TypeDefinition @'
${File:CSharp\QueryHelper.cs}
'@
}
Function _GetQueryFoldersRecursively
{
Param
(
[Parameter(ValueFromPipeline=$true)]
[Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]
$Folder
)
Process
{
$Folder.GetChildrenAsync().Wait()
$Folder.GetChildren() | Where-Object {$_ -Is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]} | ForEach-Object {
Write-Output $_
_GetQueryFoldersRecursively $_
}
}
}
Function _GetQueriesRecursively
{
Param
(
[Parameter(ValueFromPipeline=$true)]
[Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2]
$Folder
)
Process
{
$Folder.GetChildrenAsync().Wait()
foreach($i in $Folder.GetChildren())
{
if ($i -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder2])
{
_GetQueriesRecursively $i
}
else
{
Write-Output $i
}
}
}
}
<#
.SYNOPSIS
Gets one or more work item tags
.DESCRIPTION
.EXAMPLE
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.OUTPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
.NOTES
#>
Function Get-TfsWorkItemTag
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition')]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias('Name')]
[object]
$Tag = '*',
[Parameter()]
[switch]
$IncludeInactive,
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
}
Process
{
if ($Tag -is [Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition]) { _Log "Input item is of type Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition; returning input item immediately, without further processing."; return $Tag }
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc
$task = $client.GetTagsAsync($tp.Guid, $IncludeInactive.IsPresent); $result = $task.Result; if($task.IsFaulted) { throw "Error retrieving work item tag '$Tag'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return $result | Where-Object Name -like $Tag | Add-Member -Name TeamProject -MemberType NoteProperty -Value $TP.Name -PassThru
}
}
<#
.SYNOPSIS
Gets one or more work item tags
.DESCRIPTION
.EXAMPLE
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
.OUTPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
.NOTES
#>
Function New-TfsWorkItemTag
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition')]
Param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[Alias('Name')]
[string]
$Tag,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
}
Process
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
if(-not $PSCmdlet.ShouldProcess($tp.Name, "Create work item tag '$Tag'"))
{
return
}
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc
$task = $client.CreateTagAsync($tp.Guid, $Tag); $result = $task.Result; if($task.IsFaulted) { throw "Error creating work item tag '$Tag'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
if($Passthru)
{
return $result
}
}
}
<#
.SYNOPSIS
Deletes one or more work item tags
.DESCRIPTION
.EXAMPLE
.INPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
System.String
.NOTES
#>
Function Remove-TfsWorkItemTag
{
[CmdletBinding(ConfirmImpact='High', SupportsShouldProcess=$true)]
Param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[SupportsWildcards()]
[Alias('Name')]
[object]
$Tag = '*',
[Parameter()]
[switch]
$IncludeInactive,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
}
Process
{
$tags = Get-TfsWorkItemTag -Tag $Tag -Project $Project -Collection $Collection
foreach($t in $tags)
{
if($t.TeamProject) {$Project = $t.TeamProject}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
if(-not $PSCmdlet.ShouldProcess($tp.Name, "Delete work item tag [$($t.Name)]"))
{
continue
}
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc
$task = $client.DeleteTagAsync($tp.Guid, $t.Id); $result = $task.Result; if($task.IsFaulted) { throw "Error deleting work item tag [$($t.Name)]'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
}
}
}
<#
.SYNOPSIS
Deletes one or more work item tags
.DESCRIPTION
.EXAMPLE
.INPUTS
Microsoft.TeamFoundation.Core.WebApi.WebApiTagDefinition
System.String
.NOTES
#>
Function Rename-TfsWorkItemTag
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
Param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[Alias('Name')]
[object]
$Tag,
[Parameter(Position=1)]
[string]
$NewName,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$Passthru
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.Core.WebApi'
}
Process
{
$tags = Get-TfsWorkItemTag -Tag $Tag -Project $Project -Collection $Collection
foreach($t in $tags)
{
if(-not $PSCmdlet.ShouldProcess($t.Name, "Rename work item tag to [$NewName]"))
{
continue
}
if($t.TeamProject) {$Project = $t.TeamProject}; $tp = Get-TfsTeamProject -Project $Project -Collection $Collection; if (-not $tp -or ($tp.Count -ne 1)) {throw "Invalid or non-existent team project $Project."}; $tpc = $tp.Store.TeamProjectCollection
$client = _GetRestClient 'Microsoft.TeamFoundation.Core.WebApi.TaggingHttpClient' -Collection $tpc
$task = $client.UpdateTagAsync($tp.Guid, $t.Id, $NewName, $t.Active); $result = $task.Result; if($task.IsFaulted) { throw "Error renaming work item tag [$($t.Name)]'" + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
if($Passthru.IsPresent)
{
return $result
}
}
}
}
<#
.SYNOPSIS
Creates a copy of a work item, optionally changing its type
.DESCRIPTION
Use this cmdlet to create a copy of a work item (using its latest saved state/revision data) that is of the specified work item type. By default, the copy retains the same type of the original work item, unless the Type argument is specified
.PARAMETER WorkItem
Specifies the work item to be copied. Can be either a work item ID or an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
.PARAMETER Type
Specifies the new type for the copy of the original work item. It can be provided as either a string representing the work item type name (e.g. "Bug" or "Task") or an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType. When an instance of WorkItemType is provided, the team project from where that WorkItemType object was retrieved will be used to define where to copy the work item into, unless the Project argument is specified
.PARAMETER IncludeAttachments
Includes attachments as part of the copy process. By default, only field values are copied
.PARAMETER IncludeLinks
Includes work item links as part of the copy process. By default, only field values are copied
.PARAMETER Project
Specified the team project where the work item will be copied into. If omitted, the copy will be created in the same team project of the source work item. The value provided to this argument takes precedence over both the source team project and the team project of an instance of WorkItemType provided to the Type argument
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.PARAMETER SkipSave
Leaves the new work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the new work item object to persist the copy.
.PARAMETER Passthru
Returns the results of the command. It takes one of the following values: Original (returns the original work item), Copy (returns the newly created work item copy) or None.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
System.Int32
.EXAMPLE
Copy-TfsWorkItem -WorkItem 123
Creates (and returns) a copy of a work item with ID #123
.EXAMPLE
Get-TfsWorkItem -Filter '[System.WorkItemType] = "Bug"' | Copy-TfsWorkItem -Type Task
Retrieves all work item of Bug type and copy them as Tasks
.LINK
https://msdn.microsoft.com/en-us/library/ff738070.aspx
#>
Function Copy-TfsWorkItem
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
Param
(
[Parameter(ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter()]
[object]
$Type,
[Parameter()]
[object]
$Project,
[Parameter()]
[switch]
$IncludeAttachments,
[Parameter()]
[switch]
$IncludeLinks,
[Parameter()]
[switch]
$SkipSave,
[Parameter()]
[ValidateSet('Original', 'Copy', 'None')]
[string]
$Passthru = 'Copy',
[Parameter()]
[object]
$Collection
)
Process
{
$wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
#$store = $wi.Store
if($Type)
{
if ($Project)
{
$tp = $Project
}
else
{
$tp = $wi.Project
}
$witd = Get-TfsWorkItemType -Type $Type -Project $tp -Collection $wi.Store.TeamProjectCollection
}
else
{
$witd = $wi.Type
}
$flags = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::None
if ($IncludeAttachments)
{
$flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyFiles
}
if ($IncludeLinks)
{
$flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyLinks
}
$copy = $wi.Copy($witd, $flags)
if(-not $SkipSave)
{
$copy.Save()
}
if ($Passthru -eq 'Original')
{
return $wi
}
if($Passthru -eq 'Copy')
{
return $copy
}
}
}
<#
.SYNOPSIS
Gets the contents of one or more work items.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsWorkItem
{
[CmdletBinding(DefaultParameterSetName="Query by text")]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
Param
(
[Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by revision")]
[Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by date")]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter(ParameterSetName="Query by revision")]
[Alias("rev")]
[int]
$Revision,
[Parameter(Mandatory=$true, ParameterSetName="Query by date")]
[datetime]
$AsOf,
[Parameter(Mandatory=$true, ParameterSetName="Query by WIQL")]
[Alias('WIQL')]
[Alias('QueryText')]
[Alias('SavedQuery')]
[Alias('QueryPath')]
[string]
$Query,
# [Parameter(Mandatory=$true, ParameterSetName="Query by filter")]
# [string[]]
# $Fields,
[Parameter(Mandatory=$true, ParameterSetName="Query by filter")]
[string]
$Filter,
[Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by text")]
[string]
$Text,
[Parameter()]
[hashtable]
$Macros,
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
}
Process
{
if ($Project)
{
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
$tpc = $tp.Store.TeamProjectCollection
$store = $tp.Store
}
else
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
}
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
if ((-Not $Revision) -and (-Not $AsOf))
{
return $WorkItem
}
}
switch($PSCmdlet.ParameterSetName)
{
"Query by revision" {
return _GetWorkItemByRevision $WorkItem $Revision $store
}
"Query by date" {
return _GetWorkItemByDate $WorkItem $AsOf $store
}
"Query by text" {
$localMacros = @{TfsQueryText=$Text}
$Wiql = "SELECT * FROM WorkItems WHERE [System.Title] CONTAINS @TfsQueryText OR [System.Description] CONTAINS @TfsQueryText"
return _GetWorkItemByWiql $Wiql $localMacros $tp $store
}
"Query by filter" {
$Wiql = "SELECT * FROM WorkItems WHERE $Filter"
return _GetWorkItemByWiql $Wiql $Macros $tp $store
}
"Query by WIQL" {
_Log "Get-TfsWorkItem: Running query by WIQL. Query: $Query"
return _GetWorkItemByWiql $Query $Macros $tp $store
}
"Query by saved query" {
return _GetWorkItemBySavedQuery $StoredQueryPath $Macros $tp $store
}
}
}
}
Function _GetWorkItemByRevision($WorkItem, $Revision, $store)
{
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
$ids = @($WorkItem.Id)
}
elseif ($WorkItem -is [int])
{
$ids = @($WorkItem)
}
elseif ($WorkItem -is [int[]])
{
$ids = $WorkItem
}
else
{
throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
}
if ($Revision -is [int] -and $Revision -gt 0)
{
foreach($id in $ids)
{
$store.GetWorkItem($id, $Revision)
}
}
elseif ($Revision -is [int[]])
{
if ($ids.Count -ne $Revision.Count)
{
throw "When supplying a list of IDs and Revisions, both must have the same number of elements"
}
for($i = 0; $i -le $ids.Count-1; $i++)
{
$store.GetWorkItem($ids[$i], $Revision[$i])
}
}
else
{
foreach($id in $ids)
{
$store.GetWorkItem($id)
}
}
}
Function _GetWorkItemByDate($WorkItem, $AsOf, $store)
{
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
$ids = @($WorkItem.Id)
}
elseif ($WorkItem -is [int])
{
$ids = @($WorkItem)
}
elseif ($WorkItem -is [int[]])
{
$ids = $WorkItem
}
else
{
throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
}
if ($AsOf -is [datetime[]])
{
if ($ids.Count -ne $AsOf.Count)
{
throw "When supplying a list of IDs and Changed Dates (AsOf), both must have the same number of elements"
}
for($i = 0; $i -le $ids.Count-1; $i++)
{
$store.GetWorkItem($ids[$i], $AsOf[$i])
}
}
else
{
foreach($id in $ids)
{
$store.GetWorkItem($id, $AsOf)
}
}
}
Function _GetWorkItemByWiql($QueryText, $Macros, $Project, $store)
{
if ($QueryText -notlike 'select*')
{
$q = Get-TfsWorkItemQuery -Query $QueryText -Project $Project
if (-not $q)
{
throw "Work item query '$QueryText' is invalid or non-existent."
}
if ($q.Count -gt 1)
{
throw "Ambiguous query name '$QueryText'. $($q.Count) queries were found matching the specified name/pattern:`n`n - " + ($q -join "`n - ")
}
$QueryText = $q.QueryText
}
if (-not $Macros -and (($QueryText -match "@project") -or ($QueryText -match "@me")))
{
$Macros = @{}
}
if ($QueryText -match "@project")
{
if (-not $Project)
{
$Project = Get-TfsTeamProject -Current
}
if (-not $Macros.ContainsKey("Project"))
{
$Macros["Project"] = $Project.Name
}
}
if ($QueryText -match "@me")
{
$user = $null
$store.TeamProjectCollection.GetAuthenticatedIdentity([ref] $user)
$Macros["Me"] = $user.DisplayName
}
_Log "Get-TfsWorkItem: Running query $QueryText"
$wis = $store.Query($QueryText, $Macros)
# foreach($wi in $wis)
# {
# if($Fields)
# {
# foreach($f in $Fields)
# {
# $wi | Add-Member -Name (_GetEncodedFieldName $f.ReferenceName) -MemberType ScriptProperty -Value `
# {$f.Value}.GetNewClosure() `
# {param($Value) $f.Value = $Value}.GetNewClosure()
# }
# }
# }
return $wis
}
Function Move-TfsWorkItem
{
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='High')]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
Param
(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter(Mandatory=$true, Position=1)]
[object]
$Destination,
[Parameter()]
[object]
$Area,
[Parameter()]
[object]
$Iteration,
[Parameter()]
[object]
$State,
[Parameter()]
[object]
$History,
[Parameter()]
[object]
$Collection
)
Begin
{
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.Client'
#_ImportRequiredAssembly -AssemblyName 'Microsoft.TeamFoundation.WorkItemTracking.WebApi'
}
Process
{
$wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
$targetTp = Get-TfsTeamProject -Project $Destination -Collection $Collection
$tpc = $targetTp.Store.TeamProjectCollection
if ($Area)
{
$targetArea = Get-TfsArea $Area -Project $targetTp
if (-not $targetArea)
{
if ($PSCmdlet.ShouldProcess("Team Project '$($targetTp.Name)'", "Create area path '$Area'"))
{
$targetArea = New-TfsArea $Area -Project $targetTp -Passthru
}
}
_Log "Moving to area $($targetTp.Name)$($targetArea.RelativePath)"
}
else
{
_Log 'Area not informed. Moving to root iteration.'
$targetArea = Get-TfsArea '' -Project $targetTp
}
if ($Iteration)
{
$targetIteration = Get-TfsIteration $Iteration -Project $targetTp
if (-not $targetIteration)
{
if ($PSCmdlet.ShouldProcess("Team Project '$($targetTp.Name)'", "Create iteration path '$Iteration'"))
{
$targetIteration = New-TfsIteration $Iteration -Project $targetTp -Passthru
}
}
_Log "Moving to iteration $($targetTp.Name)$($targetIteration.RelativePath)"
}
else
{
_Log 'Iteration not informed. Moving to root iteration.'
$targetIteration = Get-TfsIteration '' -Project $targetTp
}
$targetArea = "$($targetTp.Name)$($targetArea.RelativePath)"
$targetIteration = "$($targetTp.Name)$($targetIteration.RelativePath)"
$patch = _GetJsonPatchDocument @(
@{
Operation = 'Add';
Path = '/fields/System.TeamProject';
Value = $targetTp.Name
},
@{
Operation = 'Add';
Path = "/fields/System.AreaPath";
Value = $targetArea
},
@{
Operation = 'Add';
Path = "/fields/System.IterationPath";
Value = $targetIteration
}
)
if ($State)
{
$patch.Add( @{
Operation = 'Add';
Path = '/fields/System.State';
Value = $State
})
}
if ($History)
{
$patch.Add( @{
Operation = 'Add';
Path = '/fields/System.History';
Value = $History
})
}
if ($PSCmdlet.ShouldProcess("$($wi.WorkItemType) $($wi.Id) ('$($wi.Title)')",
"Move work item to team project '$($targetTp.Name)' under area path " +
"'$($targetArea)' and iteration path '$($targetIteration)'"))
{
$client = _GetRestClient 'Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItemTrackingHttpClient' -Collection $tpc
$task = $client.UpdateWorkItemAsync($patch, $wi.Id)
$result = $task.Result; if($task.IsFaulted) { throw 'Error moving work item' + ": $($task.Exception.InnerExceptions | ForEach-Object {$_.ToString()})" }
return Get-TfsWorkItem $result.Id -Collection $tpc
}
}
}
<#
.SYNOPSIS
Creates a new work item in a team project.
.PARAMETER Type
Represents the name of the work item type to create.
.PARAMETER Title
Specifies a Title field of new work item type that will be created.
.PARAMETER Fields
Specifies the fields that are changed and the new values to give to them.
FieldN The name of a field to update.
ValueN The value to set on the fieldN.
[field1=value1[;field2=value2;...]
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.EXAMPLE
New-TfsWorkItem -Type Task -Title "Task 1" -Project "MyTeamProject"
This example creates a new Work Item on Team Project "MyTeamProject".
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType
System.String
#>
Function New-TfsWorkItem
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem')]
Param
(
[Parameter(ValueFromPipeline=$true, Mandatory=$true, Position=0)]
[object]
$Type,
[Parameter(Position=1)]
[string]
$Title,
[Parameter()]
[hashtable]
$Fields,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[switch]
$SkipSave,
[Parameter()]
[switch]
$Passthru
)
Process
{
if($PSCmdlet.ShouldProcess($Type, 'Create work item of specified type'))
{
$wit = Get-TfsWorkItemType -Type $Type -Project $Project -Collection $Collection
$wi = $wit.NewWorkItem()
if ($Title)
{
$wi.Title = $Title
}
foreach($field in $Fields)
{
$wi.Fields[$field.Key] = $field.Value
}
if (-not $SkipSave.IsPresent)
{
$wi.Save()
}
if ($Passthru)
{
return $wi
}
}
}
}
<#
.SYNOPSIS
Deletes a work item from a team project collection.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
System.Int32
#>
Function Remove-TfsWorkItem
{
[CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter()]
[object]
$Collection
)
Process
{
$ids = @()
foreach($wi in $WorkItem)
{
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
$id = $WorkItem.Id
}
elseif ($WorkItem -is [int])
{
$id = $WorkItem
}
else
{
throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
}
if ($PSCmdlet.ShouldProcess("$($wi.WorkItemType) $id ('$($wi.Title)')", "Remove work item"))
{
$ids += $id
}
}
if ($ids.Count -gt 0)
{
$tpc = Get-TfsTeamProjectCollection $Collection
$store = $tpc.GetService([type] "Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore")
$errors = $store.DestroyWorkItems([int[]] $ids)
if ($errors -and ($errors.Count -gt 0))
{
$errors | Write-Error "Error $($_.Id): $($_.Exception.Message)"
throw "Error destroying one or more work items"
}
}
}
}
<#
.SYNOPSIS
Sets the contents of one or more work items.
.PARAMETER SkipSave
Leaves the work item in a "dirty" (unsaved) state, by not calling its Save() method. It is useful for when subsequents changes need to be made to the work item object before saving it. In that case, it is up to the user to later invoke the Save() method on the work item object to persist the changes.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
#>
Function Set-TfsWorkItem
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
Param
(
[Parameter(ValueFromPipeline=$true, Position=0)]
[Alias("id")]
[ValidateNotNull()]
[object]
$WorkItem,
[Parameter(Position=1)]
[hashtable]
$Fields,
[Parameter()]
[switch]
$BypassRules,
[Parameter()]
[switch]
$SkipSave,
[Parameter()]
[object]
$Collection
)
Process
{
if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
{
$tpc = $WorkItem.Store.TeamProjectCollection
$id = $WorkItem.Id
}
else
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
$id = (Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection).Id
}
if ($BypassRules)
{
$store = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore' -ArgumentList $tpc, [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStoreFlags]::BypassRules
}
else
{
$store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
}
$wi = $store.GetWorkItem($id)
$Fields = _FixAreaIterationValues -Fields $Fields -ProjectName $wi.Project.Name
if($PSCmdlet.ShouldProcess("Set work item fields $($Fields.Keys -join ', ') to $($Fields.Values -join ', '), respectively"))
{
foreach($fldName in $Fields.Keys)
{
$wi.Fields[$fldName].Value = $Fields[$fldName]
}
if(-not $SkipSave)
{
$wi.Save()
}
}
return $wi
}
}
Function _FixAreaIterationValues([hashtable] $Fields, $ProjectName)
{
if ($Fields.ContainsKey('System.AreaPath') -and ($Fields['System.AreaPath'] -notmatch "'\\?$ProjectName\\.+'"))
{
$Fields['System.AreaPath'] = ("$ProjectName\$($Fields['System.AreaPath'])" -replace '\\', '\')
}
if ($Fields.ContainsKey('System.IterationPath') -and ($Fields['System.IterationPath'] -notmatch "'\\?$ProjectName\\.+'"))
{
$Fields['System.IterationPath'] = ("$ProjectName\$($Fields['System.IterationPath'])" -replace '\\', '\')
}
return $Fields
}
Function _GetEscapedFieldName([string] $fieldName)
{
$fieldName = $fieldName.Trim()
if(-not $fieldName.StartsWith('['))
{
$fieldName = '[' + $fieldName
}
if(-not $fieldName.EndsWith(']'))
{
$fieldName += ']'
}
return $fieldName
}
Function _GetEncodedFieldName([string] $fieldName)
{
return $fieldName.Trim(' ', '[', ']') -replace '[/W]', '_'
}
@{
Description = 'This module contains cmdlets to query, edit and administer work items'
ModuleVersion = '0.0.0'
RootModule = 'WorkItem.psm1'
PrivateData = @{
FriendlyName = 'WorkItem'
}
}
<#
.SYNOPSIS
Exports a work item type definition from a team project to XML.
.PARAMETER Name
Uses this parameter to filter for an specific Work Item Type.
If suppress, cmdlet will return all Work Item Types on XML format.
.PARAMETER IncludeGlobalLists
Exports the definitions of referenced global lists. If not specified, global list definitions are omitted.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Export-TfsWorkItemType
{
[CmdletBinding()]
[OutputType('Xml')]
Param
(
[Parameter()]
[Alias('Name')]
[SupportsWildcards()]
[string]
$WorkItemType = "*",
[Parameter()]
[switch]
$IncludeGlobalLists,
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$types = Get-TfsWorkItemType -Name $WorkItemType -Project $Project -Collection $Collection
foreach($type in $types)
{
$type.Export($IncludeGlobalLists)
}
}
}
<#
.SYNOPSIS
Gets one or more Work Item Type definitions from a team project.
.PARAMETER Name
Uses this parameter to filter for an specific Work Item Type.
If suppress, cmdlet will show all Work Item Types.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.EXAMPLE
Get-TfsWorkItemType -Name "Task" -Project "My Team Project"
Get informations about Work Item Type "Task" of a team project name "My Team Project"
.EXAMPLE
Get-TfsWorkItemType -Project "My Team Project"
Get all Work Item Types of a team project name "My Team Project"
.INPUTS
Microsoft.TeamFoundation.WorkItemTracking.Client.Project
System.String
#>
Function Get-TfsWorkItemType
{
[CmdletBinding()]
[OutputType('Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType')]
Param
(
[Parameter(Position=0)]
[SupportsWildcards()]
[Alias("Name")]
[object]
$Type = "*",
[Parameter(ValueFromPipeline=$true)]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
if ($Type -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType])
{
return $Type
}
$tp = Get-TfsTeamProject -Project $Project -Collection $Collection
return $tp.WorkItemTypes | Where-Object Name -Like $Type
}
}
<#
.SYNOPSIS
Imports a work item type definition to a team project from XML.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.INPUTS
System.Xml.XmlDocument
#>
Function Import-TfsWorkItemType
{
[CmdletBinding(ConfirmImpact='Medium')]
Param
(
[Parameter(Position=0, ValueFromPipeline=$true)]
[xml]
$Xml,
[Parameter()]
[object]
$Project,
[Parameter()]
[object]
$Collection
)
Process
{
$tp = Get-TfsTeamProject $Project $Collection
$tp.WorkItemTypes.Import($Xml.OuterXml)
}
}
<#
.SYNOPSIS
Queues a XAML Build.
.PARAMETER BuildDefinition
Build Definition Name that you want to queue.
.PARAMETER Project
Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).
For more details, see the Get-TfsTeamProject cmdlet.
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
When using a URL, it must be fully qualified. The format of this string is as follows:
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
For more details, see the Get-TfsTeamProjectCollection cmdlet.
.EXAMPLE
Start-TfsBuild -BuildDefinition "My Build Definition" -Project "MyTeamProject"
This example queue a Build Definition "My Build Definition" of Team Project "MyTeamProject".
#>
Function Start-TfsXamlBuild
{
[CmdletBinding(ConfirmImpact='Medium', SupportsShouldProcess=$true)]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[object]
$BuildDefinition,
[Parameter(ValueFromPipeline=$true, Mandatory=$true)]
[object]
[ValidateNotNull()]
[ValidateScript({($_ -is [string]) -or ($_ -is [Microsoft.TeamFoundation.WorkItemTracking.Client.Project])})]
$Project,
[Parameter()]
[object]
$Collection,
[Parameter()]
[string]
[ValidateSet("LatestOnQueue", "LatestOnBuild", "Custom")]
$GetOption = "LatestOnBuild",
[Parameter()]
[string]
$GetVersion,
[Parameter()]
[string]
$DropLocation,
[Parameter()]
[hashtable]
$Parameters
)
Begin
{
if ($PSVersionTable.PSEdition -ne 'Desktop') { throw "This cmdlet requires does not work in PowerShell Core. It uses TFS Client Object Model, which only works in Windows PowerShell" }
}
Process
{
if($PSCmdlet.ShouldProcess($BuildDefinition, 'Queue new build'))
{
$tp = Get-TfsTeamProject $Project $Collection
$tpc = $tp.Store.TeamProjectCollection
$buildServer = $tpc.GetService([type]"Microsoft.TeamFoundation.Build.Client.IBuildServer")
if ($BuildDefinition -is [Microsoft.TeamFoundation.Build.Client.IBuildDefinition])
{
$buildDef = $BuildDefinition
}
else
{
$buildDef = $buildServer.GetBuildDefinition($tp.Name, $BuildDefinition);
}
$req = $buildDef.CreateBuildRequest()
$req.GetOption = [Microsoft.TeamFoundation.Build.Client.GetOption] $GetOption;
if ($GetOption -eq "Custom")
{
$req.CustomGetVersion = $GetVersion
}
if ($DropLocation)
{
$req.DropLocation = $DropLocation
}
$buildServer.QueueBuild($req)
}
}
}
@{
Description = 'This module contains cmdlets to maintain and administer XAML Builds and their infrastructure (controllers, agents etc.)'
ModuleVersion = '0.0.0'
RootModule = 'XamlBuild.psm1'
PrivateData = @{
FriendlyName = 'XAML Builds'
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
namespace TfsCmdlets
{
public class AssemblyResolver
{
private static bool IsVerbose {get;set;}
public static Dictionary<string, string> PrivateAssemblies {get;set;}
public static readonly Dictionary<string, Assembly> LoadedAssemblies = new Dictionary<string, Assembly>();
public static readonly Dictionary<string, object> LogEntries = new Dictionary<string, object>();
public static void Register(Dictionary<string, string> privateAssemblies, bool verbose = false)
{
PrivateAssemblies = privateAssemblies;
IsVerbose = verbose;
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e)
{
var assemblyName = e.Name.Split(',')[0];
try
{
if (!PrivateAssemblies.ContainsKey(assemblyName))
{
LogWarn("Skipping unknown assembly " + e.Name);
return null;
}
var asm = LoadAssembly(assemblyName);
LogInfo(assemblyName + " resolved as '" + asm.FullName + "'");
return asm;
}
catch(Exception ex)
{
LogError(ex, assemblyName);
return null;
}
};
}
private static Assembly LoadAssembly(string assemblyName)
{
if(LoadedAssemblies.ContainsKey(assemblyName))
{
return LoadedAssemblies[assemblyName];
}
var assembly = Assembly.LoadFrom(PrivateAssemblies[assemblyName]);
LoadedAssemblies.Add(assemblyName, assembly);
return assembly;
}
private static void Log(string message, object data)
{
message = "[" + (LogEntries.Count+1).ToString("00000") + " - " + DateTime.Now.ToString("HH:mm:ss.ffff") + "] " + message;
LogEntries.Add(message, data);
}
private static void LogInfo(string message)
{
if (!IsVerbose) return;
Log("[INFO ] " + message, string.Empty);
}
private static void LogWarn(string message)
{
Log("[WARN ] " + message, string.Empty);
}
private static void LogError(Exception ex, string assemblyName = null)
{
Log("[ERROR] Loading assembly " + (assemblyName?? "(unknown)"), ex);
}
}
}
function _GetAbsolutePath
{
[CmdletBinding()]
Param
(
$Path,
[switch]$CreateFolder
)
Process
{
$Path = [System.IO.Path]::Combine($pwd.Path, $Path)
$Path = [System.IO.Path]::GetFullPath($Path)
$folder = Split-Path $Path -Parent
if ((-not (Test-Path $folder)) -and ($CreateFolder.IsPresent))
{
New-Item $folder -ItemType Directory -Force | _Log
}
return $Path
}
}
Function _GetJsonPatchDocument
{
[CmdletBinding()]
[OutputType([Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument])]
Param
(
$operations
)
$doc = New-Object 'Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument'
foreach($op in $operations)
{
if ($op -is [Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation])
{
$doc.Add($op)
continue
}
$jsonOp = New-Object 'Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation'
$jsonOp.Operation = $op.Operation
$jsonOp.Path = $op.Path
$jsonOp.Value = $op.Value
$doc.Add($jsonOp)
}
Write-Output -NoEnumerate $doc
}
Function _GetRegistryValue
{
Param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$Path,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$Value
)
Process
{
return Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value
}
}
Function _GetRestClient
{
[CmdletBinding()]
[OutputType('Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase')]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string]
$Type,
[Parameter()]
[object]
$Collection
)
Process
{
$tpc = Get-TfsTeamProjectCollection -Collection $Collection
return _InvokeGenericMethod -InputObject $tpc -MethodName GetClient -GenericType $Type
}
}
Function _ImportRequiredAssembly($assemblyName)
{
$libPath = (Join-Path $PSScriptRoot "../lib" -Resolve)
if($assemblyName -eq '*')
{
$assemblies = (Get-ChildItem "$libPath/*.dll" -Exclude 'Microsoft.WitDataStore*.*','TfsCmdletsLib.dll').BaseName
$assemblies += (Get-ChildItem "$libPath/TfsCmdletsLib.dll").BaseName
}
else
{
$assemblies = (Get-ChildItem "$libPath/$assemblyName.dll").BaseName
}
foreach($asm in $assemblies)
{
Write-Verbose "Loading assembly $asm from folder $libPath"
try
{
Add-Type -Path (Join-Path $libPath "$asm.dll")
}
catch
{
Write-Error "Error loading assembly '$asm': $($_.Exception)"
}
}
}
Function _TestLoadedAssembly($assemblyName)
{
try
{
$asm = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object FullName -like "$assemblyName,*"
return $asm -is [System.Reflection.Assembly]
}
catch
{
return $false
}
}
function _InvokeGenericMethod
{
[CmdletBinding(DefaultParameterSetName = 'Instance')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Instance')]
$InputObject,
[Parameter(Mandatory = $true, ParameterSetName = 'Static')]
[Type]
$Type,
[Parameter(Mandatory = $true)]
[string]
$MethodName,
[Parameter(Mandatory = $true)]
[Type[]]
$GenericType,
[Object[]]
$ArgumentList
)
process
{
switch ($PSCmdlet.ParameterSetName)
{
'Instance'
{
$_type = $InputObject.GetType()
$object = $InputObject
$flags = [System.Reflection.BindingFlags] 'Instance, Public'
}
'Static'
{
$_type = $Type
$object = $null
$flags = [System.Reflection.BindingFlags] 'Static, Public'
}
}
if ($null -ne $ArgumentList)
{
$argList = $ArgumentList.Clone()
}
else
{
$argList = @()
}
$params = @{
Type = $_type
BindingFlags = $flags
MethodName = $MethodName
GenericType = $GenericType
ArgumentList = [ref]$argList
}
$method = _GetGenericMethod @params
if ($null -eq $method)
{
Write-Error "No matching method was found"
return
}
return [PSGenericMethods.MethodInvoker]::InvokeMethod($method, $object, $argList)
}
}
function _GetGenericMethod
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[Type]
$Type,
[Parameter(Mandatory = $true)]
[string]
$MethodName,
[Parameter(Mandatory = $true)]
[Type[]]
$GenericType,
[ref]
$ArgumentList,
[System.Reflection.BindingFlags]
$BindingFlags = [System.Reflection.BindingFlags]::Default,
[switch]
$WithCoercion
)
if ($null -eq $ArgumentList.Value)
{
$originalArgList = @()
}
else
{
$originalArgList = @($ArgumentList.Value)
}
foreach ($method in $Type.GetMethods($BindingFlags))
{
$argList = $originalArgList.Clone()
if (-not $method.IsGenericMethod -or $method.Name -ne $MethodName) { continue }
if ($GenericType.Count -ne $method.GetGenericArguments().Count) { continue }
if (_TestGenericMethodParameters -MethodInfo $method -ArgumentList ([ref]$argList) -GenericType $GenericType -WithCoercion:$WithCoercion)
{
$ArgumentList.Value = $argList
return $method.MakeGenericMethod($GenericType)
}
}
if (-not $WithCoercion)
{
$null = $PSBoundParameters.Remove('WithCoercion')
return _GetGenericMethod @PSBoundParameters -WithCoercion
}
}
function _TestGenericMethodParameters
{
[CmdletBinding()]
param (
[System.Reflection.MethodInfo] $MethodInfo,
[ref]
$ArgumentList,
[Parameter(Mandatory = $true)]
[Type[]]
$GenericType,
[switch]
$WithCoercion
)
if ($null -eq $ArgumentList.Value)
{
$argList = @()
}
else
{
$argList = @($ArgumentList.Value)
}
$parameterList = $MethodInfo.GetParameters()
$arrayType = $null
$_HasParamsArray = _HasParamsArray -ParameterList $parameterList
if ($parameterList.Count -lt $argList.Count -and -not $_HasParamsArray)
{
return $false
}
$methodGenericType = $MethodInfo.GetGenericArguments()
for ($i = 0; $i -lt $argList.Count; $i++)
{
$params = @{
ArgumentList = $argList
ParameterList = $ParameterList
WithCoercion = $WithCoercion
RuntimeGenericType = $GenericType
MethodGenericType = $methodGenericType
Index = [ref]$i
ArrayType = [ref]$arrayType
}
$isOk = _TryMatchParameter @params
if (-not $isOk) { return $false }
}
$defaults = New-Object System.Collections.ArrayList
for ($i = $argList.Count; $i -lt $parameterList.Count; $i++)
{
if (-not $parameterList[$i].HasDefaultValue) { return $false }
$null = $defaults.Add($parameterList[$i].DefaultValue)
}
# When calling a method with a params array using MethodInfo, you have to pass in the array; the
# params argument approach doesn't work.
if ($_HasParamsArray)
{
$firstArrayIndex = $parameterList.Count - 1
$lastArrayIndex = $argList.Count - 1
$newArgList = $argList[0..$firstArrayIndex]
$newArgList[$firstArrayIndex] = $argList[$firstArrayIndex..$lastArrayIndex] -as $arrayType
$argList = $newArgList
}
$ArgumentList.Value = $argList + $defaults.ToArray()
return $true
}
function _TryMatchParameter
{
param (
[System.Reflection.ParameterInfo[]]
$ParameterList,
[object[]]
$ArgumentList,
[Type[]]
$MethodGenericType,
[Type[]]
$RuntimeGenericType,
[switch]
$WithCoercion,
[ref] $Index,
[ref] $ArrayType
)
$params = @{
ParameterType = $ParameterList[$Index.Value].ParameterType
RuntimeType = $RuntimeGenericType
GenericType = $MethodGenericType
}
$runtimeType = _ResolveRuntimeType @params
if ($null -eq $runtimeType)
{
throw "Could not determine runtime type of parameter '$($ParameterList[$Index.Value].Name)'"
}
$_IsParamsArray = _IsParamsArray -ParameterInfo $ParameterList[$Index.Value]
if ($_IsParamsArray)
{
$ArrayType.Value = $runtimeType
$runtimeType = $runtimeType.GetElementType()
}
do
{
$isOk = _TryMatchArgument @PSBoundParameters -RuntimeType $runtimeType
if (-not $isOk) { return $false }
if ($_IsParamsArray) { $Index.Value++ }
}
while ($_IsParamsArray -and $Index.Value -lt $ArgumentList.Count)
return $true
}
function _TryMatchArgument
{
param (
[System.Reflection.ParameterInfo[]]
$ParameterList,
[object[]]
$ArgumentList,
[Type[]]
$MethodGenericType,
[Type[]]
$RuntimeGenericType,
[switch]
$WithCoercion,
[ref] $Index,
[ref] $ArrayType,
[Type] $RuntimeType
)
Function _GetType($object)
{
if ($null -eq $object) { return $null }
return $object.GetType()
}
$argValue = $ArgumentList[$Index.Value]
$argType = _GetType $argValue
$isByRef = $RuntimeType.IsByRef
if ($isByRef)
{
if ($ArgumentList[$Index.Value] -isnot [ref]) { return $false }
$RuntimeType = $RuntimeType.GetElementType()
$argValue = $argValue.Value
$argType = _GetType $argValue
}
$isNullNullable = $false
while ($RuntimeType.FullName -like 'System.Nullable``1*')
{
if ($null -eq $argValue)
{
$isNullNullable = $true
break
}
$RuntimeType = $RuntimeType.GetGenericArguments()[0]
}
if ($isNullNullable) { continue }
if ($null -eq $argValue)
{
return -not $RuntimeType.IsValueType
}
else
{
if ($argType -ne $RuntimeType)
{
$argValue = $argValue -as $RuntimeType
if (-not $WithCoercion -or $null -eq $argValue) { return $false }
}
if ($isByRef)
{
$ArgumentList[$Index.Value].Value = $argValue
}
else
{
$ArgumentList[$Index.Value] = $argValue
}
}
return $true
}
function _HasParamsArray([System.Reflection.ParameterInfo[]] $ParameterList)
{
return $ParameterList.Count -gt 0 -and (_IsParamsArray -ParameterInfo $ParameterList[-1])
}
function _IsParamsArray([System.Reflection.ParameterInfo] $ParameterInfo)
{
return @($ParameterInfo.GetCustomAttributes([System.ParamArrayAttribute], $true)).Count -gt 0
}
function _ResolveRuntimeType
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[Type]
$ParameterType,
[Parameter(Mandatory = $true)]
[Type[]]
$RuntimeType,
[Parameter(Mandatory = $true)]
[Type[]]
$GenericType
)
if ($ParameterType.IsByRef)
{
$elementType = _ResolveRuntimeType -ParameterType $ParameterType.GetElementType() -RuntimeType $RuntimeType -GenericType $GenericType
return $elementType.MakeByRefType()
}
elseif ($ParameterType.IsGenericParameter)
{
for ($i = 0; $i -lt $GenericType.Count; $i++)
{
if ($ParameterType -eq $GenericType[$i])
{
return $RuntimeType[$i]
}
}
}
elseif ($ParameterType.IsArray)
{
$arrayType = $ParameterType
$elementType = _ResolveRuntimeType -ParameterType $ParameterType.GetElementType() -RuntimeType $RuntimeType -GenericType $GenericType
if ($ParameterType.GetElementType().IsGenericParameter)
{
$arrayRank = $arrayType.GetArrayRank()
if ($arrayRank -eq 1)
{
$arrayType = $elementType.MakeArrayType()
}
else
{
$arrayType = $elementType.MakeArrayType($arrayRank)
}
}
return $arrayType
}
elseif ($ParameterType.ContainsGenericParameters)
{
$genericArguments = $ParameterType.GetGenericArguments()
$runtimeArguments = New-Object System.Collections.ArrayList
foreach ($argument in $genericArguments)
{
$null = $runtimeArguments.Add((_ResolveRuntimeType -ParameterType $argument -RuntimeType $RuntimeType -GenericType $GenericType))
}
$definition = $ParameterType
if (-not $definition.IsGenericTypeDefinition)
{
$definition = $definition.GetGenericTypeDefinition()
}
return $definition.MakeGenericType($runtimeArguments.ToArray())
}
else
{
return $ParameterType
}
}
if (-not ([System.Management.Automation.PSTypeName]'PSGenericMethods.MethodInvoker').Type)
{
Add-Type -ErrorAction SilentlyContinue -TypeDefinition @'
namespace PSGenericMethods
{
using System;
using System.Reflection;
using System.Management.Automation;
public static class MethodInvoker
{
public static object InvokeMethod(MethodInfo method, object target, object[] arguments)
{
if (method == null) { throw new ArgumentNullException("method"); }
object[] args = null;
if (arguments != null)
{
args = (object[])arguments.Clone();
for (int i = 0; i < args.Length; i++)
{
PSObject pso = args[i] as PSObject;
if (pso != null)
{
args[i] = pso.BaseObject;
}
PSReference psref = args[i] as PSReference;
if (psref != null)
{
args[i] = psref.Value;
}
}
}
object result = method.Invoke(target, args);
for (int i = 0; i < arguments.Length; i++)
{
PSReference psref = arguments[i] as PSReference;
if (psref != null)
{
psref.Value = args[i];
}
}
return result;
}
}
}
'@
}
Function _InvokeScriptBlock($ScriptBlock, $Computer, $Credentials, $ArgumentList)
{
if (-not $Computer)
{
return Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $ArgumentList
}
elseif ($Computer -is [System.Management.Automation.Runspaces.PSSession])
{
return Invoke-Command -ScriptBlock $scriptBlock -Session $Computer -ArgumentList $ArgumentList
}
return Invoke-Command -ScriptBlock $scriptBlock -ComputerName $Computer -Credential $Credential -ArgumentList $ArgumentList
}
Function _Log
{
Param
(
[Parameter(ValueFromPipeline=$true)]
[object]
$Message,
[Parameter()]
[string]
$Caller,
[Parameter()]
[switch]
$Force
)
if(($VerbosePreference -ne 'Continue') -and (-not $Force.IsPresent))
{
# No verbose set. Exit now to avoid expensive/unnecessary calls to Get-PSCallStack and Write-Verbose
return
}
if(-not $Caller)
{
$caller = _GetLogCallStack
}
Write-Verbose "[$([DateTime]::Now.ToString('HH:mm:ss.ffff'))] [$caller] $Message"
}
Function _GetLogCallStack
{
$cs = [System.Collections.Stack]::new()
foreach($frame in Get-PSCallStack)
{
if ($frame.Command -in @('_Log', '_GetLogCallStack', '', $null))
{
continue
}
$cs.Push($frame.Command.Trim('_'))
if ($frame.Command -like '*-*')
{
break
}
}
return $cs.ToArray() -join ':'
}
Function _DumpObj
{
Param
(
[Parameter(ValueFromPipeline=$true, Position=0)]
[object]
$InputObject,
[Parameter()]
$Depth = 5
)
return $InputObject | ConvertTo-Json -Depth $Depth -Compress
}
function _NewDictionary
{
#requires -Version 2.0
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position=1)]
[ValidateNotNull()]
[hashtable]
$InputObject,
[Parameter(Position=0)]
[ValidateCount(2,2)]
[Type[]]
$Types = @([string], [object])
)
process
{
$KeyType = $Types[0]
$ValueType = $Types[1]
$outputObject = New-Object "System.Collections.Generic.Dictionary[[$($KeyType.FullName)],[$($ValueType.FullName)]]"
foreach ($entry in $InputObject.GetEnumerator())
{
$newKey = $entry.Key -as $KeyType
if ($null -eq $newKey)
{
throw 'Could not convert key "{0}" of type "{1}" to type "{2}"' -f
$entry.Key,
$entry.Key.GetType().FullName,
$KeyType.FullName
}
elseif ($outputObject.ContainsKey($newKey))
{
throw "Duplicate key `"$newKey`" detected in input object."
}
$outputObject.Add($newKey, $entry.Value -as $ValueType)
}
Write-Output $outputObject
}
}
Function _NewScriptBlock($EntryPoint, [string[]]$Dependency)
{
$entryPoint = (Get-Item "function:$EntryPoint").Definition.Trim()
$paramSection = $entryPoint.Substring(0, $entryPoint.IndexOf("`n"))
$bodySection = $entryPoint.Substring($paramSection.Length) + "`n`n"
$body = $paramSection
foreach($depFn in $Dependency)
{
$f = Get-Item "function:$depFn"
$body += "Function $f `n{`n"
$body += $f.Definition
$body += "`n}`n`n"
}
$body += $bodySection
return [scriptblock]::Create($body)
}
Function _RegisterAssemblyResolver
{
if ($TfsCmdletsDebugStartup)
{
Write-Host "Entering TfsCmdlets startup debug mode" -ForegroundColor DarkYellow
# For some reason, setting VerbosePreference here breaks the script. Using Set-Alias to work around it
Set-Alias Write-Verbose Write-Host -Option Private
}
Write-Verbose 'Registering custom Assembly Resolver'
if (-not ([System.Management.Automation.PSTypeName]'TfsCmdlets.AssemblyResolver').Type)
{
Write-Verbose "Compiling $PSEdition version of the assembly resolver"
$sourcePath = (Join-Path $PSScriptRoot "../_cs/$($PSEdition)AssemblyResolver.cs" -Resolve)
$sourceText = (Get-Content $sourcePath -Raw)
Add-Type -TypeDefinition $sourceText -Language CSharp
$libPath = (Join-Path $PSScriptRoot '../Lib' -Resolve)
$assemblies = [System.Collections.Generic.Dictionary[string,string]]::new()
Write-Verbose "Enumerating assemblies from $libPath"
foreach($f in (Get-ChildItem $libPath -Filter '*.dll'))
{
Write-Verbose "Adding $f to list of private assemblies"
$assemblies.Add($f.BaseName, $f.FullName)
}
Write-Verbose 'Calling AssemblyResolver.Register()'
[TfsCmdlets.AssemblyResolver]::Register($assemblies, [bool]($TfsCmdletsDebugStartup))
}
else
{
Write-Verbose 'Custom Assembly Resolver already registered; skipping'
}
}
Function _TestGuid([string]$guid)
{
if([string]::IsNullOrEmpty($guid))
{
return $false
}
$parsedGuid = [guid]::Empty
return [guid]::TryParse($guid, [ref] $parsedGuid)
}
Function _TestRegistryValue
{
Param
(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$Path,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$Value
)
Process
{
try
{
_GetRegistryValue -Path $Path -Value $Value | Out-Null
return $true
}
finally {}
return $false
}
}
Function _Throw
{
Param
(
[Parameter(ValueFromPipeline=$true, Position=0)]
[object]
$Message,
[Parameter(Position=1)]
[object]
$Exception
)
$caller = (Get-PSCallStack)[1].Command
if ($Exception)
{
$Message += "`r`rAdditional error information: $Exception"
}
throw "[$caller] $Message"
}
Log in or click on link to see number of positives.
- System.Net.Http.Formatting.dll (1c7fa94de5e7) - ## / 67
- System.Web.Http.dll (a47387c4a098) - ## / 66
- System.Web.Http.WebHost.dll (acee4e07c74c) - ## / 66
- Microsoft.IdentityModel.Clients.ActiveDirectory.dll (a9b91af8552e) - ## / 67
- Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll (48f7bfec411e) - ## / 70
- TfsCmdlets.2.0.0-beta0004.nupkg (1a0f84fb57b8) - ## / 58
- Ben.Demystifier.dll (5dfa652b6f95) - ## / 66
- HtmlAgilityPack.dll (a5113fa6f675) - ## / 67
- Microsoft.Azure.DevOps.Comments.WebApi.dll (3e0f866d1b62) - ## / 68
- Microsoft.IdentityModel.JsonWebTokens.dll (47f008c0a3b7) - ## / 70
- Microsoft.IdentityModel.Logging.dll (8a2fed0aa975) - ## / 69
- Microsoft.IdentityModel.Tokens.dll (c2cce56edf47) - ## / 69
- Microsoft.TeamFoundation.Build.Client.dll (e6a39a0be0cf) - ## / 70
- Microsoft.TeamFoundation.Build.Common.dll (131c56e9b41c) - ## / 70
- Microsoft.TeamFoundation.Build2.WebApi.dll (aaa14e60fd88) - ## / 67
- Microsoft.TeamFoundation.Client.dll (51b8db50abe8) - ## / 69
- Microsoft.TeamFoundation.Common.dll (343ac0e5b3f4) - ## / 66
- Microsoft.TeamFoundation.Core.WebApi.dll (10cb0ce7d190) - ## / 64
- Microsoft.TeamFoundation.Dashboards.WebApi.dll (1e7ab5626da6) - ## / 66
- Microsoft.TeamFoundation.DeleteTeamProject.dll (1d97d8a5b162) - ## / 69
- Microsoft.TeamFoundation.Diff.dll (dcdd58f859ee) - ## / 68
- Microsoft.TeamFoundation.Discussion.Client.dll (c664cb482775) - ## / 69
- Microsoft.TeamFoundation.DistributedTask.Common.Contracts.dll (753449134a06) - ## / 68
- Microsoft.TeamFoundation.Git.Client.dll (e98537767152) - ## / 69
- Microsoft.TeamFoundation.Lab.Client.dll (6605e485608f) - ## / 69
- Microsoft.TeamFoundation.Lab.Common.dll (d8e0421a9b52) - ## / 69
- Microsoft.TeamFoundation.Lab.TestIntegration.Client.dll (d414bdf5df71) - ## / 69
- Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.dll (249d53bb9b74) - ## / 69
- Microsoft.TeamFoundation.Policy.WebApi.dll (474ae277bc24) - ## / 69
- Microsoft.TeamFoundation.ProjectManagement.dll (a2cc011bd17e) - ## / 64
- Microsoft.TeamFoundation.SharePointReporting.Integration.dll (7361f75c9e27) - ## / 69
- Microsoft.TeamFoundation.SourceControl.WebApi.dll (f791789f10f7) - ## / 70
- Microsoft.TeamFoundation.Test.WebApi.dll (4e5b4a78c30a) - ## / 69
- Microsoft.TeamFoundation.TestImpact.Client.dll (4be42f34898b) - ## / 70
- Microsoft.TeamFoundation.TestManagement.Client.dll (592cdc736aad) - ## / 69
- Microsoft.TeamFoundation.TestManagement.Common.dll (b6f882985010) - ## / 70
- Microsoft.TeamFoundation.TestManagement.WebApi.dll (a9ce50d30a21) - ## / 69
- Microsoft.TeamFoundation.VersionControl.Client.dll (293e446b58d5) - ## / 69
- Microsoft.TeamFoundation.VersionControl.Common.dll (96e9a23bf3a2) - ## / 67
- Microsoft.TeamFoundation.VersionControl.Common.Integration.dll (b786d641283b) - ## / 69
- Microsoft.TeamFoundation.Wiki.WebApi.dll (43aad918447f) - ## / 69
- Microsoft.TeamFoundation.Work.WebApi.dll (e02f5894cbf0) - ## / 69
- Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll (3f4c00ff172f) - ## / 70
- Microsoft.TeamFoundation.WorkItemTracking.Client.dll (dcddb0ca878b) - ## / 67
- Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll (1fe5bd860623) - ## / 69
- Microsoft.TeamFoundation.WorkItemTracking.Common.dll (0f886e8f3f1f) - ## / 70
- Microsoft.TeamFoundation.WorkItemTracking.Process.WebApi.dll (90b28ccea30a) - ## / 61
- Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll (88291af7d1b5) - ## / 60
- Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll (a9591361304e) - ## / 70
- Microsoft.VisualStudio.Services.Client.Interactive.dll (823a9afb6b16) - ## / 68
- Microsoft.VisualStudio.Services.Common.dll (ae2147de3864) - ## / 60
- Microsoft.VisualStudio.Services.ServiceHooks.WebApi.dll (4c4699d90fa7) - ## / 69
- Microsoft.VisualStudio.Services.TestManagement.TestPlanning.WebApi.dll (3588873756c2) - ## / 70
- Microsoft.VisualStudio.Services.TestResults.WebApi.dll (385970f99134) - ## / 70
- Microsoft.VisualStudio.Services.WebApi.dll (a92eb9bc07f9) - ## / 70
- Microsoft.WITDataStore32.dll (6283b6d50788) - ## / 60
- Microsoft.WITDataStore64.dll (de94137b2233) - ## / 69
- Newtonsoft.Json.dll (52cc6ddf7799) - ## / 68
- System.IdentityModel.Tokens.Jwt.dll (6024102a8a0c) - ## / 70
- TfsCmdletsLib.dll (36ccf5cf12ac) - ## / 69
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.9.0 | 40 | Thursday, August 15, 2024 | Approved | |
TfsCmdlets 2.8.2 | 31 | Wednesday, July 24, 2024 | Approved | |
TfsCmdlets 2.8.1 | 25 | Tuesday, July 16, 2024 | Approved | |
TfsCmdlets 2.8.0 | 32 | Tuesday, July 9, 2024 | Approved | |
TfsCmdlets 2.7.1 | 22 | Wednesday, July 3, 2024 | Approved | |
TfsCmdlets 2.6.1 | 42 | Wednesday, May 15, 2024 | Approved | |
TfsCmdlets 2.6.0 | 247 | Saturday, October 1, 2022 | Approved | |
TfsCmdlets 2.5.1 | 61 | Monday, August 22, 2022 | Approved | |
TfsCmdlets 2.5.0 | 59 | Wednesday, August 3, 2022 | Approved | |
TfsCmdlets 2.4.1 | 67 | Thursday, July 21, 2022 | Approved | |
TfsCmdlets 2.4.0 | 89 | Monday, May 23, 2022 | Approved | |
TfsCmdlets 2.3.2 | 61 | Wednesday, May 18, 2022 | Approved | |
TfsCmdlets 2.3.1 | 70 | Saturday, April 9, 2022 | Approved | |
TfsCmdlets 2.3.0 | 67 | Sunday, April 3, 2022 | Approved | |
TfsCmdlets 2.2.1 | 75 | Friday, February 11, 2022 | Approved | |
TfsCmdlets 2.2.0 | 62 | Saturday, February 5, 2022 | Approved | |
TfsCmdlets 2.1.4 | 89 | Tuesday, November 30, 2021 | Approved | |
TfsCmdlets 2.1.3 | 66 | Thursday, November 25, 2021 | Approved | |
TfsCmdlets 2.1.2 | 83 | Friday, September 10, 2021 | Approved | |
TfsCmdlets 2.1.1 | 78 | Wednesday, September 8, 2021 | Approved | |
TfsCmdlets 2.0.0 | 83 | Tuesday, August 3, 2021 | Approved | |
TfsCmdlets 2.0.0-rc0005 | 87 | Sunday, April 18, 2021 | Exempted | |
TfsCmdlets 2.0.0-rc0004 | 87 | Monday, April 5, 2021 | Exempted | |
TfsCmdlets 2.0.0-rc0003 | 74 | Friday, February 19, 2021 | Exempted | |
TfsCmdlets 2.0.0-rc0002 | 84 | Tuesday, December 1, 2020 | Exempted | |
TfsCmdlets 2.0.0-beta0015 | 84 | Tuesday, July 21, 2020 | Exempted | |
TfsCmdlets 2.0.0-beta0014 | 65 | Sunday, July 19, 2020 | Exempted | |
TfsCmdlets 2.0.0-beta0013 | 67 | Saturday, July 18, 2020 | Exempted | |
TfsCmdlets 2.0.0-beta0010 | 157 | Thursday, September 12, 2019 | Exempted | |
TfsCmdlets 2.0.0-beta0009 | 93 | Tuesday, September 10, 2019 | Exempted | |
TfsCmdlets 2.0.0-beta0008 | 103 | Friday, September 6, 2019 | Exempted | |
TfsCmdlets 2.0.0-beta0004 | 117 | Thursday, August 29, 2019 | Exempted | |
TfsCmdlets 1.0.0.894-beta1 | 389 | Thursday, April 6, 2017 | Exempted | |
TfsCmdlets 1.0.0-alpha9 | 332 | Saturday, December 24, 2016 | Exempted | |
TfsCmdlets 1.0.0-alpha7 | 299 | Thursday, October 22, 2015 | Exempted | |
TfsCmdlets 1.0.0-alpha6 | 279 | Thursday, October 22, 2015 | Exempted | |
TfsCmdlets 1.0.0-alpha5 | 255 | Thursday, September 10, 2015 | Exempted | |
TfsCmdlets 1.0.0-alpha4 | 247 | Friday, September 4, 2015 | Exempted | |
TfsCmdlets 1.0.0-alpha3 | 311 | Thursday, September 3, 2015 | Exempted | |
TfsCmdlets 1.0.0-alpha1 | 310 | Friday, July 31, 2015 | Exempted |
(c) 2014 Igor Abade V. Leite. All rights reserved.
This package has no dependencies.
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.