Common.psm1


<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 2c1a2f98-e781-403c-9c81-85b736767abc
 
.AUTHOR RaviCKolandaiswamy
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Basic Functions for calling various APIs
 
#>
 

#Get public and private function definition files.

#check PS version for this, PS 6 and above use -SkipCertificateCheck for Invoke-RestMethod
if ($PSVersionTable.PSVersion.Major -lt 6)
{
    #Ignore SSL errors
    If ($Null -eq ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
        Add-Type -Debug:$False @"
            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
}


#Enable TLS, TLS1.1, TLS1.2 in this session if they are available
IF([Net.SecurityProtocolType]::Tls) {[Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls}
IF([Net.SecurityProtocolType]::Tls11) {[Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11}
IF([Net.SecurityProtocolType]::Tls12) {[Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12}

$currentDirectory = Get-Location
Import-Module $currentDirectory\Helpers.psm1 -Force

function Invoke-RestApiRequest {
    [CmdletBinding(DefaultParameterSetName = 'EndpointName')]
    param (
         [Parameter(ParameterSetName = 'Endpoint')]
          $url,
         [Parameter(ParameterSetName = 'Endpoint')]
          $user,
         [Parameter(ParameterSetName = 'Endpoint')]
          $pass,

          [Parameter(ParameterSetName = 'EndpointName')]
          $endpointName,

          [Parameter(ParameterSetName = 'EndpointName')]
          [Parameter(ParameterSetName = 'Endpoint')]
          $relativeUrl,

          [Parameter(ParameterSetName = 'EndpointName')]
          [Parameter(ParameterSetName = 'Endpoint')]
          $jsonBody,

          [Parameter(ParameterSetName = 'EndpointName')]
          [Parameter(ParameterSetName = 'Endpoint')]
          $method = 'GET'
    )
    
    if ($PSCmdlet.ParameterSetName -eq 'EndpointName') 
    {
        $connection = Get-ApiConnection $endpointName
        $url = $connection.ApiEndpointUrl
        $user = $connection.ApiUser
        $pass = $connection.ApiKey
    } 

    $decodedCreds = Invoke-Decode $pass #[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass))
    $pair = "$($user):$($decodedCreds)"
    $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
    $basicAuthValue = "Basic $encodedCreds"
    $Headers = @{
        Authorization = $basicAuthValue
    }

    $params = @{
        Uri         = $url.TrimEnd('/') + '/' + $relativeUrl.TrimStart('/')
        Headers     = $Headers
        Method      = $method
        Body        = $jsonBody
        ContentType = 'application/json'
    }
    Write-Output "URL: $($params.Uri)"
    return Invoke-RestMethod @params -SkipCertificateCheck
}    

function Invoke-Decode {
    param($text)
    return [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($text))
}

function Add-ApiConnection {
    $name = Read-Host 'API Connection Name'
    $url = Read-Host 'API Endpoint Url'
    $user = Read-Host 'API User'
    $key = Read-Host "API Key" -AsSecureString
    $enc = $key | ConvertFrom-SecureString 
    $apiConnection = @{
        Name = $name
        ApiEndpointUrl = $url
        ApiUser = $user
        ApiKey = $enc
    }
    $json = ConvertTo-Json $apiConnection
    $json | Out-File "$name.api.dat"
}

function Get-ApiConnection {
    param (
        $name
        )
    
        if (!(Test-Path $name)) {
           $fileName = "$name.api.dat"
        } else {
            $fileName = $name
        }

        if (!(Test-Path $fileName)) {
            throw "Local Endpoint data file does not exist for the given connection name: $fileName"
        }
    $connectionData = Get-Content $fileName | ConvertFrom-Json
    $url = $connectionData.psobject.Properties['ApiEndpointUrl'].Value
    $user = $connectionData.psobject.Properties['ApiUser'].Value
    $enc = $connectionData.psobject.Properties['ApiKey'].Value
    $key = $enc | ConvertTo-SecureString

    $connection = @{
        Name = $connectionData.Name
        ApiEndpointUrl = $url
        ApiUser = $user
        ApiKey = $key
    }
    return $connection
}

function Add-HostConnection {
    $name = Read-Host 'Connection Name'
    $hostName = Read-Host 'Host Name (Machine Name or IP)'
    $creds = Get-Credential
    $user = $creds.UserName
    $encPassword = $creds.Password | ConvertFrom-SecureString

    try
    {
        $portInput = Read-Host 'WMI Port (Ex: 5985)'
        $port = [System.Convert]::ToInt($portInput)
    } catch
    {
        $port = 5985
    }
    
    try
    {
        $sslInput = Read-Host 'WMI Is Use SSL ? (yes / no)?'
        $isUseSsl = [System.Convert]::ToBoolean($sslInput)
    } catch
    {
        $isUseSsl = $False
    }

    $hostConnection = @{
        Name = $name
        HostName = $hostName
        User = $user
        Password = $encPassword
        Port = $port
        IsUseSsl = $isUseSsl
    }
    $json = ConvertTo-Json $hostConnection
    $json | Out-File "$name.host.dat"
}

function Get-HostConnection {
    param (
        $name
        )
    
        if (!(Test-Path $name)) {
           $fileName = "$name.host.dat"
        } else {
            $fileName = $name
        }

        if (!(Test-Path $fileName)) {
            throw "Local Host data file does not exist for the given connection name: $fileName"
        }
    $connectionData = Get-Content $fileName | ConvertFrom-Json
    $hostName = $connectionData.psobject.Properties['HostName'].Value
    $port= [int] ($connectionData.psobject.Properties['Port'].Value)
    $isUseSsl= [bool] ($connectionData.psobject.Properties['IsUseSsl'].Value)
    $user = $connectionData.psobject.Properties['User'].Value
    $enc = $connectionData.psobject.Properties['Password'].Value
    $key = $enc | ConvertTo-SecureString

    $connection = @{
        Name = $connectionData.Name
        HostName = $hostName
        User = $user
        Password = $key
        Port = $port
        IsUseSsl = $isUseSsl
    }
    return $connection
}

function Add-SqlDbConnection {
    $name = Read-Host 'Connection Name'
    $dbServerName = Read-Host 'DB Server Name'
    $user = Read-Host 'DB User'
    $pass = Read-Host "DB Password" -AsSecureString

    $dbName = Read-Host 'DB Name (optional)'

    $encPassword = $pass | ConvertFrom-SecureString


    $sqlDbConnection = @{
        Name = $name
        DbServerName = $dbServerName
        User = $user
        Password = $encPassword
        DbName = $dbName
    }
    $json = ConvertTo-Json $sqlDbConnection
    $json | Out-File "$name.sqldb.dat"
}

function Get-SqlDbConnection {
    param (
        $name
        )
    
        if (!(Test-Path $name)) {
           $fileName = "$name.sqldb.dat"
        } else {
            $fileName = $name
        }

        if (!(Test-Path $fileName)) {
            throw "Local SQL DB data file does not exist for the given connection name: $fileName"
        }
    $connectionData = Get-Content $fileName | ConvertFrom-Json
    $dbServerName = $connectionData.psobject.Properties['DbServerName'].Value
    $dbName = $connectionData.psobject.Properties['DbName'].Value
    $user = $connectionData.psobject.Properties['User'].Value
    $enc = $connectionData.psobject.Properties['Password'].Value
    $pass = $enc | ConvertTo-SecureString

    $connection = @{
       Name = $connectionData.Name
       DbServerName = $dbServerName
       User = $user
       Password = $pass
       DbName = $dbName
    }
    return $connection
}

function Invoke-SqlDbQuery {
    param($name, $query, $dbName)
    $sqlDbConn = Get-SqlDbConnection $name
    $decoded = Invoke-Decode $sqlDbConn.Password
    if($dbName -eq $null) {
        $dbName = $sqlDbConn.DbName
    }
    if($dbName -eq $null) {
            Invoke-Sqlcmd -ServerInstance $sqlDbConn.DbServerName -Username $sqlDbConn.User -Password "$decoded" -Query $query
    } else {
        Invoke-Sqlcmd -ServerInstance $sqlDbConn.DbServerName -Database $dbName -Username $sqlDbConn.User -Password "$decoded" -Query $query
    }
}

function Create-SqlTransactionLogShrinkJob {
    param($connectionName, $backupPath, $purgeBackupOlderThanDays)
    if($connectionName -eq $null) {
            $connectionName =  Read-Input -message "Enter SQL connection name"
    }
    if($backupPath -eq $null) {
            $backupPath =  Read-Input -message "Enter backup folder path"
    }
    if($purgeBackupOlderThanDays -eq $null) {
            $purgeBackupOlderThanDays =  Read-Input -message "Enter number of days to purge old backup"
    }
    $backupPath = $backupPath.Trim('\')+'\'
    $sqlDbConn = Get-SqlDbConnection $connectionName
    $decoded = Invoke-Decode $sqlDbConn.Password

    $hybrDb = "Hybr";
    $billingDb = "CloudAssert.Billing";
    $vconnectDb = "CloudAssert.Vconnect";
    $dacmDb = "CloudAssert.Dacm";

    if(!(Get-YesOrNoUserResponse -message "Is Hybr database name - $hybrDb ?")) {
        $hybrDb = Read-Input -message "Enter Hybr database name"
    }

    if(!(Get-YesOrNoUserResponse -message "Is Billing database name - $billingDb ?")) {
        $billingDb = Read-Input -message "Enter Billing database name"
    }

    if(!(Get-YesOrNoUserResponse -message "Is VConnect database name - $vconnectDb ?")) {
        $vconnectDb = Read-Input -message "Enter VConnect database name"
    }

    if(!(Get-YesOrNoUserResponse -message "Is Cost Management database name - $dacmDb ?")) {
        $dacmDb = Read-Input -message "Enter Cost Management database name"
    }

    $query = "IF EXISTS(SELECT 1 FROM msdb.dbo.sysjobs WHERE name='shrink_cloudassert_logs')
        BEGIN
            EXEC msdb.dbo.sp_delete_job @job_name = N'shrink_cloudassert_logs', @delete_unused_schedule = 1
        END
 
        IF NOT EXISTS(SELECT 1 FROM msdb.dbo.sysjobs WHERE name='shrink_cloudassert_logs')
        BEGIN
            EXEC msdb.dbo.sp_add_job
                @job_name = N'shrink_cloudassert_logs',
                @description = N'shrink_cloudassert_logs Description';
 
           EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_vconnect_db',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${vconnectDb}.bak''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$vconnectDb'') IS NOT NULL AND @result = 1)
                               Begin
                             BACKUP DATABASE [$vconnectDb] TO DISK = @path With Differential;
                             End
                            Else
                             Begin
                              BACKUP DATABASE [$vconnectDb] TO DISK = @path
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
           EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_vconnect_log',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${vconnectDb}.TRN''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$vconnectDb'') IS NOT NULL)
                             Begin
                              BACKUP LOG [$vconnectDb] TO DISK = @path;
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                    EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'shrink_vconnect_log',
                        @subsystem = N'TSQL',
                        @command = N'IF DB_ID(''$vconnectDb'') IS NOT NULL
                   Begin
                    USE [$vconnectDb]
                    DBCC SHRINKFILE (''${vconnectDb}_log'',0, TRUNCATEONLY)
                   END',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_billing_db',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${billingDb}.bak''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$billingDb'') IS NOT NULL AND @result = 1)
                               Begin
                             BACKUP DATABASE [$billingDb] TO DISK = @path With Differential;
                             End
                            Else
                             Begin
                              BACKUP DATABASE [$billingDb] TO DISK = @path
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_billing_log',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${billingDb}.TRN''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$billingDb'') IS NOT NULL)
                             Begin
                              BACKUP LOG [$billingDb] TO DISK = @path;
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                 EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'shrink_billing_log',
                        @subsystem = N'TSQL',
                        @command = N'IF DB_ID(''$billingDb'') IS NOT NULL
                   Begin
                    USE [$billingDb]
                    DBCC SHRINKFILE (''${billingDb}_log'',0, TRUNCATEONLY)
                   END',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_hybr_db',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${hybrDb}.bak''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$hybrDb'') IS NOT NULL AND @result = 1)
                               Begin
                             BACKUP DATABASE [$hybrDb] TO DISK = @path With Differential;
                             End
                            Else
                             Begin
                              BACKUP DATABASE [$hybrDb] TO DISK = @path
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_hybr_log',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${hybrDb}.TRN''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$hybrDb'') IS NOT NULL)
                             Begin
                              BACKUP LOG [$hybrDb] TO DISK = @path;
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                 EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'shrink_hybr_log',
                        @subsystem = N'TSQL',
                        @command = N'IF DB_ID(''$hybrDb'') IS NOT NULL
                   Begin
                    USE [$hybrDb]
                    DBCC SHRINKFILE (''${hybrDb}_log'',0, TRUNCATEONLY)
                   END',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_dacm_db',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${dacmDb}.bak''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$dacmDb'') IS NOT NULL AND @result = 1)
                               Begin
                             BACKUP DATABASE [$dacmDb] TO DISK = @path With Differential;
                             End
                            Else
                             Begin
                              BACKUP DATABASE [$dacmDb] TO DISK = @path
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
          EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'backup_dacm_log',
                        @subsystem = N'TSQL',
                        @command = N'
                            DECLARE @result INT
                            DECLARE @path nvarchar(500) = ''${backupPath}\${dacmDb}.TRN''
                            EXEC master.dbo.xp_fileexist @path ,@result OUTPUT
                            IF (DB_ID(''$dacmDb'') IS NOT NULL)
                             Begin
                              BACKUP LOG [$dacmDb] TO DISK = @path;
                             End',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                 EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'shrink_dacm_log',
                        @subsystem = N'TSQL',
                        @command = N'IF DB_ID(''$dacmDb'') IS NOT NULL
                             Begin
                              USE [$dacmDb]
                              DBCC SHRINKFILE (''${dacmDb}_log'',0, TRUNCATEONLY)
                             END',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                 EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'purge_db_backup',
                        @subsystem = N'TSQL',
                        @command = N'DECLARE @path nvarchar(500) = ''$backupPath''
                            DECLARE @DeleteDateTime DATETIME
                            SET @DeleteDateTime = DateAdd(DAY, -$purgeBackupOlderThanDays, GetDate())
                            EXECUTE master.dbo.xp_delete_file 0,
                              @path,
                              ''bak'',
                              @DeleteDateTime,
                              0',
                        @on_success_action = 3,
                        @database_name = 'master';
 
                 EXEC msdb.dbo.sp_add_jobstep
                        @job_name = N'shrink_cloudassert_logs',
                        @step_name = N'purge_log_backup',
                        @subsystem = N'TSQL',
                        @command = N'DECLARE @path nvarchar(500) = ''$backupPath''
                            DECLARE @DeleteDateTime DATETIME
                            SET @DeleteDateTime = DateAdd(DAY, -$purgeBackupOlderThanDays, GetDate())
                            EXECUTE master.dbo.xp_delete_file 0,
                              @path,
                              ''trn'',
                              @DeleteDateTime,
                              0',
                        @on_success_action = 1,
                        @database_name = 'master';
     
                    EXEC msdb.dbo.sp_add_jobschedule
                        @job_name = N'shrink_cloudassert_logs',
                        @name = N'shrink_cloudassert_logs_SCHEDULE',
                  @freq_type=4,
                  @freq_interval=1,
                  @freq_subday_type=1,
                  @freq_subday_interval=0,
                  @active_start_time=0,
                  @active_end_time=235959;
     
                    EXEC msdb.dbo.sp_add_jobserver @job_name = N'shrink_cloudassert_logs'
                END"
