TeamProjectCollection/TeamProjectCollection.psm1

<#
 
.SYNOPSIS
    Detaches a team project collection database from a Team Foundation Server installation.
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

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

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

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsConfigurationServer
    System.String
    System.Uri
#>

Function Dismount-TfsTeamProjectCollection
{
    [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [object] 
        $Collection,

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

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

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

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

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

            return $connectionString
        }
    }
}
<#
.SYNOPSIS
    Gets one or more Team Project Collection addresses registered in the current computer.
 
.PARAMETER Name
    Specifies the name of a registered collection. When omitted, all registered collections are returned. Wildcards are permitted.
 
.INPUTS
    System.String
#>

Function Get-TfsRegisteredTeamProjectCollection
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.Client.RegisteredProjectCollection[]])]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [SupportsWildcards()]
        [string]
        $Name = "*"
    )

    Process
    {
        return [Microsoft.TeamFoundation.Client.RegisteredTfsConnections]::GetProjectCollections() | ? DisplayName -Like $Name
    }
}
<#
.SYNOPSIS
    Gets information about one or more team project collections.
 
.DESCRIPTION
    The Get-TfsTeamProjectCollection cmdlets gets one or more Team Project Collection objects (an instance of Microsoft.TeamFoundation.Client.TfsTeamProjectCollection) from a TFS instance.
    Team Project Collection objects can either be obtained by providing a fully-qualified URL to the collection or by collection name (in which case a TFS Configuration Server object is required).
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

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

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

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.PARAMETER Server
    Specifies either a URL/name of the Team Foundation Server configuration server (the "root" of a TFS installation) to connect to, or a previously initialized Microsoft.TeamFoundation.Client.TfsConfigurationServer object.
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the cached credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in. To provide a user name and password, and/or to open a input dialog to enter your credentials, call Get-TfsCredential with the appropriate arguments and pass its return to this argument. For more information, refer to https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.client.tfsclientcredentials.aspx
 
.EXAMPLE
    Get-TfsTeamProjectCollection http://
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsConfigurationServer
 
.NOTES
    Cmdlets in the TfsCmdlets module that operate on a collection level require a TfsConfigurationServer object to be provided via the -Server argument. If absent, it will default to the connection opened by Connect-TfsConfigurationServer.
#>

Function Get-TfsTeamProjectCollection
{
    [CmdletBinding(DefaultParameterSetName='Get by collection')]
    [OutputType([Microsoft.TeamFoundation.Client.TfsTeamProjectCollection])]
    Param
    (
        [Parameter(Position=0, ParameterSetName="Get by collection")]
        [SupportsWildcards()]
        [object] 
        $Collection = "*",
    
        [Parameter(ValueFromPipeline=$true, ParameterSetName="Get by collection")]
        [object] 
        $Server,
    
        [Parameter(Position=0, ParameterSetName="Get current")]
        [switch]
        $Current,

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

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

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

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

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

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

            $Collection = $null
        }

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

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

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

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

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


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

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

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

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

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

        $tpc
    }
}
<#
 
.SYNOPSIS
    Attaches a team project collection database to a Team Foundation Server installation.
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsConfigurationServer
    System.String
    System.Uri
#>

Function Mount-TfsTeamProjectCollection
{
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]
        $Name,

        [Parameter()]
        [string]
        $Description,

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

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

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

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

        [Parameter()]
        [switch]
        $Clone,

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

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

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

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

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

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

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

            $start = Get-Date

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

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

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

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

        throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Name")
    }
}
<#
 
.SYNOPSIS
    Creates a new team project collection.
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

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

Function New-TfsTeamProjectCollection
{
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [string]
        $Name,

        [Parameter()]
        [string]
        $Description,

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

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

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

        [Parameter()]
        [switch]
        $Default,

        [Parameter()]
        [switch]
        $UseExistingDatabase,

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

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

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

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

    Process
    {
        $configServer = Get-TfsConfigurationServer $Server -Credential $Credential
        $tpcService = $configServer.GetService([type] 'Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService')

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

        $servicingTokens["SharePointAction"] = "None"
        $servicingTokens["ReportingAction"] = "None"

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

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

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

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

            $start = Get-Date

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

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

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

                if (($jobDetail -eq $null) -or 
                    (($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Queued) -and 
                     ($jobDetail.JobStatus -ne [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Running)))
                {
                    if ($jobDetail.Result -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobResult]::Failed -or 
                        $jobDetail.JobStatus -eq [Microsoft.TeamFoundation.Framework.Client.ServicingJobStatus]::Failed)
                    {
                        throw "Error creating team project collection $Name : "
                    }
                
                    return Get-TfsTeamProjectCollection -Server $Server -Credential $Credential -Collection $Name
                }
            }
        }
        finally
        {
                Write-Progress -Id 1 -Activity "Create team project collection" -Completed
        }

        throw (New-Object 'System.TimeoutException' -ArgumentList "Operation timed out during creation of team project collection $Name")
    }
}
<#
 
.SYNOPSIS
    Deletes a team project collection
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
    System.Uri
#>

Function Remove-TfsTeamProjectCollection
{
    [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [object] 
        $Collection,

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

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

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

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

                $collectionInfo.Delete()
            }
            finally
            {
                Write-Progress -Id 1 -Activity "Delete team project collection" -Completed
            }
        }
    }
}
<#
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
    System.Uri
#>

Function Start-TfsTeamProjectCollection
{
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [object] 
        $Collection,

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

    Process
    {
        throw "Not implemented"
    }
}
<#
 
.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default is the credential of the user under which the PowerShell process is being run - in most cases that corresponds to the user currently logged in.

Type a user name, such as 'User01' or 'Domain01\User01', or enter a PSCredential object, such as one generated by the Get-Credential cmdlet. If you type a user name, you will be prompted for a password.

To connect to Visual Studio Team Services you must either: enable Alternate Credentials for your user profile and supply that credential in this argument or omit this argument to have a logon being dialog displayed automatically.

For more information on Alternate Credentials for your Visual Studio Team Services account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.
 
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
    System.Uri
#>

Function Stop-TfsTeamProjectCollection
{
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [object] 
        $Collection,

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

    Process
    {
        throw "Not implemented"
    }
}