Since my first post back in 2014, many of the example scripts that I’ve shared integrate with Zerto using their bolt-on REST APIs. After 4 years of stability, in 5.0 U3, Zerto changed the requirements of the authorization header to require the content type in addition to the session token as a “security” feature.
Unfortunately, this means that any Zerto script you have downloaded from my blog, customized, or written, needs to be edited to continue working after the upgrade. Without any modification, your REST API calls to Zerto won’t even give you an error, they will just return null. Pretty annoying huh? I’ll be honest in that I was completely livid when I found out. To me, this looks like a pointless change to fix a problem that didn’t exist while creating a heap more by how it is was implemented and communicated.
On top of this, the Zerto API documentation leaves a lot to be desired as it hasn’t even been updated (as of 06/25/17) to reflect the new requirements! But that’s why I’m here to help. So how do you go about fixing your Zerto scripts?
First let’s take a look at the old way of constructing the header:
# Extracting x-zerto-session from the response $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertosessionHeader = @{"x-zerto-session"=$xZertoSession}
The $zertosessionHeader variable above will no longer work. Now you need to specify the content type in the session header rather than just the session token/ID as before:
# New header for JSON content, ensure a space is maintained between the first and second line $zertoSessionHeader_json = @{"Accept"="application/json" "x-zerto-session"=$xZertoSession} # New header for XML content, ensure a space is maintained between the first and second line $zertoSessionHeader_xml = @{"Accept"="application/xml" "x-zerto-session"=$xZertoSession}
Big thanks to Dan Grinnel who alerted me to the change while he was implementing the Recovery Plan v2 script. Also, he kindly supplied the examples on how to fix it! Nice work. You then need to use the appropriate new header variable depending on the content requested:
# XML query example $VPGList = Invoke-RestMethod -Uri $VPGListUrl -TimeoutSec 100 -Headers $zertoSessionHeader_xml -ContentType "application/xml" # JSON query example $VPGList = Invoke-RestMethod -Uri $VPGListUrl -TimeoutSec 100 -Headers $zertoSessionHeader_json -ContentType "application/json"
The easiest fix is therefore to open each of your Zerto scripts then:
- Search for “”x-zerto-session”=$xZertoSession” and replace with the new JSON or XML header examples
- Search for each Invoke-RestMethod and change the variable after “-Headers” to match the content type, if they don’t match the query won’t work
As a best practice going forward I will only use JSON in my example scripts. In the past, I’ve used a mix of XML and JSON which this change highlighted as an issue (plus the use of XML is dying anyway). Here is an example script showing you authentication, using the new headers and pulling a list of VPGs using both JSON and XML:
################################################ # Configure the variables below for the ZVM ################################################ $ZertoServer = "192.168.0.31" $ZertoPort = "9669" # Prompting for username and password to authenicate with ZVM $Credentials = Get-Credential -Credential $null $ZertoUser = $Credentials.UserName $Credentials.Password | ConvertFrom-SecureString $ZertoPassword = $Credentials.GetNetworkCredential().password ######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## # Setting certificate exception handling ################################################ add-type @" 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 ################################################ # Building ZVR API string and invoking REST API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" $xZertoSessionURL = $baseURL + "session/add" $authInfo = ("{0}:{1}" -f $ZertoUser,$ZertoPassword) $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo) $authInfo = [System.Convert]::ToBase64String($authInfo) $headers = @{Authorization=("Basic {0}" -f $authInfo)} $sessionBody = '{"AuthenticationMethod": "1"}' $TypeJSON = "application/json" $TypeXML = "application/xml" # Authentication with ZVR API Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } # Selecting session token/ID $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") ############################################### # Old header - Extracting x-zerto-session from the response ############################################### # $zertosessionHeader = @{"x-zerto-session"=$xZertoSession} ############################################### # New header for JSON content ############################################### $zertoSessionHeader_json = @{"Accept"="application/json" "x-zerto-session"=$xZertoSession} ############################################### # New header for XML content ############################################### $zertoSessionHeader_xml = @{"Accept"="application/xml" "x-zerto-session"=$xZertoSession} ############################################### # Getting list of VPGs using JSON ############################################### $VPGListUrl = $baseURL+"vpgs" $VPGListJSON = Invoke-RestMethod -Uri $VPGListUrl -TimeoutSec 100 -Headers $zertoSessionHeader_json -ContentType $TypeJSON write-host "JSON VPG List:" $VPGListJSON ############################################### # Getting list of VPGs using XML ############################################### $VPGListUrl = $baseURL+"vpgs" $VPGListXML = Invoke-RestMethod -Uri $VPGListUrl -TimeoutSec 100 -Headers $zertoSessionHeader_xml -ContentType $TypeXML write-host "XML VPG List:" $VPGListXML.ArrayOfVpgApi.VpgApi ################################################ # End of script ################################################
Like you I now need to go back and start editing all my shared examples for the new change. As I complete and test each one I will share the 5.0 U3+ version. Happy scripting and good luck,
Joshua