Public/AssetOptions.ps1

## TM Dependency Type
function Get-TMDependencyType {
    param(
        [Parameter(Mandatory = $false)]
        [PSObject]$TMSession = 'Default',

        [Parameter(Mandatory = $false,
            Position = 1,
            ParameterSetName = 'ByType')]
        [String]$Name,

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

    Get-TMAssetOption -TMSession $TMSession -Type 'Dependency Type' -Name $Name -ResetIDs:$ResetIDs
}


function New-TMDependencyType {
    param(
        [Parameter(Mandatory = $false)]
        [PSObject]$TMSession = 'Default',

        [Parameter(Mandatory = $true)]
        [TMDependencyType]$DependencyType
    )

    New-TMAssetOption -TMSession $TMSession -InputObject $DependencyType -Type 'Dependency Type'
}


function Get-TMAssetOption {
    <#
    .SYNOPSIS
    Retrieves one or more Asset Options from a TransitionManager instance
 
    .DESCRIPTION
    This function will retrieve one or more Asset Options (Asset Environment, Asset Plan Status,
    Asset Priority, Dependency Type, Dependency Status, Asset Type, Task Category) from
    the specified TransitionManager instance
 
    .PARAMETER TMSession
    The name of the TM Session to use when retrieving the Asset Option
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER Type
    The types of TransitionManager Asset Option to retrieve
 
    .PARAMETER Name
    The Name/Label of the Asset Option
 
    .PARAMETER ResetIDs
    Switch indicating that the Asset Option(s) should be returned with IDs set to null
 
    .EXAMPLE
    Get-TMAssetOption -TMSession 'tmddev' -Type 'Task Category' -Name 'general'
 
    .EXAMPLE
    Get-TMAssetOption
 
    .EXAMPLE
    Get-TMAssetOption -Type 'Dependency Type'
 
    .OUTPUTS
    One or more TMAssetOption class objects
    #>


    [OutputType([TMAssetOption[]])]
    [CmdletBinding(DefaultParameterSetName = 'All')]
    param(
        [Parameter(Mandatory = $false)]
        [PSObject]$TMSession = 'Default',

        [Parameter(Mandatory = $false, Position = 0, ParameterSetName = 'All')]
        [Parameter(Mandatory = $true,
            Position = 0,
            ParameterSetName = 'ByType')]
        [ValidateSet(
            'Asset Environment',
            'Asset Plan Status',
            'Asset Priority',
            'Dependency Type',
            'Dependency Status',
            'App Type',
            'Asset Type',
            'Task Category')]
        [String[]] $Type,

        [Parameter(Mandatory = $false,
            Position = 1,
            ParameterSetName = 'ByType')]
        [String]$Name,

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

    begin {

        $TMSession = Get-TMSession $TMSession
        if (-not $TMSession) {
            throw "TM Session Not Found. Use New-TMSession command before using features."
        }

        [bool] $UseRest = $PSBoundParameters.ContainsKey('Type') -and 'Task Category' -notin $Type -and 'App Type' -notin $Type

        if ($UseRest) {
            $RESTParameters = @{
                Uri                  = "https://$($TMSession.TMServer)/tdstm/api/assetOptions?project=$($TMSession.UserContext.project.id)"
                Method               = 'GET'
                WebSession           = $TMSession.TMRestSession
                SkipHttpErrorCheck   = $true
                StatusCodeVariable   = 'StatusCode'
                SkipCertificateCheck = $TMSession.AllowInsecureSSL
            }

            # Make the request
            try {
                Write-Verbose 'Invoking REST request'
                $Response = Invoke-RestMethod @RESTParameters
                Write-Verbose 'REST Parameters:'
                Write-Verbose ($RESTParameters | ConvertTo-Json -Depth 10)
                Write-Debug "Response: $Response"
            } catch {
                Write-Host "There was an error reaching the API endpoint at $($RESTParameters.URI): $_"
            }

            if (-not $Response) {
                throw "Unable to get Asset Options - response from $($RESTParameters.URI) was empty"
            }

            [hashtable] $assetOptionsDictionary = @{
                'Asset Environment' = 'environment'
                'Asset Plan Status' = 'planStatus'
                'Asset Priority'    = 'priority'
                'Dependency Type'   = 'dependencyType'
                'Dependency Status' = 'dependencyStatus'
                'App Type'          = 'appType'
                'Asset Type'        = 'assetType'
                'Task Category'     = 'taskCategory'
            }

        }

        else {
            Write-Warning "Fetching from WEB UI (slower) as the REST API does not support all selected Asset Options"
            Import-Module PowerHTML
            $Instance = $TMSession.TMServer.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
            $Uri = "https://$instance/tdstm/assetEntity/assetOptions"

            $WebRequestSplat = @{
                Method               = 'GET'
                Uri                  = $Uri
                WebSession           = $TMSession.TMWebSession
                SkipCertificateCheck = $TMSession.AllowInsecureSSL
            }

            # Make the request
            try {
                Write-Verbose 'Invoking web request'
                $Response = Invoke-WebRequest @WebRequestSplat
                Write-Verbose 'Web Request Parameters:'
                Write-Verbose ($WebRequestSplat | ConvertTo-Json -Depth 10)
                Write-Verbose "Response status code: $($Response.StatusCode)"
                Write-Debug "Response Content: $($Response.Content)"
            } catch {
                throw $_
            }

            if ($Response.StatusCode -in 200, 204) {
                $AssetOptions = @{}
                $HTML = ConvertFrom-Html -Content $Response.Content -Raw
                $AssetTypes = @(
                    @{Element = 'planStatusTbodyId'; Class = 'TMAssetPlanStatus' }
                    @{Element = 'priorityStatusTbodyId'; Class = 'TMAssetPriority' }
                    @{Element = 'dependencyTypeTbodyId'; Class = 'TMDependencyType' }
                    @{Element = 'dependencyStatusTbodyId'; Class = 'TMDependencyStatus' }
                    @{Element = 'envOptionTbodyId'; Class = 'TMAssetEnvironment' }
                    @{Element = 'appTypeTbodyId'; Class = 'TMAppType' }
                    @{Element = 'assetTypeTbodyId'; Class = 'TMAssetType' }
                    @{Element = 'taskCategoryTbodyId'; Class = 'TMTaskCategory' }
                )
                foreach ($AssetType in $AssetTypes) {
                    $Result = [System.Collections.ArrayList]::new()
                    $TableBody = $HTML.DocumentNode.SelectNodes("//*[contains(@id, '$($AssetType.Element)')]")
                    $ChildNodes = $AssetType.Element -eq 'appTypeTableId' ? $TableBody.ChildNodes[3].ChildNodes : $TableBody.ChildNodes
                    foreach ($Node in $ChildNodes) {
                        if ($Node.Attributes.Count -gt 0) {
                            if ($Node.Attributes[0].Name -eq 'id') {
                                $TypeId = $ResetIDs.IsPresent ? $null : $Node.Attributes[0].Value.Split('_')[1]
                                $TypeName = $Node.ChildNodes[1].innerText
                                $AssetOption = New-Object -TypeName $AssetType.Class -ArgumentList $TypeId, $TypeName
                                [void]$Result.Add($AssetOption)
                            }
                        }
                    }

                    $AssetOptions.Add($AssetType.Element.Replace('TbodyId', '').Replace('TableId', ''), $Result)
                }
            } else {
                throw 'Unable to get Asset Options'
            }

            [hashtable] $AssetOptionsDictionary = @{
                'Asset Environment' = 'envOption'
                'Asset Plan Status' = 'planStatus'
                'Asset Priority'    = 'priorityStatus'
                'Dependency Type'   = 'dependencyType'
                'Dependency Status' = 'dependencyStatus'
                'App Type'          = 'appType'
                'Asset Type'        = 'assetType'
                'Task Category'     = 'taskCategory'
            }

        }
    }

    process {
        [hashtable] $SelectedAssetOptions = @{}
        [string[]] $AvailableTypesToChoose = 'Asset Environment',
        'Asset Plan Status',
        'Asset Priority',
        'Dependency Type',
        'Dependency Status',
        'App Type',
        'Asset Type',
        'Task Category'

        if ($UseRest) {
            # This used to return a hash table. Build it from the PSObject we have in $Response

            # Filter out by $Type
            Write-Verbose ("Types: $($Type -join ', ')")
            [string[]] $ResponsePropertyNames = ($Response | Get-Member -MemberType NoteProperty).Name
            $SelectedResponsePropertyNames = $ResponsePropertyNames | Where-Object { $_ -in ($Type | ForEach-Object { $AssetOptionsDictionary[$_] }) }
            Write-Verbose "Selected: $SelectedResponsePropertyNames"
            foreach ($Property in $SelectedResponsePropertyNames) {
                Write-Verbose " Adding $Property"
                $Response.$Property | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Name label -Value $_.value }
                $SelectedAssetOptions.Add(
                    $Property,
                    $Response.$Property
                )
            }
        }

        else {
            # Do we need to filter the return object? if not, then grab all types
            if (-not $PSBoundParameters.ContainsKey('Type') ) {
                $Type = $AvailableTypesToChoose
            }

            Write-Verbose ("Types: {0}" -f $Type -join ',')
            foreach ($TypeName in $Type) {
                $ShortTypeName = $AssetOptionsDictionary[$TypeName]
                Write-Verbose " Checking '$TypeName' as '$ShortTypeName' with $($Assetoptions[$ShortTypeName].Count) values"
                $SelectedAssetOptions.Add(
                    $ShortTypeName,
                    $Name ?
                        ($Assetoptions[$ShortTypeName] | Where-Object label -EQ $Name) :
                        ($Assetoptions[$ShortTypeName] )
                )
            }
        }

        if ($ResetIDs) {
            foreach ($Key in $SelectedAssetOptions.Keys) {
                $SelectedAssetOptions[$Key] | ForEach-Object { $_.id = $null }
            }
        }
        
        if($Type.Count -eq 1){
            ## There is only one type of data in
            $SelectedAssetOptions."$($SelectedAssetOptions.Keys[0])"
        } else {
            $SelectedAssetOptions
        }
    }
}


function New-TMAssetOption {
    <#
    .SYNOPSIS
    Creates a new Asset Option in TransitionManager
 
    .DESCRIPTION
    This function will create a new Asset Option (Asset Environment, Asset Plan Status,
    Asset Priority, Dependency Type, Dependency Status, Asset Type, Task Category) on
    the specified TransitionManager instance
 
    .PARAMETER TMSession
    The name of the TM Session to use when creating the Asset Option
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER Type
    The type of TransitionManager Asset Option to create
 
    .PARAMETER Name
    The Name/Label of the Asset Option
 
    .PARAMETER InputObject
    A TMAssetOption object representing the Asset Option to create
 
    .PARAMETER Passthru
    Switch indicating that the newly created Asset Option should be returned
 
    .EXAMPLE
    New-TMAssetOption -TMSession 'tdsmd06' -Type 'Asset Priority' -Name 'Critical' -Passthru
 
    .EXAMPLE
    $AssetType = [TMAssetType]::new('Server')
    New-TMAssetOption -InputObject $AssetType
 
    .EXAMPLE
    New-TMSession -ProfileName 'tmddev'
    New-TMSession -ProfileName 'tmddev2'
    Get-TMAssetOption -TMSession 'tmddev' -Type 'Asset Plan Status' | New-TMAssetOption -TMSession 'tmddev2'
 
    .OUTPUTS
    A TMAssetOption object if the Passthru switch is used, otherwise nothing
    #>


    [CmdletBinding(DefaultParameterSetName = 'ByProperty')]
    param(
        [Parameter(Mandatory = $false)]
        [PSObject]$TMSession = 'Default',

        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateSet(
            'Asset Environment',
            'Asset Plan Status',
            'Asset Priority',
            'Dependency Type',
            'Dependency Status',
            'App Type',
            'Asset Type',
            'App Type',
            'Task Category')]
        [String]$Type,

        [Parameter(Mandatory = $true,
            Position = 1,
            ParameterSetName = 'ByProperty')]
        [Alias('Label')]
        [String]$Name,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ParameterSetName = 'ByObject')]
        [TMAssetOption]$InputObject,

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

    begin {
        ## Get Session Configuration
        $TMSession = Get-TMSession $TMSession
        if (-not $TMSession) {
            throw "TM Session Not Found. Use New-TMSession command before using features."
        }

        $Instance = $TMSession.TMServer.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
        $Uri = "https://$instance/tdstm/assetEntity/saveAssetoptions"

        Set-TMHeaderContentType -ContentType 'Form' -TMSession $TMSession
    }

    process {
        if ($PSCmdlet.ParameterSetName -eq 'ByObject') {
            $Type = switch ($InputObject.GetType().Name) {
                'TMAssetEnvironment' { 'Asset Environment' }
                'TMAssetPlanStatus' { 'Asset Plan Status' }
                'TMAssetPriority' { 'Asset Priority' }
                'TMDependencyType' { 'Dependency Type' }
                'TMDependencyStatus' { 'Dependency Status' }
                'TMAssetType' { 'App Type' }
                'TMAssetType' { 'Asset Type' }
                'TMTaskCategory' { 'Task Category' }
                default {
                    Write-Error "The type of Asset Option could not be determined"
                    return
                }
            }
            $Name = $InputObject.label
        }

        switch ($Type) {
            'Asset Environment' { $Class = 'TMAssetEnvironment'; $PostBody = @{environment = $Name; assetOptionType = 'environment' } }
            'Asset Plan Status' { $Class = 'TMAssetPlanStatus'; $PostBody = @{planStatus = $Name; assetOptionType = 'planStatus' } }
            'Asset Priority' { $Class = 'TMAssetPriority'; $PostBody = @{priorityOption = $Name; assetOptionType = 'Priority' } }
            'Dependency Type' { $Class = 'TMDependencyType'; $PostBody = @{dependencyType = $Name; assetOptionType = 'dependency' } }
            'Dependency Status' { $Class = 'TMDependencyStatus'; $PostBody = @{dependencyStatus = $Name; assetOptionType = 'dependencyStatus' } }
            'App Type' { $Class = 'TMAppType'; $PostBody = @{appType = $Name; assetOptionType = 'appType' } }
            'Asset Type' { $Class = 'TMAssetType'; $PostBody = @{assetType = $Name; assetOptionType = 'assetType' } }
            'Task Category' { $Class = 'TMTaskCategory'; $PostBody = @{taskCategory = $Name; assetOptionType = 'taskCategory' } }
        }

        $WebRequestSplat = @{
            Method               = 'POST'
            Uri                  = $Uri
            WebSession           = $TMSession.TMWebSession
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
            Body                 = $PostBody
        }

        # Make the request
        try {
            Write-Verbose "Web Request Parameters:"
            Write-Verbose ($WebRequestSplat | ConvertTo-Json -Depth 10)
            Write-Verbose "Invoking web request"
            $Response = Invoke-WebRequest @WebRequestSplat
            Write-Verbose "Response status code: $($Response.StatusCode)"
            Write-Verbose "Response Content: $($Response.Content)"
        } catch {
            throw $_
        }

        if ($Response.StatusCode -in 200, 204) {
            $ResponseContent = $Response.Content | ConvertFrom-Json
            if ($ResponseContent.status -eq "error") {
                if ($ResponseContent.errors[0] -notlike 'Property value with value * must be unique') {
                    Write-Error $ResponseContent.errors[0]
                }
            } elseif ($Passthru) {
                New-Object -TypeName $Class -ArgumentList $ResponseContent.id, $Name
            }
        }
    }
}


