Public/Models.ps1

using namespace System.Collections.Generic
# https://github.com/dotnet/platform-compat/blob/master/docs/DE0006.md

function Get-TMModel {
    <#
    .SYNOPSIS
    Gets a Model from TransitionManager
 
    .DESCRIPTION
    This function will retrieve a Model from TransitionManager by name or Id
 
    .PARAMETER TMSession
    The name of the TM Session to use when retrieving a Model
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER ResetIDs
    Switch indicating that the Model(s) should be returned without Id's
 
    .PARAMETER Page
    Used internally when more than 1000 Models exist in the TransitionManager instance
 
    .PARAMETER Name
    The name of the Model to be retrieved
 
    .PARAMETER Id
    The Id of the Model to be retrieved
 
    .EXAMPLE
    Get-TMModel -TMSession 'TMDDEV' -Name 'PowerEdge R410'
 
    .OUTPUTS
    PSCustomObject representing the Model in TransitionManager
    #>


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

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

        [Parameter(Mandatory = $false)]
        [Int]$Page = 1,

        [Parameter(Mandatory = $false,
            Position = 0,
            ValueFromPipeline = $true,
            ParameterSetName = 'ByName')]
        [String]$Name,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ById')]
        [Int]$Id,

        [Parameter()] [Int16] $Rows = 1000
    )

    begin {
        $TMSession = Get-TMSession $TMSession

        # Prepare the REST request
        $RestParameters = @(
            "project=$($TMSession.UserContext.Project.Id)",
            "rows=$Rows",
            "page=$Page"
        )
        if ($Name) {
            $RestParameters += 'modelName={0}' -f [System.Web.HttpUtility]::UrlEncode("=$Name")
        }
        $api = $Id ? "model/$Id" : 'model'
        $RestSplat = @{
            Uri                  = "https://$($TMSession.TMServer)/tdstm/api/${api}?$($RestParameters -join '&')"
            Method               = 'GET'
            WebSession           = $TMSession.TMRestSession
            StatusCodeVariable   = 'StatusCode'
            SkipHttpErrorCheck   = $true
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
        }

        try {
            $Result = Invoke-RestMethod @RestSplat
            if ($StatusCode -eq 200) {
                $Models = [List[pscustomobject]]::new($Result.records ?? 1)
                if ($Id) {
                    # We will get a single record, not a collection of 1
                    $Models.Add($Result)
                } else {
                    $Result.rows.ForEach( { $Models.Add($_) } )
                    # The total property in $Result means the total number of pages
                    if ($Page -eq 1 -and $Result.total -gt 1) {
                        # Continue to make calls until all pages have been recorded
                        for ($i = 2; $i -le $Result.total; $i++) {
                            $SubResult = Get-TMModel -TMSession $TMSession -Page $i -Rows $Rows
                            $SubResult.foreach( { $Models.Add($_) } )
                        }
                    }
                }
            } else {
                throw "The response status code $StatusCode does not indicate success: $Result"
            }
        } catch {
            throw "Error reaching the server for Models: $_"
        }
    }

    process {
        if ($ResetIDs) {
            foreach ($Model in $Models) {
                $Model.id = $null
            }
        }

        $Models
    }
}


