Public/Projects.ps1


## Projects

<#
.SYNOPSIS
    Gets the Projects from a TM instance.
 
.DESCRIPTION
    The `Get-TMProject` function gets Projects from a TM instance specified in a TMSession object.
 
    By default it calls the REST endpoint of a TM server.
    A value of "$false" can be passed to the -UseAPI parameter to call the Web Service endpoint instead.
 
.PARAMETER TMSession
    Specifies the name of the TMSession whose Projects will be fetched.
 
.PARAMETER CurrentProject
    Gets the TMSession.UserContext.Project property of a TMSession object and returns a corresponding TMProject object.
 
.PARAMETER UseAPI
    If a value of $false is passed to this parameter, the function uses web service calls to get the Project data.
 
    NOTE:Currently, the REST Endpoint and the Web Services endpoint return different set of properties.
        For more information check the TMProject class source code.
 
.PARAMETER Project
Gets a Project where the Project Name or Project Code matches the specified value.
 
.PARAMETER ResetIDs
 
.NOTES
    An existing TMSession needs to be created before Get-TMProject can be used.
 
.INPUTS
    You can pipe a TMSession object or a string with the name of an existing TMSession.
 
.OUTPUTS
    [TMProject]
        This function outputs a TMProject class object.
 
.EXAMPLE
    Get the current Project, as specified in the TMSession.UserContext.Project property of the TMSession
    Get-TM-Project -Current
 
.EXAMPLE
    Get a list of Projects from a TMSession named 'Default'
    Get-TMProject -TMSession 'Default'
 
.EXAMPLE
    Get a list of Projects from a TMSession named 'Default', using web service calls instead of a REST endpoint.
    Get-TMProject -TMSession 'Default'
#>

