common_utils.ps1

$ZVM_VM_NAME = "ZVML"

function Start-ZVM {

    process {

        try {
            Write-Host "Starting $($MyInvocation.MyCommand)..."

            $ZVM = Get-VM -Name $ZVM_VM_NAME
            if ($null -eq $ZVM) {
                Write-Error "$ZVM_VM_NAME does not exist" -ErrorAction Stop
            }
            else {
                if ($ZVM.PowerState -eq 'PoweredOff') {
                    Write-Host "$ZVM_VM_NAME is powered off, going to power it on"
                    Start-VM $ZVM -ErrorAction Stop | Out-Null
                }
                else {
                    Write-Host "$ZVM_VM_NAME is up and running"
                }
            }
        }
        catch {
            Write-Error "Failed to start $ZVM_VM_NAME, exception = $_" -ErrorAction Stop
        }
    }
}

function Stop-ZVM {

    process {

        try {
            Write-Host "Starting $($MyInvocation.MyCommand)..."

            $ZVM = Get-VM -Name $ZVM_VM_NAME
            if ($null -eq $ZVM) {
                Write-Error "$ZVM_VM_NAME does not exist" -ErrorAction Stop
            }
            else {
                if ($ZVM.PowerState -eq 'PoweredOn') {
                    Write-Host "$ZVM_VM_NAME is powered on, going to power it off"
                    Stop-VM -VM $ZVM -Confirm:$False -ErrorAction Stop | Out-Null
                }
                else {
                    Write-Host "$ZVM_VM_NAME is off"
                }
            }
        }
        catch {
            Write-Error "Failed to stop $ZVM_VM_NAME, exception = $_" -ErrorAction Stop
        }
    }
}

function New-RandomPassword {
    process {
        #Generate a password with at least 2 uppercase, 4 lowercase, 4 digits & 2 special character (!@#$%^*())

        Write-Host "Starting $($MyInvocation.MyCommand)..."

        $upperChars = (65..90)
        $lowerChars    = (97..122)
        $numerics = (48..57)
        $specialChars = @(33, 35, 36, 37, 40, 41, 42, 45, 64, 94)

        $seedArray = ($upperChars | Get-SecureRandom -Count 2)
        $seedArray += ($lowerChars | Get-SecureRandom -Count 4)
        $seedArray += ($numerics | Get-SecureRandom -Count 4)
        $seedArray += ($specialChars | Get-SecureRandom -Count 2)

        Foreach ($a in $seedArray) {
            $passwordAscii += , [char][byte]$a
        }

        $password = $passwordAscii -join ""

        return $password
    }
}

function New-ZertoFolderOnHost {
    param(
        [Parameter(Mandatory = $true,
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName
    )

    process {
        Write-Host "Starting $($MyInvocation.MyCommand)..."

        $Command = "mkdir -p $ZERTO_FOLDER_ON_HOST"
        $Res = Invoke-SSHCommands -HostName $HostName -Commands $Command
        $ExitStatus = $Res["0_exitStatus"];

        if ( $ExitStatus -ne '0' ) {
            throw "failed to create $ZERTO_FOLDER_ON_HOST on host $HostName. Exit status for ""$Command"" is $ExitStatus"
        }
        else {
            Write-Host "Zerto folder ($ZERTO_FOLDER_ON_HOST) was created on $HostName."
        }
    }
}

function Invoke-Retry {
    param (
        [Parameter(Mandatory = $true)]
        [ScriptBlock]$Action,

        [Parameter(Mandatory = $true)]
        [string]$ActionName,

        [Parameter(Mandatory = $true)]
        [int]$RetryCount,

        [Parameter(Mandatory = $true)]
        [int]$RetryIntervalSeconds
    )

    for ($i = 1; $i -le $RetryCount; $i++) {
        try {
            Write-Output "Attempt $i of $RetryCount executing $ActionName."
            & $Action
            Write-Output "$ActionName succeeded."
            return
        }
        catch {
            Write-Output "Attempt $i of $RetryCount on $ActionName wasn't successful."
 
            if ($i -ne $RetryCount) {
                Write-Output "Waiting for $RetryIntervalSeconds seconds before retrying $ActionName..."
                Start-Sleep -Seconds $RetryIntervalSeconds
            }
            else {
                Write-Output "Error: All attempts to execute $ActionName failed. Exiting."
                throw
            }
        }
    }
}

function Invoke-ZVMScriptWithTimeout {
    param (
        [Parameter(Mandatory = $true)]
        [string]$ScriptText,

        [Parameter(Mandatory = $true)]
        [string]$ActionName,

        [int]$TimeoutMinutes = 30
    )
    $ZVM = Get-VM -Name $ZVM_VM_NAME

    Write-Output "Starting $ActionName execution."
    # Start the script asynchronously
    $task = Invoke-VMScript -VM $ZVM -ScriptText $ScriptText -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -RunAsync

    # Calculate the timeout time
    $timeoutTime = (Get-Date).AddMinutes($TimeoutMinutes)

    while ((Get-Date) -lt $timeoutTime) {
        # Check the task status
        if ($task.State -eq 'Success') {
            # The 'Success' state indicates that the remote script was executed, but does not reflect the script's success or failure.
            Write-Output "$ActionName execution done."
            return $task.Result
        }
        elseif ($task.State -eq 'Error') {
            throw "$ActionName execution failed with error: $($task.ErrorMessage)"
        }

        # Wait for a short period before checking again
        Start-Sleep -Seconds 30
    }

    # If the loop exits, it means the timeout was reached
    throw "$ActionName did not complete within the allotted time of $TimeoutMinutes minutes."
}