TeamProject/TeamProject.ps1

<#
.SYNOPSIS
Gets information about one or more team projects.
 
.DESCRIPTION
The Get-TfsTeamProject cmdlets gets one or more Team Project objects (an instance of Microsoft.TeamFoundation.WorkItemTracking.Client.Project) from the supplied Team Project Collection.
 
.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.
 
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
 
When using a URL, it must be fully qualified. The format of this string is as follows:
 
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
 
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
 
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
 
For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.PARAMETER Server
Specifies either a URL or the name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.
For more details, see the -Server argument in the Get-TfsTeamProjectCollection cmdlet.
 
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
 
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
 
.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.
 
#>

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

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

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

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

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

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

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

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

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

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

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

            return $wiStore.Projects[$Project]
        }

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

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

Function _GetAllProjects
{
    param ($tpc)

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

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

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

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

        [string]
        $Description,

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

        [object]
        $ProcessTemplate,

        [Parameter()]
        [switch]
        $Passthru
    )

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

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

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

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

            # Trigger the project creation

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

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

            # Wait for the operation to complete

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

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

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

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

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

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

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

            if ($Passthru)
            {
                return $tp
            }
        }
    }
}
<#
.SYNOPSIS
Deletes one or more team projects.
 
.DESCRIPTION
 
.PARAMETER Project
Specifies the name of a Team Project. Wildcards are supported.
 
.PARAMETER Collection
Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.
 
When using a URL, it must be fully qualified. The format of this string is as follows:
 
http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>
 
Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.
 
To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.
 
For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
 
.INPUTS
Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
System.String
System.Uri
 
.NOTES
As with most cmdlets in the TfsCmdlets module, this cmdlet requires a TfsTeamProjectCollection object to be provided via the -Collection argument. If absent, it will default to the connection opened by Connect-TfsTeamProjectCollection.
 
#>

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

        [Parameter()]
        [object]
        $Collection,

        [Parameter()]
        [switch]
        $Hard,

        [Parameter()]
        [switch]
        $Force
    )

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

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

        if(-not $tps)
        {
            return
        }

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

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

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

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

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

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

                        throw "Error deleting team project ${Project}: $($opsToken.DetailedMessage)"
                    }
                }
            }
        }
    }
}