lib/Models.ps1

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 AllowInsecureSSL
    Switch indicating that insecure SSL may be used
     
    .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)]
        [String]$TMSession = "Default",

        [Parameter(Mandatory = $false)]
        [String]$Server = $global:TMSessions[$TMSession].TMServer,

        [Parameter(Mandatory = $false)]
        $AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,

        [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
    )

    begin {

        ## Get Session Configuration
        $TMSessionConfig = $global:TMSessions[$TMSession]
        if (-not $TMSessionConfig) {
            Write-Host 'TMSession: [' -NoNewline
            Write-Host $TMSession -ForegroundColor Cyan
            Write-Host '] was not Found. Please use the New-TMSession command.'
            Throw "TM Session Not Found. Use New-TMSession command before using features."
        }

        # Format the request parameters
        $Instance = $Server.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
        $Uri = "https://$Instance/tdstm/model/listJson?rows=1000&page=$Page&sidx=modelName$(
            if ($Name) {
                "&modelName=$([System.Web.HttpUtility]::UrlEncode($Name))"
            }
        )"


        Set-TMHeaderContentType -TMSession $TMSession -ContentType 'JSON'
        Set-TMHeaderAccept -TMSession $TMSession -Accept 'JSON'
        
        $WebRequestSplat = @{
            Method               = 'GET'
            Uri                  = $Uri
            WebSession           = $TMSessionConfig.TMWebSession
            SkipCertificateCheck = $AllowInsecureSSL
        }

        # 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 $_
        }

        # Process the server's response
        $Models = [System.Collections.ArrayList]::new()
        if ($Response.StatusCode -in 200, 204) {
            
            if ($TMSessionConfig.TMVersion -like '4.*') {
                $Result = $Response.Content | ConvertFrom-Json -Depth 10
                foreach ($Row in $Result.rows) {
                    [void]$Models.Add(
                        [PSCustomObject]@{
                            id               = $Row.id
                            modelName        = $Row.cell[0]
                            manufacturerName = $Row.cell[1]
                            description      = $Row.cell[2]
                            assetType        = $Row.cell[3]
                            lastUpdated      = $Row.cell[4]
                            modelConnectors  = $Row.cell[5]
                            assetsCount      = $Row.cell[6]
                            sourceTDSVersion = $Row.cell[7]
                            sourceTDS        = $Row.cell[8]
                            status           = $Row.cell[9]
                        }
                    )
                }
            }
            else {
                $Result = ($Response.Content | ConvertFrom-Json -Depth 10).data
                [void]$Models.AddRange($Result.rows)
            }

            # Continue to make calls until all pages have been recorded
            if ($Page -eq 1 -and $Result.total -gt 1) {
                for ($i = 2; $i -le $Result.total; $i++) {
                    if ($Name) {
                        if ($Models | Where-Object { $_.modelName -eq $Name }) {
                            break
                        }
                    }
                    [void]$Models.AddRange(
                        @(Get-TMModel -TMSession $TMSession -Page $i)
                    )
                }
            }
        }
        else {
            throw "Unable to get Models"
        }
    }

    process {

        # Filter the results by the Name(s) passed in
        if ($Name) {
            $Models = $Models | Where-Object modelName -EQ $Name
        }

        # Filter the results by the ID(s) passed in
        if ($Id) {
            $Models = $Models | Where-Object Id -In $Id
        }

        # Remove thew IDs if the ResetIDs switch was passed
        if ($ResetIDs) {
            for ($i = 0; $i -lt $Models.Count; $i++) {
                $Models[$i].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 AllowInsecureSSL
    Switch indicating that insecure SSL may be used
     
    .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
    New-TMSession -Credential $Credential -Server 'tmddev.transitionmanager.net' -AllowInsecureSSL $true -SessionName 'TMDDEV'
    New-TMSession -Credential $Credential -Server 'tmddev2.transitionmanager.net' -AllowInsecureSSL $true -SessionName 'TMDDEV2'
    $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)]
        [String]$TMSession = "Default",

        [Parameter(Mandatory = $false)]
        [String]$Server = $global:TMSessions[$TMSession].TMServer,

        [Parameter(Mandatory = $false)]
        $AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,

        [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 = $true, 
            ValueFromPipeline = $true,
            ParameterSetName = 'ByObject')]
        [PSCustomObject]$InputObject,

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

    begin {

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

        ## Get Session Configuration
        $TMSessionConfig = $global:TMSessions[$TMSession]
        if (-not $TMSessionConfig) {
            Write-Host 'TMSession: [' -NoNewline
            Write-Host $TMSession -ForegroundColor Cyan
            Write-Host '] was not Found. Please use the New-TMSession command.'
            Throw "TM Session Not Found. Use New-TMSession command before using features."
        }

        # Format the request parameters
        $Instance = $Server.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
    }

    process {
        $ModelsToAdd = [System.Collections.ArrayList]::new()
        switch ($PSCmdlet.ParameterSetName) {
            'ByProperty' {
                [void]$ModelsToAdd.Add(
                    [PSCustomObject]@{
                        modelName      = $Name
                        description    = $Description
                        assetType      = $AssetType
                        status         = $Status
                        manufacturer   = $Manufacturer
                        aliases        = $Aliases
                        powerNameplate = 0
                        powerDesign    = 0
                        powerUse       = 0
                        useImage       = 0
                    }
                )
            }

            'ByObject' {
                $InputObject | ForEach-Object {
                    [void]$ModelsToAdd.Add(
                        [PSCustomObject]@{
                            modelName      = $_.Name
                            description    = $_.Description
                            assetType      = $_.AssetType ?? 'Server'
                            status         = $_.Status ?? 'new'
                            manufacturer   = $_.Manufacturer
                            aliases        = $_.Aliases
                            powerNameplate = 0
                            powerDesign    = 0
                            powerUse       = 0
                            useImage       = 0
                        }
                    )
                }
            }
        }

        # Loop through the manufacturers and add them on the server
        foreach ($ModelToAdd in $ModelsToAdd) {
            $ModelCheck = Get-TMModel -TMSession $TMSession -Name $ModelToAdd.modelName
            if ($ModelCheck) {
                if ($Passthru) {
                    $ModelCheck
                }
                return
            }

            # Try to find the manufacturer by name
            $ManufacturerOnServer = Get-TMManufacturer -TMSession $TMSession -Name $ModelToAdd.manufacturer
            if (!$ManufacturerOnServer) {
                # Try to find the manufacturer by alias instead
                $ManufacturerOnServer = Get-TMManufacturer -TMSession $TMSession -Alias $ModelToAdd.manufacturer
                if (!$ManufacturerOnServer) {
                    Write-Error "Manufacturer '$Manufacturer' was not found on the server. Model could not be created."
                    return
                }
            }

            # Format the manufacturer property for the request
            $ModelToAdd.PSObject.Properties.Remove('Manufacturer')

            # Prepare the request properties
            $WebRequestSplat = @{
                Method               = 'POST'
                Uri                  = "https://$Instance/tdstm/ws/model"
                WebSession           = $TMSessionConfig.TMWebSession
                SkipCertificateCheck = $AllowInsecureSSL
            }

            # Format the Manufacturer for the request body
            $ModelToAdd | Add-Member -MemberType NoteProperty -Name 'manufacturer' -Value @{ id = $ManufacturerOnServer.Id }
                
            # Format the aliases for the request body
            $FormattedAliases = @()
            if ($TMSessionConfig.TMVersion -like '4.*') {
                for ($i = 0; $i -lt $ModelToAdd.aliases.Count; $i++) {
                    $FormattedAliases += @{
                        # id = $null
                        name  = $ModelToAdd.aliases[$i]
                    }
                }
                $ModelToAdd | Add-Member -MemberType NoteProperty -Name 'aka' -Value @{ added = $FormattedAliases; edited = @() }
                $ModelToAdd.PSObject.Properties.Remove('aliases')
            }
            else {
                for ($i = 0; $i -lt $ModelToAdd.aliases.Count; $i++) {
                    $FormattedAliases += @{
                        index = $i
                        name  = $ModelToAdd.aliases[$i]
                    }
                }
                $ModelToAdd.aliases = @{
                    add    = $FormattedAliases
                    delete = @()
                }
            }

            # Add the Manufacturer object as the body of the request
            $WebRequestSplat.Add('Body', ($ModelToAdd | ConvertTo-Json -Depth 10))

            # Set the request Content-Type header
            Set-TMHeaderContentType -ContentType 'JSON' -TMSession $TMSession
            
            # Set the request Accept header
            Set-TMHeaderAccept -Accept 'Any' -TMSession $TMSession

            # 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) {
                if ($Passthru) {
                    Get-TMModel -TMSession $TMSession -Name $ModelToAdd.modelName
                }
            }
            else {
                Write-Error "Manufacturer '$($ModelToAdd.Name)' could not be created"
            }
        }
    }
}


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 AllowInsecureSSL
    Switch indicating that insecure SSL may be used
     
    .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)]
        [String]$TMSession = "Default",

        [Parameter(Mandatory = $false)]
        [String]$Server = $global:TMSessions[$TMSession].TMServer,

        [Parameter(Mandatory = $false)]
        $AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL,

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

    begin {

        ## Get Session Configuration
        $TMSessionConfig = $global:TMSessions[$TMSession]
        if (-not $TMSessionConfig) {
            Write-Host 'TMSession: [' -NoNewline
            Write-Host $TMSession -ForegroundColor Cyan
            Write-Host '] was not Found. Please use the New-TMSession command.'
            Throw "TM Session Not Found. Use New-TMSession command before using features."
        }
        
        # Format the request parameters
        $Instance = $Server.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '')
        $Uri = "https://$Instance/tdstm/ws/model"

        Set-TMHeaderContentType -TMSession $TMSession -ContentType 'JSON'
        Set-TMHeaderAccept -TMSession $TMSession -Accept 'Any'
    }

    process {
        if (!$Id) {
            $Model = Get-TMModel -TMSession $TMSession -Name $Name
            if (!$Model) {
                # Model doesn't exist
                return
            }
            else {
                $Id = $Model.id
            }
        }

        $WebRequestSplat = @{
            Method               = 'DELETE'
            Uri                  = $Uri + "/" + $Id
            WebSession           = $TMSessionConfig.TMWebSession
            SkipCertificateCheck = $AllowInsecureSSL
        }

        # 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 -notin 200, 204) {
            Write-Error "Manufacturer '$($ManufacturerToAdd.Name)' could not be removed"
        }
    }
}