;

    $dbName = 'master'
    Invoke-Sqlcmd -ServerInstance $sqlDbConn.DbServerName -Database $dbName -Username $sqlDbConn.User -Password "$decoded" -Query $query
}

function Invoke-SqlDbQueryFromFile {
    param($name, $queryFile, $dbName)
    $sqlDbConn = Get-SqlDbConnection $name
    $decoded = Invoke-Decode $sqlDbConn.Password
    if($dbName -eq $null) {
        $dbName = $sqlDbConn.DbName
    }

    if($dbName -eq $null) {
        Invoke-Sqlcmd -ServerInstance $sqlDbConn.DbServerName -Username $sqlDbConn.User -Password "$decoded" -InputFile $queryFile
    } else {
        Invoke-Sqlcmd -ServerInstance $sqlDbConn.DbServerName -Database $dbName -Username $sqlDbConn.User -Password "$decoded" -InputFile $queryFile
    }
}

function Invoke-EnterPSSession {
    param($name)
    $hostConnection = Get-HostConnection $name
    $hostCreds=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $hostConnection.User, $hostConnection.Password
    if($hostConnection.IsUseSsl) {
        Enter-PSSession -ComputerName $hostConnection.HostName -Port $hostConnection.Port -UseSSL -Credential $hostCreds
    } else {
        Enter-PSSession -ComputerName $hostConnection.HostName -Port $hostConnection.Port -Credential $hostCreds
    }
}

