zvmRemoteScripts_utils.ps1
$ZAPPLIANCE_USER = "zadmin" function Invoke-ZVMScriptWithTimeout { <# .SYNOPSIS Executes the shell script on the ZVM VM with a timeout .OUTPUTS [VMScriptResultImpl] Result .ExitCode contains script success/failure Result .ScriptOutput must be used with StartsWith() or Contains() because output ends with extra \n newline character Result .TrimmedOutput contains clean script output #> param ( [ValidateNotNullOrEmpty()] [string]$ScriptText, [ValidateNotNullOrEmpty()] [string]$ActionName, [ValidateRange(1, 60)] [int]$TimeoutMinutes = 30 ) Write-Host "Starting $($MyInvocation.MyCommand)..." $ZVM = Get-VM -Name $ZVM_VM_NAME Write-Host "Invoking '$ActionName' with $TimeoutMinutes minutes timeout." # 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 state periodically switch ($task.State) { 'Success' { # The 'Success' state indicates that the remote script was executed, but does not reflect the script success or failure. Write-Host "$ActionName execution done." # task.Result is VMScriptResultImpl type, and we add a new dynamic property to it. $task.Result | Add-Member -MemberType NoteProperty -Name "TrimmedOutput" -Value $task.Result.ScriptOutput.TrimEnd("`n") return $task.Result } 'Error' { throw "$ActionName execution error: $($task.TerminatingError.Message)" # In case of wrong VM credentials, the error message would be "Failed to authenticate with the guest operating system using the supplied credentials." } default { # If the task is 'Running' or in any other state, wait briefly before rechecking. Start-Sleep -Seconds 10 } } } # If the loop exits, it means the timeout was reached # Note that the task is not aborted, so the script could eventually succeed throw "Timeout, '$ActionName' did not complete within the allotted time of $TimeoutMinutes minutes." } function Assert-ZertoInitialized { Write-Host "Starting $($MyInvocation.MyCommand)..." $startTime = Get-Date $action = { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { Write-Error "$ZVM_VM_NAME doesn't exists" -ErrorAction Stop } $res = Invoke-VMScript -VM $ZVM -ScriptText "whoami" -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction SilentlyContinue if ($null -eq $res -or $res.ScriptOutput.Trim() -ne $ZAPPLIANCE_USER) { throw "ZVMA failed to initialize, authentication failed." } #TODO: This single check is enough to determine if ZVM is initialized, split between null, when authentication fails and when ZVM is not initialized $zvmInitStatusFile = "/opt/zerto/zvr/initialization-files/zvm_initialized" $res = Invoke-VMScript -VM $ZVM -ScriptText "[ -e $zvmInitStatusFile ] && echo true || echo false" -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction SilentlyContinue if ($null -eq $res -or $res.ScriptOutput.Trim() -ne 'true') { throw "ZVMA failed to initialize, initialization file not found." } } Invoke-Retry -Action $action -ActionName "TestZertoInitialized" -RetryCount 15 -RetryIntervalSeconds 60 Write-Host "Zerto initialization took: $((Get-Date).Subtract($startTime).TotalSeconds.ToString("F0")) seconds." } function Set-ZertoVmPassword { <# .SYNOPSIS Sets the ZVM VM console password and updates the PersistentSecrets #> param( [ValidateNotNullOrEmpty()] [SecureString]$NewPassword ) Write-Host "Starting $($MyInvocation.MyCommand)..." $newPasswordText = ConvertFrom-SecureString -SecureString $NewPassword -AsPlainText $action = { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { Write-Error "$ZVM_VM_NAME doesn't exists" -ErrorAction Stop } # We need to write result to variable to avoid module logging issues # We need SilentlyContinue because when in-guest script changes the password for that very same account during execution, the authenticated session may no longer be valid by the time the cmdlet tries to finalize or return results. This leads to the "Failed to authenticate..." error even though the password is successfully changed. $passChange = Invoke-VMScript -VM $ZVM -ScriptText "echo '$($ZAPPLIANCE_USER):$newPasswordText' | sudo chpasswd" -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction SilentlyContinue $res = Invoke-VMScript -VM $ZVM -ScriptText "whoami" -GuestUser $ZAPPLIANCE_USER -GuestPassword $newPasswordText -ErrorAction SilentlyContinue if ($null -eq $res -or $res.ScriptOutput.Trim() -ne $ZAPPLIANCE_USER) { throw "Failed to change ZVML VM password" } $PersistentSecrets.ZappliancePassword = $newPasswordText } Invoke-Retry -Action $action -ActionName "ChangeZvmVmPassword" -RetryCount 10 -RetryIntervalSeconds 60 } function Set-ZertoConfiguration ([string]$DNS, [bool]$IsVaio) { Write-Host "Starting $($MyInvocation.MyCommand)..." Set-DnsConfiguration -DNS $DNS Stop-ZVM Start-ZVM Write-Host "Configuring Zerto, this might take a while..." $startTime = Get-Date #TODO: we need to rename key that holds VC user password. It sound confusing $scriptLocation = "/opt/zerto/zlinux/avs/configure_zerto.py" $commandToExecute = "sudo python3 $scriptLocation --vcPassword '$($PersistentSecrets.ZertoPassword)' --avsClientSecret '$($PersistentSecrets.AvsClientSecret)'$($IsVaio ? ' --isVaio' : '')" $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Configure ZVM" Write-Host "Zerto configuration took: $((Get-Date).Subtract($startTime).TotalSeconds.ToString("F0")) seconds." if ($result.ScriptOutput.Contains("Success")) { Write-Host "Zerto configured successfully." } elseif ($result.ScriptOutput.Contains("Warning:")) { $message = $result.ScriptOutput Write-Host $message Write-Warning $message } elseif ($result.ScriptOutput.Contains("Error:")) { $cleanErrMsg = $result.ScriptOutput -replace "Error: ", "" throw $cleanErrMsg } else { throw "An unexpected error occurred while configuring Zerto. Please reinstall Zerto." } } function Update-ZertoConfiguration { param( [ValidateNotNullOrEmpty()][string] $AzureTenantId, [ValidateNotNullOrEmpty()][string] $AzureClientID, [ValidateNotNullOrEmpty()][string] $AvsSubscriptionId, [ValidateNotNullOrEmpty()][string] $AvsResourceGroup, [ValidateNotNullOrEmpty()][string] $AvsCloudName ) Write-Host "Starting $($MyInvocation.MyCommand)..." Write-Host "Reconfiguring Zerto, this might take a while..." $scriptLocation = "/opt/zerto/zlinux/avs/reconfigure_zvm.py" $ZertoUserWithDomain = "$ZERTO_USER_NAME@$DOMAIN" $commandToExecute = "sudo python3 $scriptLocation " + "--avsClientSecret '$($PersistentSecrets.AvsClientSecret)' " + "--azureTenantId '$AzureTenantId' " + "--azureClientID '$AzureClientID' " + "--avsSubscriptionId '$AvsSubscriptionId' " + "--avsResourceGroup '$AvsResourceGroup' " + "--avsCloudName '$AvsCloudName' " + "--vcIp '$VC_ADDRESS' " + "--vcUsername '$ZertoUserWithDomain' " + "--vcPassword '$($PersistentSecrets.ZertoPassword)' " + "--zertoAdminPassword '$($PersistentSecrets.ZertoAdminPassword)'" $startTime = Get-Date $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Reconfigure ZVM" Write-Host "Zerto reconfiguration took: $((Get-Date).Subtract($startTime).TotalSeconds.ToString("F0")) seconds." if ($result.ScriptOutput.Contains("Success")) { Write-Host "Zerto reconfigured successfully." } elseif ($result.ScriptOutput.Contains("Warning:")) { $message = $result.ScriptOutput Write-Host $message Write-Warning $message } elseif ($result.ScriptOutput.Contains("Error:")) { $cleanErrMsg = $result.ScriptOutput -replace "Error: ", "" throw $cleanErrMsg } else { throw "An unexpected error occurred while reconfiguring Zerto. Please reinstall Zerto." } } function Test-ZertoPassword { <# .SYNOPSIS Checks validity of 'admin' and 'zadmin' passwords stored in PersistentSecrets .DESCRIPTION The Zerto 'admin' password is checked explicitly – try_zerto_login.py will return "Success" if the password is valid. The Console 'zadmin' password is checked implicitly – Invoke-ZVMScriptWithTimeout will fail with authentication error if the password is invalid. #> Write-Host "Starting $($MyInvocation.MyCommand)..." $scriptLocation = "/opt/zerto/zlinux/avs/try_zerto_login.py" $commandToExecute = "sudo python3 $scriptLocation --zertoAdminPassword '$($PersistentSecrets.ZertoAdminPassword)'" try { $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Validate Zerto password" -TimeoutMinutes 5 if ($result.ScriptOutput.Contains("Success")) { Write-Host "Zerto password is valid." } else { throw "Provided Zerto password is not valid." } } catch { throw "Zerto password validation failed. Problem: $_" } } enum PasswordsValidationResult { PasswordsValid = 0; ZertoPasswordInvalid = 1; ConsolePasswordInvalidOrExpired = 2; } function Test-ZertoPasswordResult { <# .SYNOPSIS Checks validity of 'admin' and 'zadmin' passwords stored in PersistentSecrets and returns a result code. .OUTPUTS [PasswordsValidationResult] PasswordsValid - Both passwords are valid ZertoPasswordInvalid - The 'admin' password is not valid ConsolePasswordInvalidOrExpired - The 'zadmin' password is not valid Throws an error if any other issue occurs during validation. #> Write-Host "Starting $($MyInvocation.MyCommand)..." try { Test-ZertoPassword return [PasswordsValidationResult]::PasswordsValid } catch { if ($_ -match "Provided Zerto password is not valid") { Write-Host 'The Zerto "admin" password is not valid.' return [PasswordsValidationResult]::ZertoPasswordInvalid } if ($_ -match "Failed to authenticate with the guest operating system using the supplied credentials") { Write-Host 'The Console "zadmin" password is not valid.' return [PasswordsValidationResult]::ConsolePasswordInvalidOrExpired } throw $_ } } function Update-VcPasswordInZvm { param ( [ValidateNotNullOrEmpty()][string] $NewVcPassword, [ValidateNotNullOrEmpty()][string] $ZertoAdminPassword, [ValidateNotNullOrEmpty()][string] $ClientSecret ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $scriptLocation = "/opt/zerto/zlinux/avs/change_vc_password.py" $commandToExecute = "sudo python3 $scriptLocation --vcPassword '$NewVcPassword' --zertoAdminPassword '$ZertoAdminPassword' --avsClientSecret '$ClientSecret'" $startTime = Get-Date $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Change VC password in ZVM" -TimeoutMinutes 20 Write-Host "Zerto reconfiguration took: $((Get-Date).Subtract($startTime).TotalSeconds.ToString("F0")) seconds." if ($result.ScriptOutput.Contains("Success")) { Write-Host "The new VC password in ZVM set successfully." } else { if ($result.ScriptOutput.Contains("Error:")) { $cleanErrMsg = $result.ScriptOutput -replace "Error: ", "" throw $cleanErrMsg #TODO: Standardize error messages for Error and Unknown cases, here and elsewhere, review unit tests } throw "Unexpected error occurred while updating VC password in ZVM." } } } function Update-ClientCredentialsInZvm { param ( [ValidateNotNullOrEmpty()][string] $NewClientId, [ValidateNotNullOrEmpty()][string] $NewClientSecret ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $scriptLocation = "/opt/zerto/zlinux/avs/change_azure_client_credentials.py" # change_azure_client_credentials is available starting ZVM 10u5p2 $scriptExists = Test-FileExistsInZVM -FileLocation $scriptLocation #TODO: Consider extracting check to caller method, method should not return bool value if ($scriptExists -eq $false) { return $false # ZVMA version does not support updating Client Credentials } $commandToExecute = "sudo python3 $scriptLocation --vcPassword '$($PersistentSecrets.ZertoPassword)' --zertoAdminPassword '$($PersistentSecrets.ZertoAdminPassword)' --azureClientId '$NewClientId' --avsClientSecret '$NewClientSecret'" $startTime = Get-Date $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Change Azure client credentials in ZVM" -TimeoutMinutes 20 Write-Host "Zerto reconfiguration took: $((Get-Date).Subtract($startTime).TotalSeconds.ToString("F0")) seconds." if ($result.ScriptOutput.Contains("Success")) { Write-Host "New Azure client credentials set successfully in ZVM." } else { if ($result.ScriptOutput.Contains("Error:")) { $cleanErrMsg = $result.ScriptOutput -replace "Error: ", "" throw $cleanErrMsg } throw "Unexpected error occurred while changing Azure client credentials in ZVM." } return $true } } function Set-DnsConfiguration($DNS) { #TODO: Once the u7 is published, this method can be removed, because static DNS should be set correctly by appliance from ovf, fixed in ZER-150945 Write-Host "Starting $($MyInvocation.MyCommand)..." try { $action = { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { Write-Error "$ZVM_VM_NAME doesn't exists" -ErrorAction Stop } $setDnsCommand = "grep -qxF 'nameserver $DNS' /etc/resolv.conf || echo 'nameserver $DNS' | sudo tee -a /etc/resolv.conf" $res = Invoke-VMScript -VM $ZVM -ScriptText $setDnsCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction SilentlyContinue $checkDnsCommand = "grep -qF 'nameserver $DNS' /etc/resolv.conf && echo 'true' || echo 'false'" $res = Invoke-VMScript -VM $ZVM -ScriptText $checkDnsCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction SilentlyContinue if ($null -eq $res -or $res.ScriptOutput.Trim() -ne "true") { throw "Failed to force set DNS" } $lockFileCommand = 'sudo chattr +i /etc/resolv.conf' $res = Invoke-VMScript -VM $ZVM -ScriptText $lockFileCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword Write-Host "DNS successfully set" } Invoke-Retry -Action $action -ActionName "SetDNS" -RetryCount 4 -RetryIntervalSeconds 30 } catch { $message = "Failed to set DNS. Configuration may fail. Problem: $_" Write-Host $message Write-Warning $message } } function Test-FileExistsInZVM($FileLocation) { Write-Host "Starting $($MyInvocation.MyCommand)..." try { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { throw "$ZVM_VM_NAME VM does not exist." } $existsFileCommand = "test -f $FileLocation && echo 'true' || echo 'false'" $res = Invoke-VMScript -VM $ZVM -ScriptText $existsFileCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction Stop switch (${res}?.ScriptOutput?.Trim()) { { $_ -eq $null } { throw "Unknown error." } { $_ -eq "true" } { return $true } { $_ -eq "false" } { return $false } default { throw "Unexpected output '$_'." } } } catch { throw "Failed to check file in ZVM. Problem: $_" } } function Set-ZertoVmPasswordExpiration { <# .SYNOPSIS Resets the ZVM VM console password expiration #> Write-Host "Starting $($MyInvocation.MyCommand)..." try { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { throw "$ZVM_VM_NAME VM does not exist." } # grep -Pq, -P to use Perl-compatible regular expressions, -q to be quiet without outputting the matching lines and returning 0 exit code if the pattern is found $chageCommand = "sudo chage --maxdays -1 $ZAPPLIANCE_USER && chage -l $ZAPPLIANCE_USER | grep -Pq '^Maximum number of days.*-1$' && echo 'true' || echo 'false'" $res = Invoke-VMScript -VM $ZVM -ScriptText $chageCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction Stop switch (${res}?.ScriptOutput?.Trim()) { { $_ -eq $null } { throw "Unknown error." } { $_ -eq "true" } { return } default { throw "Unexpected output '$_'." } } } catch { throw "Failed to set password expiry. Problem: $_" } } function Set-AzureResourceGroup { <# .SYNOPSIS Sets the Azure Resource Group name in the ZVMA #> param ( [string]$resourceGroupName ) Write-Host "Starting $($MyInvocation.MyCommand)..." $scriptLocation = "/opt/zerto/zlinux/avs/change_resource_group.py" $commandToExecute = "sudo python3 $scriptLocation --vcPassword '$($PersistentSecrets.ZertoPassword)' --avsClientSecret '$($PersistentSecrets.AvsClientSecret)' --zertoAdminPassword '$($PersistentSecrets.ZertoAdminPassword)' --resourceGroupName '$resourceGroupName'" $result = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName "Change resource group" if ($result.ScriptOutput.Contains("Success")) { Write-Host "Resource group set successfully." } elseif ($result.ScriptOutput.Contains("Error:")) { $cleanErrMsg = $result.ScriptOutput -replace "Error: ", "" throw $cleanErrMsg } else { throw "An unexpected error occurred while changing the resource group." } } function New-ZertoLogs { param ( [Parameter(Mandatory = $false)] [bool]$WithPrometheus ) Write-Host "Starting $($MyInvocation.MyCommand)..." try { $scriptParams = $WithPrometheus ? ' --with-prometheus' : '' $commandToExecute = "sudo python3 /opt/zerto/zlinux/avs/collect_logs.py$scriptParams" $res = Invoke-ZVMScriptWithTimeout -ScriptText $commandToExecute -ActionName 'Create ZVML logs archive' -TimeoutMinutes 30 $LOG_FILE = 'LogPath' $scriptOutput = $res.TrimmedOutput Write-Host "ZVML logs collection script output:`n$scriptOutput" if (-not ($scriptOutput -match "(?m)^Success\.[^']+'(?<$LOG_FILE>[^']+?)'\s+created\.$")) { throw 'No log file created.' } $logFile = $matches[$LOG_FILE] return $logFile } catch { throw "Failed to create ZVML log archive. Problem: $_" } } function Invoke-ZvmaNetDiagnostics { <# .SYNOPSIS Performs network connectivity diagnostics for ZVMA #> param( [ValidateNotNullOrEmpty()] [string]$TargetUri ) Write-Host "Starting $($MyInvocation.MyCommand) for $TargetUri..." try { $uri = [System.Uri]$TargetUri $hostname = $uri.Host Write-Host "DNS lookup result:`n$(Invoke-ZvmaNsLookup -TargetHost $hostname)" Write-Host "DNS dig lookup result:`n$(Invoke-ZvmaDigLookup -TargetHost $hostname)" Write-Host "Network ping result:`n$(Invoke-ZvmaPing -TargetHost $hostname)" Write-Host "Network traceroute result:`n$(Invoke-ZvmaTraceroute -TargetHost $hostname)" Write-Host "TCP telnet connectivity test result:`n$(Invoke-ZvmaTelnet -TargetHost $hostname)" Write-Host "TCP netcat connectivity test result:`n$(Invoke-ZvmaNetcat -TargetHost $hostname)" Write-Host "TLS connectivity test result:`n$(Invoke-ZvmaOpenSslCheck -TargetHost $hostname)" Write-Host "HTTP connectivity test result:`n$(Invoke-ZvmaCurl -TargetHost $TargetUri)" } catch { $Message = "Failed to run diagnostics, $_" Write-Host $Message Write-Error $Message -ErrorAction Stop } } function Invoke-ZvmaNsLookup { <# .SYNOPSIS Executes nslookup command on the ZVMA to test DNS resolution #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost ) Write-Host "Starting $($MyInvocation.MyCommand)..." return Invoke-ZvmaNetDiagnosticCommand -Command "nslookup" -TargetHost $TargetHost -CommandDescription "DNS lookup" } function Invoke-ZvmaDigLookup { <# .SYNOPSIS Executes dig command on the ZVMA for DNS resolution and detailed diagnostics #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost ) Write-Host "Starting $($MyInvocation.MyCommand)..." return Invoke-ZvmaNetDiagnosticCommand -Command "dig" -TargetHost $TargetHost -CommandDescription "DNS dig lookup" } function Invoke-ZvmaPing { <# .SYNOPSIS Executes ping command on the ZVMA to test network connectivity #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [int]$PingCount = 4 ) Write-Host "Starting $($MyInvocation.MyCommand)..." return Invoke-ZvmaNetDiagnosticCommand -Command "ping" -TargetHost $TargetHost -CommandArgs "-c $PingCount" -CommandDescription "Network ping" } function Invoke-ZvmaTraceroute { <# .SYNOPSIS Executes traceroute command on the ZVMA to trace network path #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [bool]$UseTcp = $true, [int]$Port = 443 ) Write-Host "Starting $($MyInvocation.MyCommand)..." $commandArgs = "-p $Port" if ($UseTcp) { $commandArgs += " -T " } return Invoke-ZvmaNetDiagnosticCommand -Command "sudo traceroute" -TargetHost $TargetHost -CommandArgs $commandArgs -CommandDescription "Network traceroute" } function Invoke-ZvmaTelnet { <# .SYNOPSIS Executes telnet command on the ZVMA to test TCP port connectivity #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [int]$Port = 443, [int]$TimeoutSeconds = 5 ) Write-Host "Starting $($MyInvocation.MyCommand)..." return Invoke-ZvmaNetDiagnosticCommand -Command "timeout $TimeoutSeconds telnet" -TargetHost $TargetHost -CommandArgs "$Port" -CommandDescription "TCP port connectivity test" } function Invoke-ZvmaNetcat { <# .SYNOPSIS Executes netcat command on the ZVMA to test TCP port connectivity .PARAMETER ZeroIo Enables netcat's zero-I/O mode (-z). When $true (default), netcat checks if a port is open without sending data. Set to $false to make a full connection and allow data transfer. #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [int]$Port = 443, [bool]$IsVerbose = $true, [bool]$ZeroIo = $true ) Write-Host "Starting $($MyInvocation.MyCommand)..." $commandArgs = "$Port" if ($ZeroIo) { $commandArgs += " -z" } if ($IsVerbose) { $commandArgs += " -v" } return Invoke-ZvmaNetDiagnosticCommand -Command "nc" -TargetHost $TargetHost -CommandArgs $commandArgs -CommandDescription "TCP netcat connectivity test" } function Invoke-ZvmaOpenSslCheck { <# .SYNOPSIS Executes openssl s_client command on the ZVMA to test TLS connectivity #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [int]$Port = 443, [int]$TimeoutSeconds = 10, [ValidateSet("tls1", "tls1_1", "tls1_2", "tls1_3")] [string]$TlsVersion = "tls1_3" ) Write-Host "Starting $($MyInvocation.MyCommand)..." return Invoke-ZvmaNetDiagnosticCommand -Command "timeout $TimeoutSeconds openssl s_client -connect" -TargetHost "$($TargetHost):$Port" -CommandArgs "-$TlsVersion" -CommandDescription "TLS connectivity test" } function Invoke-ZvmaCurl { <# .SYNOPSIS Executes curl command on the ZVMA to test HTTP connectivity and verbose output #> param ( [ValidateNotNullOrEmpty()] [string]$TargetHost, [bool]$IsVerbose = $true ) Write-Host "Starting $($MyInvocation.MyCommand)..." $commandText = "curl" if ($IsVerbose) { $commandText += " -v" } return Invoke-ZvmaNetDiagnosticCommand -Command $commandText -TargetHost "$TargetHost" -CommandDescription "HTTP connectivity test" } function Invoke-ZvmaNetDiagnosticCommand { <# .SYNOPSIS Executes a network diagnostics command on the ZVMA #> param ( [ValidateNotNullOrEmpty()] [string]$Command, [ValidateNotNullOrEmpty()] [string]$TargetHost, [string]$CommandArgs = "", [ValidateNotNullOrEmpty()] [string]$CommandDescription ) Write-Host "Starting Invoke-ZvmaNetDiagnosticCommand for $CommandDescription..." try { $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { throw "$ZVM_VM_NAME VM does not exist." } $fullCommand = "$Command $TargetHost $CommandArgs" Write-Host "Executing command: $fullCommand" $res = Invoke-VMScript -VM $ZVM -ScriptText $fullCommand -GuestUser $ZAPPLIANCE_USER -GuestPassword $PersistentSecrets.ZappliancePassword -ErrorAction Stop if ($null -eq $res) { throw "Failed to execute $Command command." } Write-Host "$CommandDescription for $TargetHost completed." return $res.ScriptOutput } catch { $errorMessage = "Failed to perform $CommandDescription on ZVM. Problem: $_" Write-Error $errorMessage return "Error: $errorMessage" } } |