function Get-TMProject {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)][psobject]$TMSession = 'Default',
        [Alias('Current')][Parameter(Mandatory = $false)][Switch]$CurrentProject,
        [Parameter(Mandatory = $false)][Bool]$UseAPI = $true,
        [Alias('Name', 'ProjectCode', 'ProjectName')][Parameter(Mandatory = $false, Position = 0)][string]$Project,
        [Parameter(Mandatory = $false)][Switch]$ResetIDs
    )
    begin {
        $PSBoundParameters.Remove('UseWebServices') | Out-Null
    }
    process {
        try {
            if ($UseAPI) {
                Get-TMProjectRestApi @PSBoundParameters
            } else {
                Get-TMProjectWebService @PSBoundParameters
            }
        } catch {
            throw $_
        }

    }
    end {
    }
}
function Enter-TMProject {
    <#
    .SYNOPSIS
        Sets the active Project on a TransitionManager session.
 
    .DESCRIPTION
        Changes the current Project context for the resolved TM session by Project
        identifier or by Project name/code.
 
    .PARAMETER TMSession
        A TMSession object or session name to update. Defaults to `'Default'`.
 
    .PARAMETER ProjectID
        The Project identifier to switch to when using the `ByProjectId`
        parameter set.
 
    .PARAMETER ProjectNameOrCode
        The Project name or Project code to switch to when using the
        `ByProjectNameOrCode` parameter set.
 
    .EXAMPLE
        Enter-TMProject -ProjectID 1001
 
        Sets the current session Project to the Project with id `1001`.
 
    .EXAMPLE
        Enter-TMProject -ProjectNameOrCode 'WAVE1'
 
        Sets the current session Project by Project name or Project code.
 
    .NOTES
        This function updates the `UserContext.Project` values on the resolved
        session object.
    #>

    param(
        [Parameter(Mandatory = $false)][psobject]$TMSession = 'Default',
        [Parameter(Mandatory = $false, ParameterSetName = 'ByProjectId', Position = 0)][int]$ProjectID,
        [Alias('Project')][Parameter(
            Mandatory = $false,
            ParameterSetName = 'ByProjectNameOrCode',
            Position = 0)][string]$ProjectNameOrCode
    )

    $TMSession = Get-TMSession $TMSession

    ## If either the Project ID or Project Code were known, they could be used.
    ## However, support for changing based just on the Project name is possible

    switch ($PSCmdlet.ParameterSetName) {
        'ByProjectId' {
            $Project = Get-TMProject -Project $ProjectID -TMSession $TMSession
        }

        'ByProjectNameOrCode' {
            $Project = Get-TMProject -Project $ProjectNameOrCode -TMSession $TMSession
        }
    }

    if (-not $Project.Id) {
        $idType = $PSCmdlet.ParameterSetName -replace '^By'
        $projectVar = Get-Variable -Name $idType
        throw 'Project with {1}="{0}" does not exist. Please create it and run the script again.' -f $projectVar.Value, $idType
    }

    $uri = 'https://{0}/{1}/{2}' -f $TMSession.TMServer, 'tdstm/ws/project/viewEditProject', $Project.Id
    $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSession.TMWebSession -SkipCertificateCheck:$TMSession.AllowInsecureSSL

    if ($response.StatusCode -in @(200, 204)) {
        $newProject = ($Response.Content | ConvertFrom-Json).data.projectInstance
        $TMSession.UserContext.Project.Id = $newProject.id
        $TMSession.UserContext.Project.Name = $newProject.name

        ## The code property has not been consistent in builds between 4.7 -> 6.0-alpha. Simply force it
        Add-Member -InputObject $TMSession.UserContext.Project -NotePropertyName 'code' -NotePropertyValue $newProject.projectCode -Force

        if ($VerbosePreference -eq 'Continue') {
            Write-Host 'Project has been changed to: ' -NoNewline
            Write-Host $ProjectName -ForegroundColor Cyan
        }
    } else {
        throw 'Unable to Set Projects.'
    }
}

    function New-TMProject {
        <#
    .SYNOPSIS
    Creates a Transition Manager Project in a TM instance.
 
    .DESCRIPTION
    Sends a REST API request to a TM instance to create a Project and returns a TMProject object with the new Project details if created successfully.
 
    .PARAMETER Name
    The Project Name
 
    .PARAMETER TMSession
    The name of the Transition Manager session
 
    .PARAMETER Company
    The TM Client name. It should already exist in Transition Manager.
 
    .PARAMETER Code
    The Project Code of the Project.
 
    .PARAMETER StartDate
    The start date of the Project. This parameter expects a date in the "yyyy-MM-ddTHH:mm:ssZ" format. If not specified, the current date and time will be used as the start date.
 
    .PARAMETER EndDate
    The end date of the Project. This parameter expects a date in the "yyyy-MM-ddTHH:mm:ssZ" format. If not specified, the current date and time a year from now will be used as the end date.
 
    .PARAMETER UseAPI
 
 
    .EXAMPLE
    New-TMProjectRestApi -Name 'Test Project' -TMSession 'Default' -Company 'TDS'
    Creates a Project named 'Test Project' in the TransitionManager instance in the TMSession named 'Default', if it does not exist.
 
    .OUTPUTS
    One ore more TMProject objects
    #>

        param(
            [Parameter(Mandatory = $true)]
            [string]$Name,

            [Parameter(Mandatory = $false)]
            [string]$Company = 'TM Demo',

            [Parameter(Mandatory = $false)]
            [ValidateLength(1, 20)]
            [string]$Code = $Name,

            [Parameter(Mandatory = $false)]
            [psobject]$TMSession = 'Default',

            [Parameter(Mandatory = $false)]
            [DateTime]$StartDate = (Get-Date -AsUTC),

            [Parameter(Mandatory = $false)]
            [DateTime]$EndDate = (Get-Date -AsUTC).AddYears(1),

            [Parameter(Mandatory = $false)]
            [Bool]$UseAPI = $true,

            [Parameter(Mandatory = $false)]
            [Switch]$Passthru
        )

        begin {

            try {
                ## Get Session Configuration
                $TMSession = Get-TMSession $TMSession
                #Get "Company" ('Client' in TM) id.
                $ClientId = (Get-TMCompany -Name $Company -TMSession $TMSession.Name).Id
            } catch {
                throw $_
            }
        }

        process {
            try {
                if ($UseAPI) {

                    $RestBody = @{
                        name              = $Name
                        projectType       = 'Standard'
                        projectCode       = $Code
                        clientId          = $ClientId
                        collectMetrics    = $true
                        defaultBundleName = 'TBD'
                        startDate         = $StartDate.ToString('yyyy-MM-ddTHH:mm:ssZ')
                        completionDate    = $EndDate.ToString('yyyy-MM-ddTHH:mm:ssZ')
                    }

                    $Response = Invoke-TMRestMethod -Api project -Method Post -BodyParams $RestBody
                    return [TMProject]::new($Response)
                } else {
                    $WebServiceParams = @{
                        Name      = $Name
                        Company   = $Company
                        Code      = $Code
                        TMSession = $TMSession
                        StartDate = $StartDate
                        EndDate   = $EndDate
                        Passthru  = $Passthru
                    }

                    New-TMProjectWebService @WebServiceParams
                }
            } catch {
                throw $_
            }
        }
        end {

        }
    }

    function Get-TMProjectWebService {
        <#
        .SYNOPSIS
            Gets Projects from TransitionManager by using the web service endpoint.
 
        .DESCRIPTION
            Retrieves Projects by calling the web service implementation and
            optionally filters by Project name or code.
 
        .PARAMETER TMSession
            A TMSession object or session name to use for the request. Defaults to
            `'Default'`.
 
        .PARAMETER Project
            The Project name or Project code to retrieve.
 
        .PARAMETER ResetIDs
            Switch indicating that identifiers on the returned objects should be
            refreshed or normalized during retrieval.
 
        .EXAMPLE
            Get-TMProjectWebService -Project 'WAVE1'
 
            Retrieves the Project whose name or code matches `WAVE1` by using the
            web service endpoint.
 
        .NOTES
            This helper is used by `Get-TMProject` when `-UseAPI $false` is chosen.
        #>

        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $false)][psobject]$TMSession = 'Default',
            [Alias('Name', 'ProjectCode', 'ProjectName')][Parameter(Mandatory = $false, Position = 0)][string]$Project,
            [Parameter(Mandatory = $false)][Switch]$ResetIDs
        )

        begin {
            ## Get Session Configuration
            $TMSession = Get-TMSession $TMSession

            #Honor SSL Settings
            $TMCertSettings = @{SkipCertificateCheck = $TMSession.AllowInsecureSSL }
            # Format the uri
            $instance = $instance = $TMSession.TMServer.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
            $uri = "https://$instance/tdstm/ws/projects"

        }

        process {

            try {
                $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSession.TMWebSession @TMCertSettings
            } catch {
                throw $_
            }

            if ($response.StatusCode -in 200, 204) {
                $Results = ($response.Content | ConvertFrom-Json).data | ForEach-Object { [TMProject]::New($_) }
            } else {
                throw 'Unable to collect Projects.'
            }

            if ($ResetIDs) {
                ## Clear Active Projects
                for ($i = 0; $i -lt $Results.Count; $i++) {
                    $Results[$i].id = $null
                }
            }

            if ($Project) {
                $Results = $Results | Where-Object {
                    $_.name -eq $Project -or $_.projectCode -eq $Project
                }
            }

            return $Results
        }

        end {

        }
    }
    function Get-TMProjectRestApi {
        <#
        .SYNOPSIS
            Gets Projects from TransitionManager by using the REST API.
 
        .DESCRIPTION
            Retrieves Projects by using the REST API and optionally filters by the
            current Project or by Project name/code.
 
        .PARAMETER TMSession
            A TMSession object or session name to use for the request. Defaults to
            `'Default'`.
 
        .PARAMETER CurrentProject
            Switch indicating that only the session's current Project should be
            returned.
 
        .PARAMETER Project
            The Project name or Project code to retrieve.
 
        .PARAMETER ResetIDs
            Switch indicating that identifiers on the returned objects should be
            refreshed or normalized during retrieval.
 
        .EXAMPLE
            Get-TMProjectRestApi -CurrentProject
 
            Retrieves the current Project for the resolved session by using the REST
            API.
 
        .NOTES
            This helper is used by `Get-TMProject` when the REST implementation is
            selected.
        #>

        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $false)][psobject]$TMSession = 'Default',
            [Alias('Current')][Parameter(Mandatory = $false)][Switch]$CurrentProject,
            [Alias('Name', 'ProjectCode', 'ProjectName')][Parameter(Mandatory = $false, Position = 0)][string]$Project,
            [Parameter(Mandatory = $false)][Switch]$ResetIDs
        )

        begin {
            ## Get Session Configuration
            $TMSession = Get-TMSession $TMSession
            $Api = $CurrentProject ? 'project/{0}' -f $TMSession.userContext.Project.id : 'project'
        }

        process {

            $Response = Invoke-TMRestMethod -Api $Api -Method Get
            $Results = $Response | ForEach-Object { [TMProject]::New($_) }

            if ($ResetIDs) {
                ## Clear Active Projects
                foreach ($Result in $Results) {
                    $Result.Id = $null
                }
            }

            if ($Project) {
                $Results = $Results | Where-Object {
                    $_.name -eq $Project -or $_.projectCode -eq $Project
                }
            }

            return $Results
        }

        end {

        }
    }

