TeamProjectCollection/TeamProjectCollection.psm1

<#
#>

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

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

    Process
    {
        throw "Not implemented"
    }
}
<#

.SYNOPSIS
    Detaches a team project collection database from a Team Foundation Server installation.

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

#>

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-TfsTeamProject 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 current user.
    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 Online you must enable Alternate Credentials for your user profile and supply that credential in this argument.
    For more information on Alternate Credentials for your Visual Studio Online account, please refer to https://msdn.microsoft.com/library/dd286572#setup_basic_auth.

.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")]
        [System.Management.Automation.Credential()]
        [System.Management.Automation.PSCredential]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    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($Url, $Cred)
{
    
    if ($Cred -ne [System.Management.Automation.PSCredential]::Empty)
    {
        return New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList $Url, (_GetCredential $cred)
    }

    return [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection([Uri] $Url)
}


Function _GetCollectionFromName($Name, $Server, $Cred)
{
    Process
    {
        $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
        }

    }
}

Function _GetCredential
{
    Param ($Cred)

    if (($Cred -ne $null) -and ($Cred -ne [System.Management.Automation.PSCredential]::Empty))
    {
        return [System.Net.NetworkCredential] $Cred
    }
    
    return [System.Net.CredentialCache]::DefaultNetworkCredentials
}<#

.SYNOPSIS
    Attaches a team project collection database to a Team Foundation Server installation.
#>

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.

#>

Function New-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")]
        [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(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]'

        $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

#>

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