ApiClient.psm1


Class ApiClient {
    # properties
    [string]$CustomerId
    [string]$SecureClientId
    [string]$SecureSecret
    [string]$Deployment
    [string]$DeploymentName
    [string]$UserAgent
    [string]$baseUrl


    # Default constructor
    ApiClient([hashtable]$values) {
        $this.CopyValues(@{
            CustomerId = @{
                required = $True
            }
            SecureClientId = @{
                required = $True
            }
            SecureSecret = @{
                required = $True
            }
            Deployment = @{
                default = $null
                required = $False
            }            
            DeploymentName = @{
                default = $null
                required = $False
            }
            UserAgent = @{
                required = $True
            }
        }, $values)
    
        if ($this.Deployment) {
            $this.baseUrl = "https://$($this.Deployment)/"
        } else {
            $this.baseUrl = "https://api.layering.cloud.com/"
        }

        Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
    ServicePoint srvPoint, X509Certificate certificate,
    WebRequest request, int certificateProblem) {
        return true;
    }
}
"@


        [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
    }

    [void] CopyValue([hashtable]$valueMap, [hashtable]$values, [string]$fromKey, [string]$toKey) {
        if ($values.ContainsKey($fromKey)) {
            # values contains the key, so use value from there
            $this.$toKey = $values.$fromKey
        } elseif ($valueMap[$fromKey]['required']) {
            throw "Required value $fromKey not supplied"
        } else {
            # values does not contain the key, so use the default
            $this.$toKey = $valueMap[$fromKey]['default']
        }
    }

    [void] CopyValues([hashtable]$valueMap, [hashtable]$values) {
        foreach ($key in $valueMap.Keys) {
            try {
                $this.CopyValue($valueMap, $values, $key, $key)
            }
            catch {
                throw "Failed to copy $key from $(Convert-HashToString $values) when creating Api class: $_"
            }
        }
    }

    [void] CopyValuesToPrefix([hashtable]$valueMap, [hashtable]$values, [string]$smb, [string]$prefix) {
        if (-Not $values.ContainsKey($smb)) {
            throw "Failed to copy smb share info section $smb when creating Api class: $_"
        }
        foreach ($key in $valueMap.Keys) {
            $prefixedKey = "$prefix$key"
            try {
                $this.CopyValue($valueMap, $values.$smb, $key, $prefixedKey)
            }
            catch {
                throw "Failed to copy $key from $(Convert-HashToString $values.$smb) when creating Api class: $_"
            }
        }
    }

    [string]BuildUrl([string]$leaf, [bool]$async=$True) {
        if ($async) {
            $async_str = "true"
        } else {
            $async_str = "false"
        }
        [string]$url = $this.baseUrl + $leaf + "?async=$async_str"

        return $url
    }

    # GET Bearer Token
    [string]GetBearerToken () {
        if ([string]::IsNullOrEmpty($GLOBAL:XDAuthToken)) {
            try {
                Set-XDCredentials -CustomerId $this.CustomerId -APIKey $this.SecureClientId -SecretKey $this.SecureSecret -ProfileType CloudAPI
                $parameters = @{
                    CustomerId = $this.CustomerId
                    Verbose = $Global:LogVerbose
                }
                if ($this.DeploymentName) {
                    $parameters[$this.DeploymentName] = $True
                }
                Get-XDAuthentication @parameters
            }
            catch {
                throw "Failed to get bearer token: $_"
            }
        }
        return $GLOBAL:XDAuthToken
    }
    
    [psobject]GetAuthHeaders() {
        $token = $this.GetBearerToken()

        $headers = @{
            'Authorization'     = $token
            'Citrix-CustomerId' = $this.CustomerId
            'Accept'            = 'application/json;version=preview'
            'Content-Type'      = 'application/json;charset=utf-8'
        }

        return $headers
    }

    [psobject] RestMethod([string]$method, [string]$url, [psobject]$json) {
        $parameters = @{
            Headers = $this.GetAuthHeaders()
            Method = $method
            UserAgent = $this.UserAgent
            Verbose = $Global:LogVerbose
        }
        if ($json) {
            $parameters['Body'] = $json
        }
        try {
            return Invoke-RestMethod $url @parameters
        }
        catch {
            throw "$method REST method failed: $_"
        }
    }

    [psobject] Get([string]$url) {
        return $this.RestMethod("Get", $url, $null)
    }

    [psobject] Post([string]$url, [psobject]$json) {
        return $this.RestMethod("Post", $url, $json)
    }

    [psobject] Put([string]$url, [psobject]$json) {
        return $this.RestMethod("Put", $url, $json)
    }

    [psobject] Delete([string]$url) {
        return $this.RestMethod("Delete", $url, $null)
    }

    [hashtable] AddDefaultTags([hashtable]$tags) {
        $tags['ctx-tool'] = "ctx-al-ps-api"
        $tags['ctx-user'] = ($env:UserName).ToLower()
        return $tags
    }
}

$verbose = $False

$files = @("Smb.ps1", "ExportApi.ps1", "vSphereExportApi.ps1", "AzureExportApi.ps1", "PrepareApi.ps1", "AzurePrepareApi.ps1", "GcpPrepareApi.ps1", "JobStatusApi.ps1", "CancelApi.ps1", "CredentialsApi.ps1", "Azure.ps1",
           "UploadClient.ps1", "AzureUploadClient.ps1", "GcpUploadClient.ps1", "CreateVmClient.ps1", "Configuration.ps1", "Log.ps1", "GcpCreateVmClient.ps1")

foreach ($file in $files) {
    $fullPath = "$PSScriptRoot\$file"
    try {
        if ($verbose) {
            Write-Host "CTX.AL.Api importing $fullPath"
        }
        . $fullPath
    }
    catch {
        Write-Error -Message "Failed to import $($fullPath): $_"
    }                    
}