In the last post I covered the basics of establishing an authenticated session with the Zerto API and connecting to the vCenter server. You need to configure the script examples covered in the first post in order to follow the instructions in this blog post, you can find this here:
In the Zerto GUI you can see real-time statistics on Recovery Point Objectives (RPO) and storage consumption. This gives you an easy to use overview on what is currently happening on the Zerto platform at all times, but there is a catch. The catch is that the data is only stored for 4 hours maximum (RPO) or is a real-time view on the usage (storage).
For large enterprises or cloud providers you may require reporting on these data points over a much longer period to ensure you stayed within your defined SLAs, to build customer facing reports or generate billing data.
A common request is often reporting on the RPO and/or storage usage of a customer on an interval every x minutes in a monthly report. In this post I’m going to cover how to do this step by step and then give you a full working example at the end which is being used by Zerto customers and cloud providers I work with today.
To get started run the authentication and web session examples from the first post. Then we need to set the directory where we want to store the reporting data and this example will create a subfolder for each month and create the subfolder if it does not exist:
# Export Directory, should be created in advance
$ExportDataDir = "C:\ZVRAPIScript\"
# Setting log directory for engine and current month
$CurrentMonth = get-date -format MM.yy
$CurrentExportDataDir = $ExportDataDir + $CurrentMonth
# Testing path exists to engine logging, if not creating it
$ExportDataDirTestPath = test-path $CurrentExportDataDir
if ($ExportDataDirTestPath -eq $False)
New-Item -ItemType Directory -Force -Path $CurrentExportDataDir
Now we need to build an Array of all the VPG data in order to then export it to the CSV directory created above:
# Build List of VPGs
$vpgListApiUrl = $baseURL+"vpgs"
$vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertSessionHeader -ContentType "application/xml"
# Building Protection group array and getting date and time of the query for insertion into the CSV
$zertoprotectiongrouparray = @()
# Change the date time formats below if needed
$zertoprotectiongrouparrayTimeStampDate = get-date -format d
$zertoprotectiongrouparrayTimeStampTime = get-date -format HH:mm:ss
$zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,ActualRPO,Status,vmscount,ProvisionedStorage,UsedStorage,vpgidentifier
In the $zertoprotectiongrouparray variable you will now see a list of all the VPGs, with the data from the fields selected that includes the ZORG, VPG name, RPO and storage usage amongst other data. We now need to export this information and in my example I’m using a CSV file per ZORG which contains all of the VPGs for that ZORG on a monthly basis:
# Logging data per VPG
foreach ($_ in $zertoprotectiongrouparray)
$CurrentOrganizationName = $_.OrganizationName
# Assigning a ZORG called "NoZORG" if one does not exist
if ($CurrentOrganizationName -eq "")
$CurrentOrganizationName = "NoZORG"
# Building log file name for the ZORG found
$CurrentCSVName = $CurrentExportDataDir + "\" + "$CurrentOrganizationName" + "-" + $CurrentMonth + "-ZertoAPIExport.CSV"
# Setting current values for insertion into the CSV file using an array
$CurrentVPGArray = @()
$CurrentVPGArrayLine = new-object PSObject
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "Date" -Value $zertoprotectiongrouparrayTimeStampDate
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "Time" -Value $zertoprotectiongrouparrayTimeStampTime
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $_.vpgname
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "ZORG" -Value $CurrentOrganizationName
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "ActualRPO" -Value $_.ActualRPO
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "Status" -Value $_.Status
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "vmscount" -Value $_.vmscount
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "ProvisionedStorage" -Value $_.ProvisionedStorage
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "UsedStorage" -Value $_.UsedStorage
$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "vpgidentifier" -Value $_.vpgidentifier
$CurrentVPGArray += $CurrentVPGArrayLine
# Testing to see if CSV already exists
$CurrentCSVNameTestPath = test-path $CurrentCSVName
# If CSV exist test False creating the CSV with no append
if ($CurrentCSVNameTestPath -eq $False)
$CurrentVPGArray | export-csv -path $CurrentCSVName -NoTypeInformation
# If CSV exist test True appending to the existing CSV
if ($CurrentCSVNameTestPath -eq $True)
$CurrentVPGArray | export-csv -path $CurrentCSVName -NoTypeInformation -Append
# End of per VPG actions below
In the specified output directory, you will now see a CSV file like the below:
Any subsequent times you run the script it will append the information to the existing CSVs, re-create them if they don’t exist and create a new subfolder and CSV on a monthly basis.
You can now automate the script to run on any frequency you desire using Windows Task Scheduler:
Arguments: -ExecutionPolicy Bypass -File "C:\ ZVRAPIScript \ZVRAPIReportingtoCSV.ps1"
Now that you have all the RPO and storage usage data in simple CSV files you can keep this for any number of months or even years, on any granularity you require. Pretty cool huh?! For a pre-built version of this script you can download it from:
I hope you found this blog post useful and questions or comments let me know. Happy scripting,