function Invoke-ExitPSSession {
    Exit-PSSession
}

function Invoke-HostCommand {
    param($name, $cmd)
    $hostConnection = Get-HostConnection $name
    $hostCreds=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $hostConnection.User, $hostConnection.Password
    $sc=[Scriptblock]::Create($cmd)
    if($hostConnection.IsUseSsl) {
        Invoke-Command -ComputerName $hostConnection.HostName -Port $hostConnection.Port -UseSSL -Credential $hostCreds -ScriptBlock $sc
    } else {
        Invoke-Command -ComputerName $hostConnection.HostName -Port $hostConnection.Port -Credential $hostCreds -ScriptBlock $sc
    }
}

function Get-HostEventLog {
    param($name, $logName = "Application", [int] $newest = 10, $entryType = "Error", [datetime] $after, [datetime] $before, $source, $message, [int] $index)
    $hostConnection = Get-HostConnection $name
    $hostCreds=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $hostConnection.User, $hostConnection.Password
    $cmd = "Get-EventLog -LogName $logName -Newest $newest -EntryType $entryType"
    if($after -ne $null) {
        $cmd = $cmd + " -After $after"
    }
    if($before -ne $null) {
        $cmd = $cmd + " -Before $before"
    }
    if($source -ne $null) {
        $cmd = $cmd + " -Source $source"
    }
    if($message -ne $null) {
        $cmd = $cmd + " -Message $message"
    }
    if($index -ne $null -and $index -gt 0) {
        $cmd = $cmd + " -Index $index"
    }
    Write-Host "Executing: $cmd"
    $sc=[Scriptblock]::Create($cmd)
    if($hostConnection.IsUseSsl) {
        Invoke-Command -ComputerName $hostConnection.HostName -Port $hostConnection.Port -UseSSL -Credential $hostCreds -ScriptBlock $sc
    } else {
        Invoke-Command -ComputerName $hostConnection.HostName -Port $hostConnection.Port -Credential $hostCreds -ScriptBlock $sc
    }
}