function New-TMModel {
    <#
    .SYNOPSIS
    Creates a new Model in TransitionManager
 
    .DESCRIPTION
    This function will create a new Model in TransitionManager
 
    .PARAMETER TMSession
    The name of the TM Session to use when creating a Model
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER Name
    The name of the Model to be created
 
    .PARAMETER Description
    The new Model's description
 
    .PARAMETER AssetType
    The asset type of the new Model
 
    .PARAMETER Status
    The status of the new Model
 
    .PARAMETER Manufacturer
    The manufacturer of the new Model
 
    .PARAMETER Aliases
    One or more aliases for the new Model
 
    .PARAMETER InputObject
    A PSCustomObject representing the Model to be created
 
    .PARAMETER Passthru
    Switch indicating that the new Model should be returned after creation
 
    .EXAMPLE
    $NewModelSplat = @{
        TMSession = 'TMDDEV'
        Manufacturer = 'Microsoft'
        Name = 'Test-Model01'
        Description = "Created via PowerShell"
        Aliases = @('TestModel01', 'Test Model 01')
    }
    New-TMModel @NewModelSplat
 
    .EXAMPLE
    $ModelFromTmddev = Get-TMModel -TMSession 'TMDDEV' -Name 'Model123'
    New-TMModel -TMSession 'TMDDEV2' -InputObject $ModelFromTmddev
 
 
    .OUTPUTS
    If Passthru switch is used, an object representing the created Model. Otherwise, none
    #>


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

        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [string]$Name,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [string]$Description,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [string]$AssetType = 'Server',

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [ValidateSet('new', 'full', 'valid')]
        [string]$Status = 'new',

        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [string]$Manufacturer,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [string[]]$Aliases,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [int]$powerNameplate = 0,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [int]$powerDesign = 0,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [int]$powerUse = 0,

        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperty')]
        [int]$useImage = 0,

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

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

    begin {
        if (!(Get-Module BAMCIS.Common)) {
            # Import-Module BAMCIS.Common
        }

        $TMSession = Get-TMSession $TMSession
    }

    process {
        $ModelsToAdd = [List[psobject]]::new($InputObject?.Count ?? 1)
        switch ($PSCmdlet.ParameterSetName) {
            'ByProperty' {
                $ModelsToAdd.Add(
                    [PSCustomObject]@{
                        Name           = $Name
                        description    = $Description
                        assetType      = $AssetType
                        status         = $Status
                        manufacturer   = $Manufacturer
                        aliases        = $Aliases
                        powerNameplate = $powerNameplate
                        powerDesign    = $powerDesign
                        powerUse       = $powerUse
                        useImage       = $useImage
                    }
                )
            }

            'ByObject' {
                $InputObject | ForEach-Object {
                    $ModelsToAdd.Add(
                        [PSCustomObject]@{
                            Name           = $_.Name
                            description    = $_.Description
                            assetType      = $_.AssetType ?? 'Server'
                            status         = $_.Status ?? 'new'
                            manufacturer   = $_.Manufacturer
                            aliases        = $_.Aliases
                            powerNameplate = $_.powerNameplate ?? 0
                            powerDesign    = $_.powerDesign ?? 0
                            powerUse       = $_.powerUse ?? 0
                            useImage       = $_.useImage ?? 0
                        }
                    )
                }
            }
        }
        # Loop through the models and add them on the server
        foreach ($ModelToAdd in $ModelsToAdd) {
            # Check if the model exists. If it does, move on to the next one
            $ModelCheck = Get-TMModel -TMSession $TMSession -Name $ModelToAdd.Name
            if ($ModelCheck) {
                Write-Host 'Model [ ' -NoNewline
                Write-Host $($ModelCheck.modelName) -ForegroundColor Cyan -NoNewline
                Write-Host ' ] already exists'
                if ($Passthru) {
                    $ModelCheck
                }
                continue
            }

            # We need the model manufacturer to exist. If it doesn't, move on to the next one
            $ManufacturerOnServer = Get-TMManufacturer -TMSession $TMSession -Name $ModelToAdd.manufacturer
            if ( -not $ManufacturerOnServer) {
                $ManufacturerOnServer = Get-TMManufacturer -TMSession $TMSession -Alias $ModelToAdd.manufacturer
                if ( -not $ManufacturerOnServer) {
                    Write-Error "Manufacturer '$Manufacturer' was not found on the server. Model '$($ModelToAdd.Name)' cannot be created."
                    continue
                }
            }

            $aliasCounter = 0
            [pscustomobject[]]$IndexedAliases = foreach ($alias in $Aliases) {
                [PSCustomObject]@{
                    index = $aliasCounter++
                    name  = $alias
                }
            }

            $RestParametersMap = @{
                project        = $TMSession.UserContext.Project.Id
                modelName      = $Name
                assetType      = $AssetType
                manufacturer   = $ManufacturerOnServer.id
                powerNameplate = $powerNameplate
                powerDesign    = $powerDesign
                powerUse       = $powerUse
                aliases        = @{
                    add    = $IndexedAliases
                    delete = @()
                }
            }

            foreach ($RestParameter in $RestParametersMap.Keys) {
                try {
                    $ModelToAdd.$RestParameter = $RestParametersMap.$RestParameter
                } catch {
                    $ModelToAdd | Add-Member -MemberType NoteProperty -Name $RestParameter -value $RestParametersMap.$RestParameter
                }
            }

            $RestSplat = @{
                Uri                  = "https://$($TMSession.TMServer)/tdstm/api/model"
                Method               = [Microsoft.PowerShell.Commands.WebRequestMethod]::Post
                WebSession           = $TMSession.TMRestSession
                StatusCodeVariable   = 'StatusCode'
                SkipHttpErrorCheck   = $true
                SkipCertificateCheck = $TMSession.AllowInsecureSSL
                Body                 = $ModelToAdd | ConvertTo-Json -Depth 10 -Compress
            }
            $Response = Invoke-RestMethod @RestSplat

            if ($StatusCode -eq 200) {
                if ($Passthru) {
                    $Response
                }
            } else {
                Write-Error "Model '$($ModelToAdd.Name)' could not be created: $Response"
            }
        }
    }
}