function Remove-TMAssetOption {
    <#
    .SYNOPSIS
    Deletes an Asset Option from TransitionManager
 
    .DESCRIPTION
    This function will delete an Asset Option (Asset Environment, Asset Plan Status,
    Asset Priority, Dependency Type, Dependency Status, Asset Type, Task Category) from
    the specified TransitionManager instance
 
    .PARAMETER TMSession
    The name of the TM Session to use when deleting the Asset Option
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER Type
    The type of TransitionManager Asset Option to delete
 
    .PARAMETER Name
    The NAme of the Asset Option to delete
 
    .PARAMETER Id
    The Id of the Asset Option to delete
 
    .PARAMETER InputObject
    A TMAssetOption object representing the Asset Option to remove
 
    .EXAMPLE
    Get-TMAssetOption -Type 'Asset Environment' | Remove-TMAssetOption
 
    .EXAMPLE
    Remove-TMAssetOption -TMSession 'tmddev' -Type 'Dependency Type' -Name 'A2A'
 
    .OUTPUTS
    None
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [PSObject]$TMSession = 'Default',

        [Parameter(Mandatory = $true,
            Position = 0,
            ParameterSetName = 'ByName')]
        [Parameter(Mandatory = $true,
            Position = 0,
            ParameterSetName = 'ById')]
        [ValidateSet(
            'Asset Environment',
            'Asset Plan Status',
            'Asset Priority',
            'Dependency Type',
            'Dependency Status',
            'Asset Type',
            'App Type',
            'Task Category')]
        [String]$Type,

        [Parameter(Mandatory = $true,
            Position = 1,
            ParameterSetName = 'ByName')]
        [Alias('Label')]
        [String]$Name,

        [Parameter(Mandatory = $true,
            Position = 1,
            ParameterSetName = 'ById')]
        [String]$Id,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ParameterSetName = 'ByObject')]
        [TMAssetOption]$InputObject
    )

    begin {
        ## Get Session Configuration
        $TMSession = Get-TMSession $TMSession
        if (-not $TMSession) {
            throw "TM Session Not Found. Use New-TMSession command before using features."
        }

        $Instance = $TMSession.TMServer.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
        $Uri = "https://$instance/tdstm/assetEntity/deleteAssetOptions"

        Set-TMHeaderContentType -ContentType 'Form' -TMSession $TMSession
    }

    process {
        if ($PSCmdlet.ParameterSetName -eq 'ByObject') {
            $Type = switch ($InputObject.GetType().Name) {
                'TMAssetEnvironment' { 'Asset Environment' }
                'TMAssetPlanStatus' { 'Asset Plan Status' }
                'TMAssetPriority' { 'Asset Priority' }
                'TMDependencyType' { 'Dependency Type' }
                'TMDependencyStatus' { 'Dependency Status' }
                'TMAssetType' { 'Asset Type' }
                'TMTaskCategory' { 'Task Category' }
            }
            $Name = $InputObject.label
            $Id = $InputObject.id
        }

        # Get the Id if it wasn't provided
        if (($null -eq $Id) -or ($Id -le 0)) {
            $AssetOption = Get-TMAssetOption -TMSession $TMSession -Type $Type -Name $Name
            if ($AssetOption) {
                $Id = $AssetOption.id
            } else {
                # There is no asset option, so there's nothing to remove
                return
            }
        }

        # Format the request form body
        $PostBody = switch ($Type) {
            'Asset Environment' { @{ environmentId = $Id; assetOptionType = 'environment' } }
            'Asset Plan Status' { @{ assetStatusId = $Id; assetOptionType = 'planStatus' } }
            'Asset Priority' { @{ priorityId = $Id; assetOptionType = 'Priority' } }
            'Dependency Type' { @{ dependecyId = $Id; assetOptionType = 'dependency' } }
            'Dependency Status' { @{ dependecyId = $Id; assetOptionType = 'dependencyStatus' } }
            'Asset Type' { @{ assetTypeId = $Id; assetOptionType = 'assetType' } }
            'Task Category' { @{ taskCategoryId = $Id; assetOptionType = 'taskCategory' } }
        }

        # Format the web request
        $WebRequestSplat = @{
            Method               = 'POST'
            Uri                  = $Uri
            WebSession           = $TMSession.TMWebSession
            SkipCertificateCheck = $AllowInsecureSSL
            Body                 = $PostBody
        }

        # Make the web request
        try {
            Write-Verbose "Web Request Parameters:"
            Write-Verbose ($WebRequestSplat | ConvertTo-Json -Depth 10)
            Write-Verbose "Invoking web request"
            $Response = Invoke-WebRequest @WebRequestSplat
            Write-Verbose "Response status code: $($Response.StatusCode)"
            Write-Verbose "Response Content: $($Response.Content)"
        } catch {
            Write-Error $_
        }

        # Process the response
        if ($Response.StatusCode -in 200, 204) {
            $ResponseContent = $Response.Content | ConvertFrom-Json
            if ($ResponseContent.status -eq "error") {
                Write-Error $ResponseContent.errors[0]
            }
        }
    }
}