function Invoke-InstallOrUpdateModule {
    param($name) 
    if ((Get-InstalledModule -Name $name -ErrorAction SilentlyContinue) -eq $null) {
        #-MinimumVersion 5.0 # Optionally specify minimum version to have
        Install-Module -Name CloudAssert.Common
    } else {
        Update-Module -Name CloudAssert.Common -Force
    }
}
# SIG # Begin signature block
# MIIOCwYJKoZIhvcNAQcCoIIN/DCCDfgCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUIAWhEiBQ4o3sK2B00q2f5qPr
# iI2gggtCMIIFWjCCBEKgAwIBAgIQDO0lEK+T1uQiVg3lGt++5DANBgkqhkiG9w0B
# AQsFADB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy
# MRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEj
# MCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcxMDEzMDAw
# MDAwWhcNMjExMDEzMjM1OTU5WjCBojELMAkGA1UEBhMCVVMxDjAMBgNVBBEMBTk4
# MDUyMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHUmVkbW9uZDESMBAGA1UECQwJU3Vp
# dGUgMjAwMRowGAYDVQQJDBE4MjAxIDE2NHRoIEF2ZSBORTEZMBcGA1UECgwQQ0xP
# VUQgQVNTRVJUIExMQzEZMBcGA1UEAwwQQ0xPVUQgQVNTRVJUIExMQzCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3TRJvdYkx0p/ETrd2ZDE42azIJ4qsR
# SrFIrV2Ac0rSRry9gouPMNgPGCdvcLkDj247i5LuJK1G/kXK27cCnefXgiiy7IZz
# XCzYIr+rhQ2IpZFDQHRDu8gAHthtCrW/0DiDZZLOqAfQipoaJiZLktfw1ExMjoZO
# lzux00hH/8BasYAaV2wWR3MPEqt8ehtOInop7vUKXHBeHqlS0vGZpmZmSooqnOqo
# e/+Ik7rBODjfWbS/ukEEz3uT5tQAfbaCqe0AI7jy+Qguag20pUSJZI15tzoUGDzu
# QF0IIhDZRUhrs9MVGlBCHPcQg5nAfll1xeyAXDGvOTUVNbe7p20H0tECAwEAAaOC
# Aa4wggGqMB8GA1UdIwQYMBaAFCmRYP+KTfrr+aZquM/55ku9Sc4SMB0GA1UdDgQW
# BBQDFhoCqrRSPk96X5/uWmKZzc0GfjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/
# BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzARBglghkgBhvhCAQEEBAMCBBAwRgYD
# VR0gBD8wPTA7BgwrBgEEAbIxAQIBAwIwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9z
# ZWN1cmUuY29tb2RvLm5ldC9DUFMwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2Ny
# bC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ29kZVNpZ25pbmdDQS5jcmwwdAYIKwYB
# BQUHAQEEaDBmMD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9D
# T01PRE9SU0FDb2RlU2lnbmluZ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuY29tb2RvY2EuY29tMB8GA1UdEQQYMBaBFGluZm9AY2xvdWRhc3NlcnQuY29t
# MA0GCSqGSIb3DQEBCwUAA4IBAQCkmEma81+PRWa1v+En+dBfFF0TlfrnwXHQeU6a
# qGRxFWJO2ORTlj8TyTJZNQp7/5senwqGOkhZyBiUbDDz+mgpS3dD8+OTB+LPeTC0
# qxA2FwZan2yLiMyJ+tzWoMZThxWGdKr//9SwglLk6sjgAYeQ8zw0eLC3R5GkGZKE
# ZJdlZkeZj3OcjDZ+tsB0YeyrvzQApaAHxROJjPFmFNJulHkGTOIftgAYTZOLCuBw
# UjveYnsgiOjey0ljXb94Xfiy5V7F+Tg3hKmu+ykDthEr04omYgun4JRB++4ZmoYy
# Q9oqjKQDJM7/dnVbMh0W0D/8Ns0OepvGilKNbYYbVsLKi451MIIF4DCCA8igAwIB
# AgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UEBhMC
# R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9y
# ZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBS
# U0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5MDAwMDAwWhcNMjgw
# NTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5j
# aGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGlt
# aXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR3elnMRHrzB79MR2z
# uWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvthe4YJs+P9omidHCyd
# v3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3e9V5kAoUGFEs5v7B
# EvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQc5hc9IVKaw+A3V7W
# vf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPiXzjbxghdR7ODQfAu
# ADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmLAgaff9ULAgMBAAGj
# ggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4E
# FgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB
# /wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYDVR0gBAowCDAGBgRV
# HSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NP
# TU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUw
# YzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNB
# QWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2Nh
# LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4MbU2x8U6ST6/COCwE
# zMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQciGlEcOtTh6Qm/5iR0
# rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHfWGshqknUfDdOvf+2
# dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HITfK7ZU2o94VFB696
# aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46BLqioXwfy2M6FafU
# FRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gbqjSm/Iz13X9ljIwx
# VzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm5LLY5TjCqO3GgZw1
# a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQFhv/K53b0CDKieoo
# fjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5sL6iPDAZQ+4wns3bJ
# 9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55ZmjoIs2475iFTZYR
# PAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6Q++6Z2H/fUnguzB9
# XIDj5hY5S6cxggIzMIICLwIBATCBkTB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS
# R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
# T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p
# bmcgQ0ECEAztJRCvk9bkIlYN5RrfvuQwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcC
# AQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYB
# BAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFLV/v700PXn7
# h3aKTjWP4ilJhlNXMA0GCSqGSIb3DQEBAQUABIIBAD+LDQjq6YYz6158CQRtX0Vb
# IunNUUexnWuz1loqtqLo5xsusKt4xGy1QrD2F0QgoGDSlBtOL46hF02I78ep1oGr
# oSldguLV0H/J3ZgHbhJpTbYkRbU3dDN4HjTN9Z3rYiJJzlgyPD+iryt2MS4kPYZw
# Q1LgTASqc6vPsrVueantxxR/aFoYmDMFqnXwftHSJw0KZanva2FS9IrSsUi0dcT1
# kl5+ARSy3JpjqZjmPUVmYq+9OGv5jLMoOctEEwmjFKMSDXyoYQrfGrxgLlEQTPPF
# Mr7jTSKJ9JNtCSkpXzGgfOM0Y4zA9jSqwgChMFp2Z17SwA7ZO4DYM1xf8RRyfp0=
# SIG # End signature block