Update Invoke-ZertoRestRequest.ps1

reverting to non-LLM code
This commit is contained in:
2025-02-09 21:01:17 -05:00
parent de23881418
commit 392048afce
+141 -122
View File
@@ -1,151 +1,170 @@
function Invoke-ZertoRestRequest { function Invoke-ZertoRestRequest {
[cmdletbinding()] [cmdletbinding()]
param( param(
[Parameter(HelpMessage = "API method to be used. GET, PUT, POST, or DELETE. If unspecified, defaults to GET.")] # Parameter help description
[Parameter(
Helpmessage = "API method to be used. GET, PUT, POST, or DELETE. Refer to documentation for the API endpoint to ensure the correct method is being used. If unspecified, defaults to GET"
)]
[ValidateSet("GET", "PUT", "POST", "DELETE")] [ValidateSet("GET", "PUT", "POST", "DELETE")]
[string]$method = "GET", [string]$method = "GET",
[Parameter(
[Parameter(Mandatory, HelpMessage = "URI endpoint to be utilized. Only the endpoint needs to be submitted.")] Mandatory,
Helpmessage = "URI endpoint to be utilized. When submitting the URI, only the endpoint needs to be submitted. Please review the help documentation for examples."
)]
[ValidateNotNullOrEmpty()] [ValidateNotNullOrEmpty()]
[string]$uri, [string]$uri,
[Parameter(
[Parameter(HelpMessage = "Body to be submitted to the REST API endpoint in JSON format.")] Helpmessage = "Body to be submitted to the REST API endpoint. This needs to be submitted in JSON format"
[string]$body = "", )]
[ValidateNotNullOrEmpty()]
[Parameter(HelpMessage = "PSCredential object, used only when authenticating with the ZVM.")] [string]$body,
[Parameter(
Helpmessage = "PSCredential object. This is ONLY used when authenticating with the ZVM. No other endpoints require this and generally is not used."
)]
[PSCredential]$credential, [PSCredential]$credential,
[Parameter(
[Parameter(HelpMessage = "Use this switch to return request headers along with the response body.")] Helpmessage = "Use this switch if you would like the request headers returned along with the body. Useful for troubleshooting to get HTTP error codes."
)]
[switch]$returnHeaders [switch]$returnHeaders
) )
# API version. Currently this is locked at v1 in all versions of Zerto. Should this change, will look
# at making this as parameter to be selected during function call.
$apiVersion = "v1" $apiVersion = "v1"
# While the API can use XML or JSON, this module is built on JSON functionality. Currently forcing all
# content types and language to JSON.
$contentType = "application/json"
$callerErrorActionPreference = $ErrorActionPreference $callerErrorActionPreference = $ErrorActionPreference
# If the ZVM server and Port not defined, Stop Call
# Ensure required script variables exist if ( -not ((Test-Path variable:script:zvmServer) -and (Test-Path variable:script:zvmPort)) ) {
if (-not (Test-Path variable:script:zvmServer) -or -not (Test-Path variable:script:zvmPort)) { Throw "Zerto Connection does not Exist. Please run Connect-ZertoServer first to establish a connection"
Throw "Zerto connection does not exist. Run Connect-ZertoServer first."
} }
# Ensure $Script:Reconnect is defined # If the Headers exist and the Last action was more than 30 minutes ago, Session is Expired
if (-not (Test-Path variable:script:Reconnect)) { $Script:Reconnect = $false } if ( (Test-Path variable:script:zvmHeaders) -and (Test-Path variable:script:AuthExpiresAt) -and $([datetime]$script:AuthExpiresAt) -lt $(Get-Date) -and $Script:Reconnect -eq $False ) {
# Check for expired session
if ((Test-Path variable:script:AuthExpiresAt) -and $([datetime]$script:AuthExpiresAt) -lt (Get-Date)) {
Remove-Variable -Name AuthExpiresAt -Scope Script Remove-Variable -Name AuthExpiresAt -Scope Script
if ($Script:Reconnect) { Throw "Authorization Token has Expired. Please re-authorize to the Zerto Virtual Manager"
Write-Verbose "Authorization expired. Reauthorizing." } elseif (( (Test-Path variable:script:zvmHeaders) -and (Test-Path variable:script:AuthExpiresAt) -and $([datetime]$script:AuthExpiresAt) -lt $(Get-Date) -and $Script:Reconnect -eq $True )) {
Connect-ZertoServer -zertoServer $Script:zvmServer -zertoPort $script:zvmPort -credential $Script:CachedCredential Write-Verbose "Authorization had expired. Attempting Reauthorization."
} else { Remove-Variable -Name AuthExpiresAt -Scope Script
Throw "Authorization token expired. Please reauthorize." Connect-ZertoServer -zertoServer $Script:zvmServer -zertoPort $script:zvmPort -credential $Script:CachedCredential
} }# else {
}
# Build the URI to be submitted
$submittedURI = "https://{0}:{1}/{2}/{3}" -f $script:zvmServer, $script:zvmPort, $apiVersion, $uri $submittedURI = "https://{0}:{1}/{2}/{3}" -f $script:zvmServer, $script:zvmPort, $apiVersion, $uri
$script:zvmLastAction = (Get-Date).Ticks
$responseHeaders = @{}
$apiRequestResults = $null
try { try {
# Set default headers # Set the zvmLastAction time and try to submit the REST Request
$headers = @{ $script:zvmLastAction = (Get-Date).Ticks
"Accept" = "application/json" # If running PwSh - Use this Invoke-RestMethod with passed Variables
}
# If authorization headers exist, add them
if (Test-Path variable:script:zvmHeaders) {
$headers["Authorization"] = "Bearer $($script:zvmHeaders.Authorization)"
}
$params = @{
Uri = $submittedURI
Method = $method
Headers = $headers
TimeoutSec = 100
ContentType = "application/json"
}
# Ensure GET requests do not include a body
if ($method -ne "GET") {
$params["Body"] = $body
}
# Handle authentication requests
if ($uri -match "auth/realms/.*/protocol/openid-connect/token" -and $method -eq "POST") {
$data = @{
'client_id' = $script:zertoClientId
'username' = $credential.GetNetworkCredential().UserName
'password' = $credential.GetNetworkCredential().Password
'grant_type' = 'password'
}
$params.Uri = "https://{0}:{1}/auth/realms/zerto/protocol/openid-connect/token" -f $script:zvmServer, $script:zvmPort
$params.Body = $data
$params.ContentType = "application/x-www-form-urlencoded"
}
# Handle SSL/TLS trust issue for PowerShell 5.1
if ($PSVersionTable.PSVersion.Major -lt 6) {
Add-Type -TypeDefinition @"
using System;
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;
}
}
"@ -PassThru
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
} else {
$params["SkipCertificateCheck"] = $true
}
# Execute API request
if ($PSVersionTable.PSVersion.Major -ge 6) { if ($PSVersionTable.PSVersion.Major -ge 6) {
$apiRequestResults = Invoke-RestMethod @params -ResponseHeadersVariable responseHeaders # If we are authenticating to the ZVM, Use this block to use Invoke-WebRequest and format the Headers and Body as expected.
if ($uri -eq "auth/realms/zerto/protocol/openid-connect/token" -and $method -eq "POST") {
$data = @{
'client_id' = $script:zertoClientId
'username' = $credential.GetNetworkCredential().UserName
'password' = $credential.GetNetworkCredential().Password
'grant_type' = 'password'
}
$params = @{
'Uri' = 'https://' + $script:zvmServer + ':' + $script:zvmPort + '/auth/realms/zerto/protocol/openid-connect/token'
'Method' = 'Post'
'Body' = $data
'ContentType' = 'application/x-www-form-urlencoded'
}
$apiRequestResults = Invoke-RestMethod @params -SkipCertificateCheck
$ExpiresIn = $apiRequestResults.expires_in
$script:AuthExpiresAt = (Get-Date).AddSeconds($ExpiresIn)
$script:refreshToken = $apiRequestResults.refresh_token
$responseHeaders = @{ }
$responseHeaders['Authorization'] = "Bearer " + @($apiRequestResults.access_token)
# If we are logging out from the ZVM, use this block to use Invoke-WebRequest and format the Headers and Body as expected.
} elseif ($uri -eq "auth/realms/zerto/protocol/openid-connect/logout" -and $method -eq "POST") {
$data = @{
'client_id' = $script:zertoClientId
'logout' = 'true'
}
$params = @{
'Uri' = 'https://' + $script:zvmServer + ':' + $script:zvmPort + '/auth/realms/zerto/protocol/openid-connect/logout'
'Method' = 'Post'
'Body' = $data
'ContentType' = 'application/x-www-form-urlencoded'
}
$apiRequestResults = Invoke-RestMethod @params -SkipCertificateCheck
} else {
$apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -Body $body -ContentType $contentType -Credential $credential -SkipCertificateCheck -ResponseHeadersVariable responseHeaders -TimeoutSec 100
}
} else { } else {
# PowerShell 5.1 workaround: use Invoke-WebRequest instead # If running PowerShell 5.1 --> Do the Following
$webResponse = Invoke-WebRequest @params # Check to see if All Certs are Trusted. If not, Create the Policy to Trust All Certificates
$apiRequestResults = $webResponse.Content | ConvertFrom-Json -ErrorAction SilentlyContinue if ([System.Net.ServicePointManager]::CertificatePolicy.GetType().Name -ne "TrustAllCertsPolicy") {
$responseHeaders = $webResponse.Headers Try {
} $type = @'
using System.Net;
# Debugging - Inspect Response Type using System.Security.Cryptography.X509Certificates;
Write-Verbose "Response Type: $($apiRequestResults.GetType().FullName)" public class TrustAllCertsPolicy : ICertificatePolicy {
Write-Verbose "Response Content: $($apiRequestResults | ConvertTo-Json -Depth 10)" public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
return true;
# Ensure response is parsed properly
if ($apiRequestResults -is [string]) {
try {
$apiRequestResults = $apiRequestResults | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-Verbose "Response is not in JSON format, returning raw output."
}
}
# Handle token expiration update
if ($uri -match "auth/realms/.*/protocol/openid-connect/token" -and $method -eq "POST") {
if ($apiRequestResults -is [System.Collections.IDictionary]) {
Write-Verbose "API response is a dictionary. Extracting values..."
}
$script:AuthExpiresAt = (Get-Date).AddSeconds($apiRequestResults.expires_in)
$script:refreshToken = $apiRequestResults.refresh_token
$headers["Authorization"] = "Bearer " + $apiRequestResults.access_token
}
} }
catch { }
'@
Add-Type -TypeDefinition $type -ErrorAction SilentlyContinue
} Catch {
if ($error[0].Exception -ne "Cannot add type. The type name 'TrustAllCertsPolicy already exists.") {
Write-Debug $error[0]
}
}
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
# If we are authenticating to the ZVM, Use this block to use Invoke-WebRequest and format the Headers as expected.
if ($uri -eq "auth/realms/zerto/protocol/openid-connect/token" -and $method -eq "POST") {
$data = @{
'client_id' = $script:zertoClientId
'username' = $credential.GetNetworkCredential().UserName
'password' = $credential.GetNetworkCredential().Password
'grant_type' = 'password'
}
$params = @{
'Uri' = 'https://' + $script:zvmServer + ':' + $script:zvmPort + '/auth/realms/zerto/protocol/openid-connect/token'
'Method' = 'POST'
'Body' = $data
'ContentType' = 'application/x-www-form-urlencoded'
}
$apiRequestResults = Invoke-RestMethod @params
$ExpiresIn = $apiRequestResults.expires_in
$script:AuthExpiresAt = (Get-Date).AddSeconds($ExpiresIn)
$script:refreshToken = $apiRequestResults.refresh_token
$responseHeaders = @{ }
$responseHeaders['Authorization'] = "Bearer " + @($apiRequestResults.access_token)
} elseif ($method -ne "GET") {
# If the Method is something other than 'GET' use this call with a body parameter
$apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -Body $body -ContentType $contentType -Credential $credential -TimeoutSec 100
} else {
# If the Method we are calling is 'GET' use this call without a body parameter
$apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -ContentType $contentType -Credential $credential -TimeoutSec 100
}
}
} catch {
# If an error is encountered, Catch
Write-Error -ErrorRecord $_ -ErrorAction $callerErrorActionPreference Write-Error -ErrorRecord $_ -ErrorAction $callerErrorActionPreference
return
} }
# Return response based on $returnHeaders flag # If the calling function does not need the headers (Default Action) return the results of the API Call
if (-not $returnHeaders) { if (-not $returnHeaders) {
return $apiRequestResults return $apiRequestResults
} else { } else {
return [PSCustomObject]@{ #If Headers are required, build a PS Custom Object with the Results and the Headers
apiRequestResults = $apiRequestResults $apiRequestAndHeaderResults = New-Object -TypeName psobject
Headers = $responseHeaders $apiRequestAndHeaderResults | Add-Member -MemberType NoteProperty -Name "apiRequestResults" -Value $apiRequestResults
} $apiRequestAndHeaderResults | Add-Member -MemberType NoteProperty -Name "Headers" -Value $responseHeaders
return $apiRequestAndHeaderResults
#}
} }
} }