function Remove-TMModel {
    <#
    .SYNOPSIS
    Removes a Model from TransitionManager
 
    .DESCRIPTION
    This function will remove a Model in TransitionManager by Name or Id
 
    .PARAMETER TMSession
    The TransitionManager session to be used when deleting a Model
 
    .PARAMETER Server
    The URI of the TransitionManager instance
 
    .PARAMETER Name
    The name of the Model to be removed
 
    .PARAMETER Id
    The Id of the Model to be removed
 
    .EXAMPLE
    Remove-TMModel -Name 'Test-Model100' -TMSession 'TMDDEV'
 
    .EXAMPLE
    Remove-TMModel -Id 1806
 
    .OUTPUTS
    None
    #>


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

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByName', Position = 0)]
        [string]$Name,

        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById', Position = 0)]
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByName')]
        [string]$Id
    )

    begin {
        $TMSession = Get-TMSession $TMSession

        $RestParameters = @(
            "project=$($TMSession.UserContext.Project.Id)"
        ) -join '&'

        $RestSplat = @{
            Uri                  = "https://$($TMSession.TMServer)/tdstm/api/model/$($PSBoundParameters.ContainsKey('Id') ? $Id : "ID_PLACEHOLDER")?$RestParameters"
            WebSession           = $TMSession.TMRestSession
            StatusCodeVariable   = 'StatusCode'
            SkipHttpErrorCheck   = $true
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
            Method               = [Microsoft.PowerShell.Commands.WebRequestMethod]::Delete
        }
    }

    process {
        # The API executes a DELETE by id only
        if (-not $PSBoundParameters.ContainsKey('Id')) {
            $Model = Get-TMModel -TMSession $TMSession -Name $Name
            if (-not $Model) {
                Write-Host "Specified model [ " -NoNewline
                Write-Host $Name -NoNewline -ForegroundColor Cyan
                Write-Host " ] " -NoNewline
                Write-Host "was not found" -BackgroundColor Yellow -NoNewline
                Write-Host " in project [$($TMSession.UserContext.Project.Name)]@$($TMSession.TMServer)"
                return
            } else {
                $RestSplat.Uri = $RestSplat.Uri -replace 'ID_PLACEHOLDER', $Model.modelId
            }
        }

        try {
            $Response = Invoke-RestMethod @RestSplat
            if ($StatusCode -ne 200) {
                throw "Status code $StatusCode does not indicate success"
            }
            if ($Response.deleted -ne 1) {
                throw "An unknown error happened: $Response"
            }
            Write-Host "Model [ " -NoNewline
            Write-Host $($PSBoundParameters.ContainsKey('Name') ? "'$Name'" : "id '$Id'") -ForegroundColor Yellow -NoNewline
            Write-Host " ] has been deleted"
        }
        catch {
            Write-Error "Error deleting Model '$($PSBoundParameters.ContainsKey('Name') ? $Name : $Id)': $Response ($_)"
        }
    }
}