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 {
    param(
        [Parameter(Mandatory = $false)][PSObject]$TMSession = 'Default',
        [Parameter(Mandatory = $false, ParameterSetName = "ByProjectId", Position = 0)][Int]$ProjectID,
        [Alias("Project")][Parameter(
            Mandatory = $false,
            HelpMessage = 'Enter the Project Name or Project Code',
            ParameterSetName = "ByProjectNameOrCode",
            Position = 0)][String]$ProjectNameOrCode
    )

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

    #Honor SSL Settings
    $TMCertSettings = @{SkipCertificateCheck = $TMSession.AllowInsecureSSL }

    ## 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
    if (-not $ProjectID) {
        ## Get the Project by Name or Code
        $Project = Get-TMProject -Project $ProjectNameOrCode -TMSession $TMSession
        $ProjectID = $Project.id
        if (!$ProjectID) {
            throw "Project [" + $ProjectNameOrCode + "] does not exist. Please create it and run the script again."
        }
    }

    $uri = "https://"
    $uri += $TMSession.TMServer
    $uri += '/tdstm/ws/project/viewEditProject/' + $ProjectID


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

    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) {
                # Format the uri
                $Instance = $TMSession.TMServer

                $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")
                }

                $QueryString = [System.Web.HttpUtility]::ParseQueryString([String]::Empty)
                $RestBody.GetEnumerator() | ForEach-Object { $QueryString.Add($_.Key, $_.Value) }

                $RestParams = @{
                    SkipCertificateCheck = $TMSession.AllowInsecureSSL
                    Headers              = $TMSession.TMRestSession.Headers
                    Uri                  = "https://$Instance/tdstm/api/project?" + $QueryString.ToString()
                    Method               = "Post"
                    StatusCodeVariable   = "ResponseStatusCode"
                }
                try {
                    $Response = Invoke-RestMethod @RestParams
                    if ($ResponseStatusCode -in 200, 204 -and $Passthru) {
                        return [TMProject]::new($Response)
                    }

                } catch {
                    throw $_
                }
            } 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 {
    [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 {
    [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

        # Format the uri
        $Instance = $TMSession.TMServer

        $RestParams = @{
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
            Headers              = $TMSession.TMRestSession.Headers
            Uri                  = "https://$Instance/tdstm/api/project"
            Method               = "Get"
            StatusCodeVariable   = "ResponseStatusCode"
        }
        if ($CurrentProject) {
            $RestParams.Uri = $RestParams.Uri.Replace('project', "project/$($TMSession.userContext.Project.id)")
        }
    }

    process {

        try {
            $Response = Invoke-RestMethod @RestParams
        } catch {
            throw $_
        }


        if ($ResponseStatusCode -in 200, 204) {
            $Results = $Response | ForEach-Object { [TMProject]::New($_) }
        } else {
            return "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 Remove-TMProject {
    <#
    .SYNOPSIS
    Deletes a Transition Manager 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 {

        try {
            ## Get Session Configuration
            $TMSession = Get-TMSession $TMSession
            ## Get Project
            $Project = Get-TMProject -Project $Name -TMSession $TMSession
            $ProjectId = $Project.Id
        } catch {
            throw $_
        }
    }

    process {

        # Format the uri
        $Instance = $TMSession.TMServer

        $RestParams = @{
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
            Headers              = $TMSession.TMRestSession.Headers
            Uri                  = "https://$Instance/tdstm/api/project/$ProjectId"
            Method               = "Delete"
            StatusCodeVariable   = "ResponseStatusCode"
        }

        Invoke-RestMethod @RestParams
        if ($ResponseStatusCode -in 200, 204) {
            return $Project
        }

    }

    end {

    }
}