function Remove-TMProject {
    <#
    .SYNOPSIS
    Deletes a TransitionManager Project in a TM instance.
 
    .DESCRIPTION
    Sends a REST API request to a TM instance to delete a Project and returns a TMProject object with the deleted Project details if deleted successfully.
 
    .PARAMETER Name
    The Project name of the Project to be deleted.
 
    .PARAMETER TMSession
    The name of the Transition Manager session
 
    .EXAMPLE
    Remove-TMProject -Name 'Test Project' -TMSession 'Default'
    Deletes a Project named 'Test Project' in the TransitionManager instance in the TMSession named 'Default', if it exists.
 
    .OUTPUTS
    A TMProject object.
    #>

        param(
            [Parameter(Mandatory = $true)]
            [string]$Name,

            [Parameter(Mandatory = $false)]
            [psobject]$TMSession = 'Default'
        )

        begin {
            $TMSession = Get-TMSession $TMSession
            $Project = Get-TMProject -Project $Name -TMSession $TMSession
            $api = 'project/{0}' -f $Project.Id

            if ( $Project.Count -gt 1 ) {
                throw 'More than 1 Project found with given Name "{1}": IDs {0}' -f
                    $($Project.id -join ', '),
                    $Name
            }
        }

        process {
            $null = Invoke-TMRestMethod -Api $api -Method Delete
            $okMessage = "Project '{0}' (id {1}) has been successfully deleted." -f
                $Project.Name, $Project.Id
            Write-Host $okMessage
        }

    }