Private/Connection.ps1

function Get-DattoApiConnectionView {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Collections.IDictionary]$ConnectionState
    )

    $publicKey = [string]$ConnectionState.Credential.UserName
    if ($publicKey.Length -le 4) {
        $publicKeyHint = '****'
    }
    else {
        $publicKeyHint = '***{0}' -f $publicKey.Substring($publicKey.Length - 4)
    }

    $view = [pscustomobject][ordered]@{
        Id                  = [guid]$ConnectionState.Id
        Name                = [string]$ConnectionState.Name
        BaseUri             = [uri]$ConnectionState.BaseUri
        ApiVersion          = 'v1'
        PublicKeyHint       = $publicKeyHint
        IsDefault           = ([string]$script:DattoApiState.DefaultConnectionId -eq [string]$ConnectionState.Id)
        CreatedAtUtc        = $ConnectionState.CreatedAtUtc
        LastUsedAtUtc       = $ConnectionState.LastUsedAtUtc
        TimeoutSeconds      = [int]$ConnectionState.TimeoutSeconds
        MaxRetryCount       = [int]$ConnectionState.MaxRetryCount
        MaxRetryDelaySeconds = [int]$ConnectionState.MaxRetryDelaySeconds
    }
    $view.PSObject.TypeNames.Insert(0, 'DattoBackupApi.Connection')
    return $view
}

function Find-DattoApiConnectionStateByName {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Name
    )

    foreach ($state in $script:DattoApiState.Connections.Values) {
        if ([string]$state.Name -ieq $Name) {
            return $state
        }
    }
    return $null
}

function Resolve-DattoApiConnectionState {
    [CmdletBinding()]
    param(
        [Parameter()]
        [AllowNull()]
        [object]$Connection
    )

    if ($null -eq $Connection) {
        if ([string]::IsNullOrWhiteSpace([string]$script:DattoApiState.DefaultConnectionId)) {
            throw [System.InvalidOperationException]::new('No default Datto API connection exists. Run Connect-DattoApi first or supply -Connection.')
        }
        $id = [string]$script:DattoApiState.DefaultConnectionId
    }
    elseif ($Connection -is [string]) {
        $text = [string]$Connection
        $guidValue = [guid]::Empty
        if ([guid]::TryParse($text, [ref]$guidValue)) {
            $id = [string]$guidValue
        }
        else {
            $stateByName = Find-DattoApiConnectionStateByName -Name $text
            if ($null -eq $stateByName) {
                throw [System.Management.Automation.ItemNotFoundException]::new("A Datto API connection named '$text' was not found.")
            }
            return $stateByName
        }
    }
    elseif ($Connection.PSObject.Properties.Name -contains 'Id') {
        $id = [string]$Connection.Id
    }
    else {
        throw [System.ArgumentException]::new('The -Connection value must be a connection object, connection name, connection ID, or null for the default connection.')
    }

    if (-not $script:DattoApiState.Connections.ContainsKey($id)) {
        throw [System.Management.Automation.ItemNotFoundException]::new("Datto API connection '$id' was not found or has been disconnected.")
    }
    return $script:DattoApiState.Connections[$id]
}

function Remove-DattoApiConnectionInternal {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Collections.IDictionary]$ConnectionState
    )

    if ($null -ne $ConnectionState.Client) {
        try { $ConnectionState.Client.Dispose() } catch { Write-Debug ('HttpClient disposal failed: {0}' -f $_.Exception.Message) }
        $ConnectionState.Client = $null
    }
    if ($ConnectionState.Contains('Handler') -and $null -ne $ConnectionState.Handler) {
        try { $ConnectionState.Handler.Dispose() } catch { Write-Debug ('HttpClientHandler disposal failed: {0}' -f $_.Exception.Message) }
        $ConnectionState.Handler = $null
    }
    $ConnectionState.Credential = $null
}

function ConvertFrom-DattoSecureString {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [securestring]$SecureString
    )

    $pointer = [IntPtr]::Zero
    try {
        $pointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
        return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointer)
    }
    finally {
        if ($pointer -ne [IntPtr]::Zero) {
            [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pointer)
        }
    }
}

function Get-DattoApiAuthorizationParameter {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [pscredential]$Credential
    )

    $plainSecret = $null
    $combined = $null
    $bytes = $null
    try {
        $plainSecret = ConvertFrom-DattoSecureString -SecureString $Credential.Password
        $combined = '{0}:{1}' -f $Credential.UserName, $plainSecret
        $bytes = [Text.Encoding]::UTF8.GetBytes($combined)
        return [Convert]::ToBase64String($bytes)
    }
    finally {
        if ($null -ne $bytes) {
            [Array]::Clear($bytes, 0, $bytes.Length)
        }
        $plainSecret = $null
        $combined = $null
    }
}