automating zerto virtual replication with...

134
Automating Zerto Virtual Replication with PowerShell & REST APIs Whitepaper VERSION 3.0 NOVEMBER 2017

Upload: others

Post on 22-May-2020

34 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

Automating Zerto Virtual Replication with PowerShell & REST APIs Whitepaper

VERSION 3.0

NOVEMBER 2017

Page 2: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 2 OF 134

Table of Contents

1 INTRODUCTION .................................................................................................................................................... 4

1.1 Use Cases .....................................................................................................................................................................4

1.2 REST APIs .....................................................................................................................................................................4

1.3 Legal Disclaimer ...........................................................................................................................................................4

2 BASICS & BEST PRACTICES .................................................................................................................................... 5

2.1 Requirements ..............................................................................................................................................................5

2.2 Using Variables & Arrays .............................................................................................................................................5

2.3 Encrypting Passwords ..................................................................................................................................................6

2.4 Scripting Best Practices................................................................................................................................................6

2.5 Transcripts ...................................................................................................................................................................6

2.6 Loading Modules .........................................................................................................................................................7

2.7 Bypassing Certificate Warnings ...................................................................................................................................7

2.8 Establishing API Sessions .............................................................................................................................................8

2.9 Full Start of Script Example..........................................................................................................................................9

3 QUERYING & REPORTING ................................................................................................................................... 11

3.1 Use Cases .................................................................................................................................................................. 11

3.1 Listing Unprotected VMs .......................................................................................................................................... 11

3.2 Using Unprotected VM IDs ....................................................................................................................................... 11

3.3 Listing Protected VMs & VPGs .................................................................................................................................. 12

3.4 Long Term RPO & Storage Reporting to CSV ............................................................................................................ 13

3.5 Resource Reports...................................................................................................................................................... 15

3.6 Resource Report Use Cases ...................................................................................................................................... 17

3.7 VPG, VM, VDISK, VNIC & Re-IP Settings Report ....................................................................................................... 18

4 DAILY EMAIL REPORTS........................................................................................................................................ 27

4.1 Use Cases .................................................................................................................................................................. 27

4.2 Design Methodology ................................................................................................................................................ 27

4.3 Daily Email Report .................................................................................................................................................... 27

5 AUTOMATING DEPLOYMENT ............................................................................................................................. 67

5.1 Use Cases .................................................................................................................................................................. 67

5.2 Bulk Automated VRA Deployment ........................................................................................................................... 67

5.3 Bulk Automated VPG Creation – ZVM Only.............................................................................................................. 70

5.4 Bulk Automated VPG Creation – ZVM & ZCM .......................................................................................................... 76

5.5 Bulk Automated VPG Creation with Boot Groups & Re-IP – ZVM Only ................................................................... 82

6 AUTOMATING VM PROTECTION ........................................................................................................................ 89

6.1 Use Cases .................................................................................................................................................................. 89

6.2 Automating VM Protection by vSphere Folder - ZVM Only ..................................................................................... 89

6.3 Automating VM Protection by vSphere Folder - ZVM & ZCM .................................................................................. 97

6.4 Automating VM Protection with vRealize Orchestrator ........................................................................................ 104

6.5 Adding VMs to VPGs ............................................................................................................................................... 105

Page 3: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 3 OF 134

7 BULK EDIT OPERATIONS ................................................................................................................................... 107

7.1 Bulk VPG Name Changing ....................................................................................................................................... 107

7.2 Bulk Editing VM NIC Settings Including Re-IP & Port Groups ................................................................................. 111

8 SCHEDULING OFFSITE CLONES ......................................................................................................................... 119

8.1 Use Cases ................................................................................................................................................................ 119

8.2 Design Methodology .............................................................................................................................................. 119

8.3 Scheduled Offsite Clone ......................................................................................................................................... 120

9 TROUBLESHOOTING ......................................................................................................................................... 134

Page 4: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 4 OF 134

1 INTRODUCTION

1.1 Use Cases

This document gives an overview of how to utilize Zerto Virtual Replication REST APIs with PowerShell to automate your virtual

infrastructure. In turn, this enables the reduction of manual processes and the realization of the full benefits of software-defined

replication and recovery. Highlights of key use cases covered within this document include:

• Automating VM protection

• Automating VM protection with vRealize Orchestrator

• Bulk VRA deployment

• Bulk VPG configuration

• Scheduling Offsite Clones

• Daily email reports

• Bulk Re-IP addressing

Also included is how to obtain reporting on:

• Long term RPO statistics

• VMs by top journal and recovery storage usage

• Protected and unprotected VMs

• VMs by target Hosts for recovery balancing

• VMs by average bandwidth utilization

• VMs by datastore

• VMs by CPU and RAM allocation

The examples given have been developed to meet the requirements of Zerto cloud and enterprise environments ranging from 100s to

thousands of VMs. The font size of the examples given are optimized depending on the maximum line length to enable copying and

pasting directly from the PDF into your PowerShell scripts.

1.2 REST APIs

The REST APIs utilized in the examples are all included within the Zerto Virtual Manager documentation set. The document does not

intend to give examples for all the available APIs. Its purpose is to give examples of the most commonly requested use cases and give

you the information and knowledge to customize and create your own automation scripts.

1.3 Legal Disclaimer

ALL EXAMPLES AND SCRIPTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. THE AUTHOR AND ZERTO FURTHER

DISCLAIM ALL IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR OF

FITNESS FOR A PARTICULAR PURPOSE.

IN NO EVENT SHALL ZERTO, ITS AUTHORS, OR ANYONE ELSE INVOLVED IN THE CREATION, PRODUCTION, OR DELIVERY OF THE

SCRIPTS BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS

PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR

INABILITY TO USE THE SAMPLE SCRIPTS OR DOCUMENTATION, EVEN IF THE AUTHOR OR ZERTO HAS BEEN ADVISED OF THE

POSSIBILITY OF SUCH DAMAGES. THE ENTIRE RISK ARISING OUT OF THE USE OR PERFORMANCE OF THE SAMPLE SCRIPTS AND

DOCUMENTATION REMAINS WITH YOU.

Page 5: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 5 OF 134

2 BASICS & BEST PRACTICES

2.1 Requirements

All the example scripts given in this document share a common set of minimum requirements. These are:

• ZVM Server Name, Username and password with permission to access the API of the ZVM

• Network connectivity to the ZVM

• Access permission to write in and create the directory specified for logging, or manually create the directory in advance

• The PowerShell execution policy set to "Set-ExecutionPolicy unrestricted"

• Use Foxit PDF Reader or Adobe PDF reader to open then copy examples from this PDF and maintain the script structure

Some example scripts also directly interact with the vCenter or a Zerto Cloud Manager (ZCM). For these examples, the following

requirements must also be met:

• VMware PowerCLI, 5.5+, installed on the host running the script

• vCenter Server Name, Username and password to establish as session using PowerCLI to the vCenter

• Network connectivity to the vCenter

• ZCM with a new service profile configured and applied to both site ZVMs (source and target)

2.2 Using Variables & Arrays

To store data for execution within PowerShell scripts it is important to use variables and arrays for efficiency. Variables allow a value

to be used multiple times and it only needs to be changed once, making editing scripts easier. For ease of use the same variables will

be used in all examples in this document, these are:

$ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = [email protected] $ZertoPassword = "Password123!"

$vCenterServer = "192.168.0.81" $vCenterUser = [email protected] $vCenterPassword = "Password123!"

Arrays are used in many examples in this document. These are used to build tables of data obtained from the APIs and multiple data

sources simultaneously, like vSphere PowerCLI queries. The array is then used to export data to CSVs or to perform multiple actions

within the script. Arrays are created line by line with the required values which are then added together. Below as an example of how

to create a simple array:

$Value1 = “FirstValue” $Value2 = “SecondValue”

$Array = @()

$ArrayLine = new-object PSObject $ArrayLine | Add-Member -MemberType NoteProperty -Name "Value1" -Value $Value1 $ArrayLine | Add-Member -MemberType NoteProperty -Name "Value2" -Value $Value2 $Array += $ArrayLine $Array

Page 6: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 6 OF 134

2.3 Encrypting Passwords

In all the examples provided in this document the passwords are stored using plain text within your PowerShell scripts. This is often

against company policy and so is only done for ease of testing and there are multiple ways to remove the use of plain text passwords.

To encrypt the passwords, within the machine and user running the script, follow the steps in the link below:

http://www.adminarsenal.com/admin-arsenal-blog/secure-password-with-powershell-encrypting-credentials-part-1/

Alternatively, if you need to run the script across multiple users and machines you can use a secure key:

http://www.adminarsenal.com/admin-arsenal-blog/secure-password-with-powershell-encrypting-credentials-part-2/

2.4 Scripting Best Practices

Scripting and automating tasks in a production environment can introduce an element of risk if care is not taken to ensure the scripts

have been tested. To mitigate this risk, follow the below best practices:

1. Use Test VMs where applicable for initial testing

2. Use a demo lab or separate vSphere environment if available for testing

3. Test scripts using PowerShell ISE to aid with troubleshooting before scheduling a script

4. Use transcripts to maintain audit trails and aid with troubleshooting

5. Create descriptive comments throughout scripts to make it easier to understand and edit

6. Use version controls on scripts with last known good configurations

7. Manage and schedule scripts from a central server

8. Document scripts and automated processes

9. Ensure IT teams know how to enable and disable scripts

2.5 Transcripts

In all examples of significant length transcripts are used to log the script being run and capture any issues upon execution. A logical

naming and folder structure is also utilized. To start a transcript:

################################################ # Setting log directory and starting transcript logging ################################################ $LogDataDir = “C:\LogFolder\” $CurrentMonth = get-date -format MM.yy

$CurrentTime = get-date -format hh.mm.ss

$CurrentLogDataDir = $LogDataDir + $CurrentMonth $CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt" # Testing path exists to engine logging, if not creating it $ExportDataDirTestPath = test-path $CurrentLogDataDir if ($ExportDataDirTestPath -eq $False)

{ New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

} start-transcript -path $CurrentLogDataFile -NoClobber

To stop the transcript at the end of the script use:

################################################

# Stopping logging ################################################ Stop-Transcript

Page 7: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 7 OF 134

2.6 Loading Modules

When working with the Zerto API and PowerShell it is often required to also interact with the vCenter using PowerCLI. We

recommend installing PowerCLI via the PowerShell Galery using the method described in VMware’s Blog located here

https://blogs.vmware.com/PowerCLI/2017/04/powercli-install-process-powershell-gallery.html. Using this method, PowerCLI will be

available when needed in your scripts without having to load additional modules. The example scripts included in this document

assume that you are using this method to include required PowerShell modules. Occassionally, a module will not be available via the

PowerShell Galery and will need to be called manually, such is the case when working with the Zerto PowerShell CMDLETs. In cases

like this, we suggest using the following method to load the module required:

function LoadSnapin{ param($PSSnapinName) if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){ Add-pssnapin -name $PSSnapinName } } # Loading snapins and modules

LoadSnapin -PSSnapinName "Zerto.PS.Commands"

2.7 Bypassing Certificate Warnings

By default, ZVR is installed with a self-generated certificate. If this is not replaced the API authentication will fail unless the same

script has connected to the vCenter server using PowerCLI, which the ZVM is connected to, or if the default certificate behavior of the

script has been changed as per:

################################################ # Setting Cert Policy - required for successful auth with the Zerto API with non-trusted certs ################################################ 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

Page 8: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 8 OF 134

2.8 Establishing API Sessions

To utilize ZVR REST APIs an authenticated session is required at the start of each PowerShell script as per:

################################################ # Building Zerto API string and invoking API ################################################ $BaseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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" Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $Headers -Method POST -Body $SessionBody -ContentType $TypeJSON

} Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON #Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$ZertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON}

Page 9: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 9 OF 134

2.9 Full Start of Script Example

Following is a sample start of script that connects to the ZVM API:

################################################ # Configure the variables below ################################################ $LogDataDir = "C:\LogFolder\" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!"

################################################ # Setting log directory and starting transcript logging ################################################ $CurrentMonth = get-date -format MM.yy $CurrentTime = get-date -format hh.mm.ss $CurrentLogDataDir = $LogDataDir + $CurrentMonth $CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt" # Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir if ($ExportDataDirTestPath -eq $False) { New-Item -ItemType Directory -Force -Path $CurrentLogDataDir } start-transcript -path $CurrentLogDataFile -NoClobber ################################################ # Setting Cert Policy - required for successful auth with the Zerto API without connecting to vsphere using PowerCLI

################################################ 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 Zerto API string and invoking API ################################################

$BaseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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" Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $Headers -Method POST -Body $SessionBody -ContentType $TypeJSON } Catch { Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force }

#Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

Page 10: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 10 OF 134

$ZertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON}

Following is a sample start of script that connects to the ZVM API and a vCenter using PowerCLI:

################################################ # Configure the variables below using the Production vCenter & ZVM ################################################ $LogDataDir = "C:\LogFolder\" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!" $vCenterServer = "192.168.0.81" $vCenterUser = "[email protected]" $vCenterPassword = "Zerto1234!" ################################################ # Setting log directory for engine and current month ################################################ $CurrentMonth = get-date -format MM.yy $CurrentLogDataDir = $LogDataDir + $CurrentMonth $CurrentTime = get-date -format hh.mm.ss # Testing path exists to engine logging, if not creating it $ExportDataDirTestPath = test-path $CurrentLogDataDir $CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\VPGCreationLog-" + $CurrentTime + ".txt" if ($ExportDataDirTestPath -eq $False) { New-Item -ItemType Directory -Force -Path $CurrentLogDataDir } start-transcript -path $CurrentLogDataFile -NoClobber ################################################ # Connecting to vCenter - required for successful authentication with Zerto API ################################################ connect-viserver -Server $vCenterServer -User $vCenterUser -Password $vCenterPassword ################################################ # Building Zerto API string and invoking API ################################################ $BaseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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" Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $Headers -Method POST -Body $SessionBody -ContentType $TypeJSON } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } #Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $ZertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

Page 11: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 11 OF 134

3 QUERYING & REPORTING

3.1 Use Cases

A common use case of the API is to extend and configure custom reporting of data over long term periods, beyond the 24 hours retained within the Zerto Virtual Manager Database. The following APIs can be used to extract data:

• https://zvm_ip:port/v1/events

• https://zvm_ip:port/v1/alerts

• https://zvm_ip:port/v1/tasks

• https://zvm_ip:port/v1/vms

• https://zvm_ip:port/v1/vpgs

• https://zvm_ip:port/v1/vpgSettings

• https://zvm_ip:port/v1/vras • https://zvm_ip:port/ZvmService/ResourcesReport

With the ability to extract any data from the API the use cases are endless. Following are some commonly requested examples and how to use them. All the examples given presume you have already created the start of the script as the per section 2.9.

3.1 Listing Unprotected VMs

To list all VMs not currently protected by Zerto use the below script:

# Get SiteIdentifier $SiteInfoURL = $BaseURL+"localsite" $SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $ZertosessionHeader -ContentType $TypeJSON $LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier # Using SiteIdentifier to get a list on unprotected VMs $UnprotectedVMListURL = $BaseURL+"virtualizationsites/"+$LocalSiteIdentifier+"/vms" $UnprotectedVMList = Invoke-RestMethod -Uri $UnprotectedVMListURL -TimeoutSec 100 -Headers $ZertosessionHeader -ContentType $TypeJSON # Building table

$UnprotectedVMListTable = $UnprotectedVMList | select VmIdentifier, VmName $UnprotectedVMListTable | format-table -AutoSize

3.2 Using Unprotected VM IDs

When utilizing the Zerto API for unprotected VMs a list of VM names and Zerto VM identifiers is returned. To get further information

on the VMs from the vCenter the VM ID can be calculated using the following example:

# Connect to the source vCenter first # Creating array $UnprotectedVMArray = @() # Build the list of VMs using example in 3.1

foreach ($VM in $UnprotectedVMList)

{ # Getting vCenter VM ID from ZVR ID $VMName = $VM.VmName $VMZVRID = $VM.VmIdentifier $Separator = "." $VMZVRIDSplit = $VMZVRID.split($Separator) $VMID = $VMZVRIDSplit[1] $VMID = "VirtualMachine-" + $VMID

# Using vCenter VM ID to get more info $VMCluster = get-vm -Id $VMID | Get-Cluster | select -expandproperty Name -First 1 $VMInfo = get-vm -Id $VMID | select Folder,NumCPU,MemoryGB,HardDisks,NetworkAdapters,UsedSpaceGB -First 1 $VMFolder = $VMInfo.Folder $VMNumCPU = $VMInfo.NumCpu

Page 12: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 12 OF 134

$VMMemoryGB = $VMInfo.MemoryGB $VMMemoryGB = [math]::Round($VMMemoryGB,2) $VMHardDisks = $VMInfo.HardDisks.Count $VMNICS = $VMInfo.NetworkAdapters.Count $VMUsedSpaceGB = $VMInfo.UsedSpaceGB

$VMUsedSpaceGB = [math]::Round($VMUsedSpaceGB,2) # Building array line $UnprotectedVMArrayLine = new-object PSObject $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value "$VMName" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolder" -Value "$VMFolder" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMCluster" -Value "$VMCluster" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "NumCPU" -Value "$VMNumCPU" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "MemoryGB" -Value "$VMMemoryGB"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "NICS" -Value "$VMNICS" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "HardDisks" -Value "$VMHardDisks" $UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "UsedSpaceGB" -Value "$VMUsedSpaceGB" $UnprotectedVMArray += $UnprotectedVMArrayLine }

3.3 Listing Protected VMs & VPGs

Once Zerto is configured a common use case is to retrieve a list of protected VMs with their associated VPGs for email

reports or for integration into a separate platform. This can be achieved with:

# Querying API $VMListURL = $BaseURL+"vms"

$VMList = Invoke-RestMethod -Uri $VMListURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON $VMListTable = $VMList | select VmName, VpgName, UsedStorageInMB, SourceSite, TargetSite, Priority $VMListTable | format-table -AutoSize

Page 13: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 13 OF 134

3.4 Long Term RPO & Storage Reporting to CSV

A common request from customers is to maintain RPO history over many months. This can be achieved with the below example

which creates a new CSV file per ZORG per month and lists all of the VPGs assigned. If no ZORG is defined a NoZORG CSV is created.

The script can be scheduled to poll the information on an interval desired, but any interval of 5 minutes max is recommended to

avoid data ballooning:

################################################

# Configure the variables below

################################################

$ExportDataDir = "C:\ZVRAPIScript\"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

################################################

# Nothing to configure below here

################################################

################################################

# Setting Cert Policy - required for successful auth with the Zerto API without connecting to vsphere using PowerCLI

################################################

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 Zerto API string and invoking API

################################################

$BaseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

Try

{

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $Headers -Method POST -Body $SessionBody -ContentType $TypeJSON

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$ZertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept" = $TypeXML }

################################################

# Running main body of script

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentExportDataDir = $ExportDataDir + $CurrentMonth

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentExportDataDir

Page 14: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 14 OF 134

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentExportDataDir

}

# Build List of VPGs

$vpgListApiUrl = $baseURL+"vpgs"

$vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $ZertoSessionHeader -ContentType $TypeXML

# 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

# Building the array of data

$zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,ActualRPO,Status,vmscount,ProvisionedStorageInMB,UsedStorageInMB

# 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 $_.ProvisionedStorageInMB

$CurrentVPGArrayLine | Add-Member -MemberType NoteProperty -Name "UsedStorage" -Value $_.UsedStorageInMB

$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

}

# End of per VPG actions above

Page 15: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 15 OF 134

3.5 Resource Reports

The Resource Report API can be used to obtain a significant amount of data within Zerto on the configuration and usage of protected VMs. They can also be exported manually from the ZVM into an xls file and only show data for the VPGs replicating into the specified ZVM. The frequency on which resource report data is taken is controlled by the advanced settings within the ZVM, it is not a live view on the data unlike every other API used. In the examples given a 24-hour report sample is utilized for simplicity. The following data can be obtained from the API:

• ActiveGuestMemoryInMB - The active memory of the virtual machine.

• BandwidthInBytes - The average bandwidth used between two consecutive samples.

• ConsumedHostMemoryInMB - The amount of host memory consumed by the virtual machine.

• CpuLimitInMhz - The maximum MHz available for the CPUs in the virtual machine. • CpuReservedInMhz - The MHz reserved for use by the CPUs in the virtual machine.

• CpuUsedInMhz - The MHz used by the CPUs in the virtual machine.

• CrmId - The CRM identifier specified in Zerto Cloud Manager for an organization that uses a cloud service provider for recovery.

• MemoryInMB - The virtual machine defined memory.

• MemoryLimitInMB - The upper limit for this virtual machine’s memory allocation.

• MemoryReservedInMB - The guaranteed memory allocation for this virtual machine.

• NumberOfvCpu - The number of CPUs for the virtual machine.

• NumberOfVolumes - The number of volumes attached to the virtual machine.

• RecoveryJournalProvisionedStorageInGB - The amount of provisioned journal storage for the virtual machine.

• RecoveryJournalUsedStorageInGB - The amount of used journal storage for the virtual machine.

• RecoveryVolumesProvisionedStorageInGB - The amount of provisioned storage for the virtual machine in the target site. This value is the sum of volumes’ provisioned size.

• RecoveryVolumesUsedStorageInGB - The amount of used storage for the virtual machine in the target site.

• ServiceProfile - The service profile used by the VPG.

• SourceCluster - The source cluster name hosting the virtual machine.

• SourceHost - The source ESX/ESXi name hosting the virtual machine. • SourceOrgVDC - The name of the source vDC Org.

• SourceResourcePool - The source resource pool name hosting the virtual machine.

• SourceSite - The source protected site name, defined in the Zerto User Interface.

• SourceVCDOrg - The name of the source vCD Org.

• SourceVolumesProvisionedStorageInGB - The amount of provisioned storage for the virtual machine in the source site. This value is the sum of volumes’ provisioned size.

• SourceVolumesUsedStorageInGB - The amount of used storage for the virtual machine in the source site. This value is the sum of the volumes’ used size.

• SourceVraName - The name of the source VRA used to send data to the recovery site.

• StorageProfile - The target vCD storage profile used.

• TargetCluster - The target cluster name hosting the virtual machine.

• TargetDatastores - The target datastore used for the virtual machine if it is recovered.

• TargetHost - The target ESX/ESXi name hosting the virtual machine when it is recovered.

• TargetOrgVDC - The name of the target vDC Org

• TargetResourcePool - The target resource pool name where the virtual machine will be recovered.

• TargetSite - The target site name, defined in the Zerto User Interface. TargetVCDOrg - The name of the target vCD Org. TargetVraName - The name of the recovery VRA managing the recovery.

• ThroughputInBytes - The average throughput used between two consecutive samples.

• Timestamp - The date and time the resource information was collected.

• VmHardwareVersion - The VMware hardware version.

• VmId - The internal virtual machine identifier. The identifier comprises the server identifier and the virtual machine moref, with the format, serverid. moref.

Page 16: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 16 OF 134

• VmName - The name of the virtual machine.

• VpgName - The name of the VPG.

• VpgType - The VPG Type: VC2VC – vCenter to vCenter, VC2VCD – vCenter to vCloud Director, VCD2VCD – vCloud Director to vCloud Director, VCD2VC – vCloud Director to vCenter.

• ZORG - An organization set up in the Zerto Cloud Manager using a cloud service provider for recovery.

Following is an example querying a subset of the above data:

################################################

# Configure the variables below, use the recovery site ZVM

################################################

$ZertoServer = "192.168.0.32"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

################################################

# Setting Cert Policy - required for successful auth with the Zerto API without connecting to vsphere using PowerCLI

################################################

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 Zerto API string and invoking API

################################################

$BaseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

Try

{

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $Headers -Method POST -Body $SessionBody -ContentType $TypeJSON

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$ZertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# Setting end date to be midnight (as default time is 00:00) and start date is midnight last night for 24 hours of data

$StartDateTime = get-date -Format yyyy-MM-dd

$EndDateTime = (get-date).AddDays(1).ToString("yyyy-MM-dd")

# QueryResourceReport

$ResourceReportURLBase = "https://" + $ZertoServer + ":"+$ZertoPort + "/ZvmService/ResourcesReport/getSamples?fromTimeString="

$ResourceReportURL = $ResourceReportURLBase + $StartDateTime + "&toTimeString=" + $EndDateTime + "&startIndex=0&count=500"

$ResourceReport = Invoke-RestMethod -Uri $ResourceReportURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$ResourceReportAPIArray = $ResourceReport.ArrayOfVmResourcesInfo.VmResourcesInfo

# Building table from Array by VpgName

Page 17: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 17 OF 134

$ResourceReportAPITable = $ResourceReport | Sort-Object -Property VpgName | format-table -Property Timestamp,VpgName,VmName,TargetVraName

$ResourceReportAPITable

3.6 Resource Report Use Cases

Once you have successfully queried the resource report API many different use cases can be fulfilled. Note: when copying and pasting the below examples delete the line break inserted after “-Property” for the script to function correctly:

# Protected VMs by most RecoveryJournalUsedStorageInGB usage $ResourceReportAPITable = $ResourceReport | Sort-Object -Property RecoveryJournalUsedStorageInGB -Descending | format-table -Property Timestamp,VmName,VpgName, RecoveryJournalUsedStorageInGB,RecoveryVolumesUsedStorageInGB $ResourceReportAPITable # Protected VMs by most RecoveryVolumesStorageInGB usage $ResourceReportAPITable = $ResourceReport | Sort-Object -Property RecoveryVolumesUsedStorageInGB -Descending | format-table -Property Timestamp,VmName,VpgName,RecoveryVolumesProvisionedStorageInGB,RecoveryVolumesUsedStorageInGB $ResourceReportAPITable # Protected VMs by CPU and RAM size $ResourceReportAPITable = $ResourceReport | Sort-Object -Property NumberOfvCpu,MemoryInMB -Descending | format-table -Property Timestamp,VpgName,VmName,NumberOfvCpu,MemoryInMB,VmHardwareVersion $ResourceReportAPITable # Protected VMs by target host, then by CPU and RAM size, useful for balancing recovery $ResourceReportAPITable = $ResourceReport | Sort-Object -Property TargetHost,NumberOfvCpu,MemoryInMB -Descending | format-table -Property Timestamp,VpgName,VmName,TargetHost,NumberOfvCpu,MemoryInMB,VmHardwareVersion $ResourceReportAPITable # VMs replicating to a VRA with number of volumes per VM, useful for balancing replication $ResourceReportAPITable = $ResourceReport | Where-Object {$_.TargetVraName -eq "Z-VRA-192.168.0.14"} | format-table -Property Timestamp,VmName,VpgName,TargetVraName,NumberOfVolumes $ResourceReportAPITable # Protected VMs with a specific VM hardware version $ResourceReportAPITable = $ResourceReport | Where-Object {$_.VmHardwareVersion -eq "vmx-08"} | format-table -Property Timestamp,VmName,VpgName,VmHardwareVersion $ResourceReportAPITable # Protected VMs by highest average bandwidth usage (derived from time between samples) $ResourceReportAPITable = $ResourceReport | Sort-Object -Property BandwidthInBytes -Descending | format-table -Property Timestamp,VmName,VpgName,BandwidthInBytes $ResourceReportAPITable # Protected VMs to a specific datastore: $ResourceReportAPITable = $ResourceReport | Where-Object {$_.TargetDatastores -eq "ESXi2SATA"} | format-table -Property Timestamp,VmName,TargetDatastores,RecoveryVolumesUsedStorageInGB,RecoveryJournalUsedStorageInGB $ResourceReportAPITable

Page 18: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 18 OF 134

3.7 VPG, VM, VDISK, VNIC & Re-IP Settings Report

To report on all the settings configured within a VPG the Edit VPG API must be utilized. The API mimics the ZVM GUI which requires a VPG to be edited to view information such as re-ip settings per VM NIC. The example script creates 4 table arrays containing the report data. These are VPGArray, VMArray, VMVolumeArray and VMNICArray. 4 tables are required as multiple VMs can exist in a VPG and multiple vDISKs/VNICs can exist in a VM. The VPGidentifier and VMIdentifiers are used to link the table entries logically. Below are the example outputs in a CSV file from each of the 4 tables:

Page 19: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 19 OF 134

To build the example CSVs use the below script: ################################################

################################################

# Configure the variables below

################################################

$ExportDataDir = "C:\ZVRAPIScript\"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

########################################################################################################################

# Nothing to configure below this line - Starting the main function of the script

########################################################################################################################

################################################

# Setting certificate exception to prevent authentication issues to the ZVM

################################################

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 Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

Try

{

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

# Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertoSessionHeader_JSON = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

$zertoSessionHeader_XML = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeXML }

################################################

# Creating Arrays for populating ZVM info from the API

################################################

$VPGArray = @()

$VMArray = @()

$VMVolumeArray = @()

$VMNICArray = @()

################################################

# Creating VPGArray, VMArray, VMVolumeArray, VMNICArray

################################################

# URL to create VPG settings

Page 20: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 20 OF 134

$CreateVPGURL = $baseURL+"vpgSettings"

# Build List of VPGs

$vpgListApiUrl = $baseURL+"vpgs"

$vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

# Build List of VMs

$vmListApiUrl = $baseURL+"vms"

$vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

# Select IDs from the API array

$zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,vmscount,vpgidentifier

$vmListarray = $vmList.ArrayOfVmApi.VmApi | select-object *

################################################

# Starting for each VPG action of collecting ZVM VPG data

################################################

foreach ($VPGLine in $zertoprotectiongrouparray)

{

$VPGidentifier = $VPGLine.vpgidentifier

$VPGOrganization = $VPGLine.OrganizationName

$VPGVMCount = $VPGLine.VmsCount

$JSON =

"{

""VpgIdentifier"":""$VPGidentifier""

}"

################################################

# Posting the VPG JSON Request to the API

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertoSessionHeader_JSON

$ValidVPGSettingsIdentifier = $true

}

Catch {

$ValidVPGSettingsIdentifier = $false

}

################################################

# Getting VPG settings from API

################################################

# Skipping if unable to obtain valid VPG setting identifier

if ($ValidVPGSettingsIdentifier -eq $true)

{

$VPGSettingsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier

$VPGSettings = Invoke-RestMethod -Uri $VPGSettingsURL -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting recovery site ID (needed anyway for network settings)

$VPGRecoverySiteIdentifier = $VPGSettings.Basic.RecoverySiteIdentifier

# Getting site info

$VISitesURL = $baseURL+"virtualizationsites"

$VISitesCMD = Invoke-RestMethod -Uri $VISitesURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting network info

$VINetworksURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/networks"

$VINetworksCMD = Invoke-RestMethod -Uri $VINetworksURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting datastore info

$VIDatastoresURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/datastores"

$VIDatastoresCMD = Invoke-RestMethod -Uri $VIDatastoresURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting datastore cluster info

$VIDatastoreClustersURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/datastoreclusters"

$VIDatastoreClustersCMD = Invoke-RestMethod -Uri $VIDatastoreClustersURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting folder info

$VIFoldersURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/folders"

$VIFoldersCMD = Invoke-RestMethod -Uri $VIFoldersURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting cluster info

$VIClustersURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/hostclusters"

$VIClustersCMD = Invoke-RestMethod -Uri $VIClustersURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting host info

$VIHostsURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/hosts"

$VIHostsCMD = Invoke-RestMethod -Uri $VIHostsURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting resource pool info

$VIResourcePoolsURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/resourcepools"

Page 21: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 21 OF 134

$VIResourcePoolsCMD = Invoke-RestMethod -Uri $VIResourcePoolsURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting all VPG Settings

$VPGJournalHistoryInHours = $VPGSettings.Basic.JournalHistoryInHours

$VPGName = $VPGSettings.Basic.Name

$VPGPriortiy = $VPGSettings.Basic.Priority

$VPGProtectedSiteIdentifier = $VPGSettings.Basic.ProtectedSiteIdentifier

$VPGRpoInSeconds = $VPGSettings.Basic.RpoInSeconds

$VPGServiceProfileIdentifier = $VPGSettings.Basic.ServiceProfileIdentifier

$VPGTestIntervalInMinutes = $VPGSettings.Basic.TestIntervalInMinutes

$VPGUseWanCompression = $VPGSettings.Basic.UseWanCompression

$VPGZorgIdentifier = $VPGSettings.Basic.ZorgIdentifier

# Getting Boot Group IDs

$VPGBootGroups = $VPGSettings.BootGroups.BootGroups

$VPGBootGroupCount = $VPGSettings.BootGroups.BootGroups.Count

$VPGBootGroupNames = $VPGSettings.BootGroups.BootGroups.Name

$VPGBootGroupDelays = $VPGSettings.BootGroups.BootGroups.BootDelayInSeconds

$VPGBootGroupIdentifiers = $VPGSettings.BootGroups.BootGroups.BootGroupIdentifier

# Getting Journal info

$VPGJournalDatastoreClusterIdentifier = $VPGSettings.Journal.DatastoreClusterIdentifier

$VPGJournalDatastoreIdentifier = $VPGSettings.Journal.DatastoreIdentifier

$VPGJournalHardLimitInMB = $VPGSettings.Journal.Limitation.HardLimitInMB

$VPGJournalHardLimitInPercent = $VPGSettings.Journal.Limitation.HardLimitInPercent

$VPGJournalWarningThresholdInMB = $VPGSettings.Journal.Limitation.WarningThresholdInMB

$VPGJournalWarningThresholdInPercent = $VPGSettings.Journal.Limitation.WarningThresholdInPercent

# Getting Network IDs

$VPGFailoverNetworkID = $VPGSettings.Networks.Failover.Hypervisor.DefaultNetworkIdentifier

$VPGFailoverTestNetworkID = $VPGSettings.Networks.FailoverTest.Hypervisor.DefaultNetworkIdentifier

# Getting recovery info

$VPGDefaultDatastoreIdentifier = $VPGSettings.Recovery.DefaultDatastoreIdentifier

$VPGDefaultFolderIdentifier = $VPGSettings.Recovery.DefaultFolderIdentifier

$VPGDefaultHostClusterIdentifier = $VPGSettings.Recovery.DefaultHostClusterIdentifier

$VPGDefaultHostIdentifier = $VPGSettings.Recovery.DefaultHostIdentifier

$VPGResourcePoolIdentifier = $VPGSettings.Recovery.ResourcePoolIdentifier

# Getting scripting info

$VPGScriptingPreRecovery = $VPGSettings.Scripting.PreRecovery

$VPGScriptingPostRecovery = $VPGSettings.Scripting.PostRecovery

# Getting VM IDs in VPG

$VPGVMIdentifiers = $VPGSettings.VMs.VmIdentifier

################################################

# Translating Zerto IDs from VPG settings to friendly vSphere names

################################################

# Getting site names

$VPGProtectedSiteName = $VISitesCMD | Where-Object {$_.SiteIdentifier -eq $VPGProtectedSiteIdentifier} | select -ExpandProperty VirtualizationSiteName

$VPGRecoverySiteName = $VISitesCMD | Where-Object {$_.SiteIdentifier -eq $VPGRecoverySiteIdentifier} | select -ExpandProperty VirtualizationSiteName

# Getting network names

$VPGFailoverNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VPGFailoverNetworkID} | Select -ExpandProperty VirtualizationNetworkName

$VPGFailoverTestNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VPGFailoverTestNetworkID} | Select -ExpandProperty VirtualizationNetworkName

# Getting datastore cluster name

$VPGJournalDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VPGJournalDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore names

$VPGDefaultDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VPGDefaultDatastoreIdentifier} | select -ExpandProperty DatastoreName

$VPGJournalDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VPGJournalDatastoreIdentifier} | select -ExpandProperty DatastoreName

# Getting folder name

$VPGDefaultFolderName = $VIFoldersCMD | Where-Object {$_.FolderIdentifier -eq $VPGDefaultFolderIdentifier} | select -ExpandProperty FolderName

# Getting cluster name

$VPGDefaultHostClusterName = $VIClustersCMD | Where-Object {$_.ClusterIdentifier -eq $VPGDefaultHostClusterIdentifier} | select -ExpandProperty VirtualizationClusterName

# Getting host name

$VPGDefaultHostName = $VIHostsCMD | Where-Object {$_.HostIdentifier -eq $VPGDefaultHostIdentifier} | select -ExpandProperty VirtualizationHostName

# Getting resource pool name

$VPGResourcePoolName = $VIResourcePoolsCMD | Where-Object {$_.ResourcePoolIdentifier -eq $VPGResourcePoolIdentifier} | select -ExpandProperty ResourcepoolName

################################################

# Adding all VPG setting info to $VPGArray

################################################

$VPGArrayLine = new-object PSObject

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

Page 22: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 22 OF 134

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGOrganization" -Value $VPGOrganization

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGVMCount" -Value $VPGVMCount

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGPriortiy" -Value $VPGPriortiy

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGProtectedSiteName" -Value $VPGProtectedSiteName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGProtectedSiteIdentifier" -Value $VPGProtectedSiteIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRecoverySiteName" -Value $VPGRecoverySiteName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRecoverySiteIdentifier" -Value $VPGRecoverySiteIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRpoInSeconds" -Value $VPGRpoInSeconds

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGServiceProfileIdentifier" -Value $VPGServiceProfileIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGTestIntervalInMinutes" -Value $VPGTestIntervalInMinutes

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGUseWanCompression" -Value $VPGUseWanCompression

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGZorgIdentifier" -Value $VPGZorgIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupCount" -Value $VPGBootGroupCount

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupNames" -Value $VPGBootGroupNames

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupDelays" -Value $VPGBootGroupDelays

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupIdentifiers" -Value $VPGBootGroupIdentifiers

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHistoryInHours" -Value $VPGJournalHistoryInHours

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreClusterName" -Value $VPGJournalDatastoreClusterName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreClusterIdentifier" -Value $VPGJournalDatastoreClusterIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreName" -Value $VPGJournalDatastoreName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreIdentifier" -Value $VPGJournalDatastoreIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHardLimitInMB" -Value $VPGJournalHardLimitInMB

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHardLimitInPercent" -Value $VPGJournalHardLimitInPercent

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalWarningThresholdInMB" -Value $VPGJournalWarningThresholdInMB

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalWarningThresholdInPercent" -Value $VPGJournalWarningThresholdInPercent

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverNetworkName" -Value $VPGFailoverNetworkName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverNetworkID" -Value $VPGFailoverNetworkID

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverTestNetworkName" -Value $VPGFailoverTestNetworkName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverTestNetworkID" -Value $VPGFailoverTestNetworkID

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultDatastoreName" -Value $VPGDefaultDatastoreName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultDatastoreIdentifier" -Value $VPGDefaultDatastoreIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultFolderName" -Value $VPGDefaultFolderName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultFolderIdentifier" -Value $VPGDefaultFolderIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostClusterName" -Value $VPGDefaultHostClusterName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostClusterIdentifier" -Value $VPGDefaultHostClusterIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostName" -Value $VPGDefaultHostName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostIdentifier" -Value $VPGDefaultHostIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGResourcePoolName" -Value $VPGResourcePoolName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGResourcePoolIdentifier" -Value $VPGResourcePoolIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGScriptingPreRecovery" -Value $VPGScriptingPreRecovery

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGScriptingPostRecovery" -Value $VPGScriptingPostRecovery

$VPGArray += $VPGArrayLine

################################################

# Starting for each VM ID action for collecting ZVM VM data

################################################

foreach ($_ in $VPGVMIdentifiers)

{

$VMIdentifier = $_

# Get VMs settings

$GetVMSettingsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier

$GetVMSettings = Invoke-RestMethod -Method Get -Uri $GetVMSettingsURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting the VM name and disk usage

$VMNameArray = $vmListarray | where-object {$_.VmIdentifier -eq $VMIdentifier} | Select-Object *

$VMName = $VMNameArray.VmName

$VMProvisionedStorageInMB = $VMNameArray.ProvisionedStorageInMB

$VMUsedStorageInMB = $VMNameArray.UsedStorageInMB

# Setting variables from the API

$VMVolumeCount = $GetVMSettings.Volumes.Count

$VMNICCount = $GetVMSettings.Nics.Count

$VMBootGroupIdentifier = $GetVMSettings.BootGroupIdentifier

$VMJournalDatastoreClusterIdentifier = $GetVMSettings.Journal.DatastoreClusterIdentifier

$VMJournalDatastoreIdentifier = $GetVMSettings.Journal.DatastoreIdentifier

$VMJournalHardLimitInMB = $GetVMSettings.Journal.Limitation.HardLimitInMB

$VMJournalHardLimitInPercent = $GetVMSettings.Journal.Limitation.HardLimitInPercent

$VMJournalWarningThresholdInMB = $GetVMSettings.Journal.Limitation.WarningThresholdInMB

$VMJournalWarningThresholdInPercent = $GetVMSettings.Journal.Limitation.WarningThresholdInPercent

Page 23: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 23 OF 134

$VMDatastoreClusterIdentifier = $GetVMSettings.Recovery.DatastoreClusterIdentifier

$VMDatastoreIdentifier = $GetVMSettings.Recovery.DatastoreIdentifier

$VMFolderIdentifier = $GetVMSettings.Recovery.FolderIdentifier

$VMHostClusterIdentifier = $GetVMSettings.Recovery.HostClusterIdentifier

$VMHostIdentifier = $GetVMSettings.Recovery.HostIdentifier

$VMResourcePoolIdentifier = $GetVMSettings.Recovery.ResourcePoolIdentifier

################################################

# Translating Zerto IDs from VM settings to friendly vSphere names

################################################

# Getting boot group

$VMBootGroupName = $VPGBootGroups | Where-Object {$_.BootGroupIdentifier -eq $VMBootGroupIdentifier} | select -ExpandProperty Name

$VMBootGroupDelay = $VPGBootGroups | Where-Object {$_.BootGroupIdentifier -eq $VMBootGroupIdentifier} | select -ExpandProperty BootDelayInSeconds

# Getting datastore cluster name

$VMJournalDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMJournalDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

$VMDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore name

$VMJournalDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMJournalDatastoreIdentifier} | select -ExpandProperty DatastoreName

$VMDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMDatastoreIdentifier} | select -ExpandProperty DatastoreName

# Getting folder name

$VMFolderName = $VIFoldersCMD | Where-Object {$_.FolderIdentifier -eq $VMFolderIdentifier} | select -ExpandProperty FolderName

# Getting cluster name

$VMHostClusterName = $VIClustersCMD | Where-Object {$_.ClusterIdentifier -eq $VMHostClusterIdentifier} | select -ExpandProperty VirtualizationClusterName

# Getting host name

$VMHostName = $VIHostsCMD | Where-Object {$_.HostIdentifier -eq $VMHostIdentifier} | select -ExpandProperty VirtualizationHostName

# Getting resource pool name

$VMResourcePoolName = $VIResourcePoolsCMD | Where-Object {$_.ResourcePoolIdentifier -eq $VMResourcePoolIdentifier} | select -ExpandProperty ResourcepoolName

################################################

# Adding all VM setting info to $VMArray

################################################

$VMArrayLine = new-object PSObject

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICCount" -Value $VMNICCount

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeCount" -Value $VMVolumeCount

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMProvisionedStorageInMB" -Value $VMProvisionedStorageInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMUsedStorageInMB" -Value $VMUsedStorageInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupName" -Value $VMBootGroupName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupDelay" -Value $VMBootGroupDelay

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupIdentifier" -Value $VMBootGroupIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreClusterName" -Value $VMJournalDatastoreClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreClusterIdentifier" -Value $VMJournalDatastoreClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreName" -Value $VMJournalDatastoreName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreIdentifier" -Value $VMJournalDatastoreIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalHardLimitInMB" -Value $VMJournalHardLimitInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalHardLimitInPercent" -Value $VMJournalHardLimitInPercent

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreClusterName" -Value $VMDatastoreClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreClusterIdentifier" -Value $VMDatastoreClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreName" -Value $VMDatastoreName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreIdentifier" -Value $VMDatastoreIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolderName" -Value $VMFolderName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolderIdentifier" -Value $VMFolderIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostClusterName" -Value $VMHostClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostClusterIdentifier" -Value $VMHostClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostName" -Value $VMHostName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostIdentifier" -Value $VMHostIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMResourcePoolName" -Value $VMResourcePoolName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMResourcePoolIdentifier" -Value $VMResourcePoolIdentifier

$VMArray += $VMArrayLine

################################################

# Get VM Volume settings for the current VPG

################################################

$GetVMSettingVolumesURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/volumes"

$GetVMSettingVolumes = Invoke-RestMethod -Method Get -Uri $GetVMSettingVolumesURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

$GetVMSettingVolumeIDs = $GetVMSettingVolumes.ArrayOfVpgSettingsVmVolumeApi.VpgSettingsVmVolumeApi | select-object VolumeIdentifier -ExpandProperty VolumeIdentifier

Page 24: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 24 OF 134

################################################

# Starting for each VM Volume ID action for collecting ZVM VM Volume data

################################################

foreach ($_ in $GetVMSettingVolumeIDs)

{

$VMVolumeID = $_

# Getting API data for volume

$GetVMSettingVolumeURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/volumes/"+$VMVolumeID

$GetVMSettingVolume = Invoke-RestMethod -Method Get -Uri $GetVMSettingVolumeURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

# Setting values

$VMVolumeDatastoreClusterIdentifier = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.DatastoreClusterIdentifier

$VMVolumeDatastoreIdentifier = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.DatastoreIdentifier

$VMVolumeIsSWAP = $GetVMSettingVolume.VpgSettingsVmVolumeApi.IsSwap

$VMVolumeIsThin = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.IsThin

# Getting datastore cluster name

$VMVolumeDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMVolumeDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore name

$VMVolumeDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMVolumeDatastoreIdentifier} | select -ExpandProperty DatastoreName

################################################

# Adding all VM Volume setting info to $VMVolumeArray

################################################

$VMVolumeArrayLine = new-object PSObject

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeID" -Value $VMVolumeID

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeIsSWAP" -Value $VMVolumeIsSWAP

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeIsThin" -Value $VMVolumeIsThin

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreClusterName" -Value $VMVolumeDatastoreClusterName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreClusterIdentifier" -Value $VMVolumeDatastoreClusterIdentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreName" -Value $VMVolumeDatastoreName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreIdentifier" -Value $VMVolumeDatastoreIdentifier

$VMVolumeArray += $VMVolumeArrayLine

}

################################################

# Get VM Nic settings for the current VPG

################################################

$GetVMSettingNICsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics"

$GetVMSettingNICs = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICsURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

$VMNICIDs = $GetVMSettingNICs.ArrayOfVpgSettingsVmNicApi.VpgSettingsVmNicApi | select-object NicIdentifier -ExpandProperty NicIdentifier

################################################

# Starting for each VM NIC ID action for collecting ZVM VM NIC data

################################################

foreach ($_ in $VMNICIDs)

{

$VMNICIdentifier = $_

$GetVMSettingNICURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics/"+$VMNICIdentifier

$GetVMSettingNIC = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

# Building arrays

$VMSettingNICIDArray1 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor

$VMSettingNICIDArray2 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor.IpConfig

$VMSettingNICIDArray3 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor

$VMSettingNICIDArray4 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor.IpConfig

# Setting failover values

$VMNICFailoverDNSSuffix = $VMSettingNICIDArray1.DnsSuffix

$VMNICFailoverNetworkIdentifier = $VMSettingNICIDArray1.NetworkIdentifier

$VMNICFailoverShouldReplaceMacAddress = $VMSettingNICIDArray1.ShouldReplaceMacAddress

$VMNICFailoverGateway = $VMSettingNICIDArray2.Gateway

$VMNIsFailoverDHCP = $VMSettingNICIDArray2.IsDhcp

$VMNICFailoverPrimaryDns = $VMSettingNICIDArray2.PrimaryDns

$VMNICFailoverSecondaryDns = $VMSettingNICIDArray2.SecondaryDns

$VMNICFailoverStaticIp = $VMSettingNICIDArray2.StaticIp

$VMNICFailoverSubnetMask = $VMSettingNICIDArray2.SubnetMask

# Nulling blank content

if ($VMNICFailoverDNSSuffix.nil -eq $true){$VMNICFailoverDNSSuffix = $null}

Page 25: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 25 OF 134

if ($VMNICFailoverGateway.nil -eq $true){$VMNICFailoverGateway = $null}

if ($VMNICFailoverPrimaryDns.nil -eq $true){$VMNICFailoverPrimaryDns = $null}

if ($VMNICFailoverSecondaryDns.nil -eq $true){$VMNICFailoverSecondaryDns = $null}

if ($VMNICFailoverStaticIp.nil -eq $true){$VMNICFailoverStaticIp = $null}

if ($VMNICFailoverSubnetMask.nil -eq $true){$VMNICFailoverSubnetMask = $null}

# Setting failover test values

$VMNICFailoverTestDNSSuffix = $VMSettingNICIDArray3.DnsSuffix

$VMNICFailoverTestNetworkIdentifier = $VMSettingNICIDArray3.NetworkIdentifier

$VMNICFailoverTestShouldReplaceMacAddress = $VMSettingNICIDArray3.ShouldReplaceMacAddress

$VMNICFailoverTestGateway = $VMSettingNICIDArray4.Gateway

$VMNIsFailoverTestDHCP = $VMSettingNICIDArray4.IsDhcp

$VMNICFailoverTestPrimaryDns = $VMSettingNICIDArray4.PrimaryDns

$VMNICFailoverTestSecondaryDns = $VMSettingNICIDArray4.SecondaryDns

$VMNICFailoverTestStaticIp = $VMSettingNICIDArray4.StaticIp

$VMNICFailoverTestSubnetMask = $VMSettingNICIDArray4.SubnetMask

# Nulling blank content

if ($VMNICFailoverTestDNSSuffix.nil -eq $true){$VMNICFailoverTestDNSSuffix = $null}

if ($VMNICFailoverTestGateway.nil -eq $true){$VMNICFailoverTestGateway = $null}

if ($VMNICFailoverTestPrimaryDns.nil -eq $true){$VMNICFailoverTestPrimaryDns = $null}

if ($VMNICFailoverTestSecondaryDns.nil -eq $true){$VMNICFailoverTestSecondaryDns = $null}

if ($VMNICFailoverTestStaticIp.nil -eq $true){$VMNICFailoverTestStaticIp = $null}

if ($VMNICFailoverTestSubnetMask.nil -eq $true){$VMNICFailoverTestSubnetMask = $null}

# Mapping Network IDs to Names

$VMNICFailoverNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

$VMNICFailoverTestNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverTestNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

################################################

# Adding all VM NIC setting info to $VMNICArray

################################################

$VMNICArrayLine = new-object PSObject

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICIdentifier" -Value $VMNICIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverNetworkName" -Value $VMNICFailoverNetworkName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverNetworkIdentifier" -Value $VMNICFailoverNetworkIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDNSSuffix" -Value $VMNICFailoverDNSSuffix

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverShouldReplaceMacAddress" -Value $VMNICFailoverShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverGateway" -Value $VMNICFailoverGateway

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDHCP" -Value $VMNIsFailoverDHCP

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverPrimaryDns" -Value $VMNICFailoverPrimaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSecondaryDns" -Value $VMNICFailoverSecondaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverStaticIp" -Value $VMNICFailoverStaticIp

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSubnetMask" -Value $VMNICFailoverSubnetMask

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestNetworkName" -Value $VMNICFailoverTestNetworkName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestNetworkIdentifier" -Value $VMNICFailoverTestNetworkIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDNSSuffix" -Value $VMNICFailoverTestDNSSuffix

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestShouldReplaceMacAddress" -Value $VMNICFailoverTestShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestGateway" -Value $VMNICFailoverTestGateway

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDHCP" -Value $VMNIsFailoverTestDHCP

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestPrimaryDns" -Value $VMNICFailoverTestPrimaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSecondaryDns" -Value $VMNICFailoverTestSecondaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestStaticIp" -Value $VMNICFailoverTestStaticIp

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSubnetMask" -Value $VMNICFailoverTestSubnetMask

$VMNICArray += $VMNICArrayLine

# End of per VM NIC actions below

}

# End of per VM NIC actions above

#

# End of per VM actions below

}

# End of per VM actions above

################################################

# Deleting VPG edit settings ID (same as closing the edit screen on a VPG in the ZVM without making any changes)

################################################

Try

Page 26: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 26 OF 134

{

Invoke-RestMethod -Method Delete -Uri $VPGSettingsURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML

}

Catch [system.exception]

{

}

#

# End of check for valid VPG settings ID below

}

# End of check for valid VPG settings ID above

#

# End of per VPG actions below

}

# End of per VPG actions above

#

################################################

# Showing Results - edit here for export commands etc

################################################

write-host "VPG Array:"

$VPGArray | fl

write-host "VM Array:"

$VMArray | fl

write-host "VM VOlume Array:"

$VMVolumeArray | fl

write-host "VM NIC Array:"

$VMNICArray | fl

# Exporting results

# Exporting arrays to CSV

$VPGArray | export-csv $ExportDataDir"VPGArray.csv" -NoTypeInformation

$VMArray | export-csv $ExportDataDir"VMArray.csv" -NoTypeInformation

$VMVolumeArray | export-csv $ExportDataDir"VMVolumeArray.csv" -NoTypeInformation

$VMNICArray | export-csv $ExportDataDir"VMNICArray.csv" -NoTypeInformation

Page 27: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 27 OF 134

4 DAILY EMAIL REPORTS

4.1 Use Cases

Utilizing the examples from section 3.0 makes it possible to build daily email reports of the vital information consolidated from

multiple Zerto installations. These email reports can contain data from both the Zerto Virtual Manager (ZVM) and vCenter to give a

complete view of the data required. Some example examples include:

• Summary of protected and unprotected VMs and VPGs across multiple vCenters and ZVMs

• VPG report with current RPO and status

• Protected VM report with current RPO and status

• Unprotected VM report with configuration statistics

• Target VRA load

• Target Datastore load

• All VPG and VM settings

4.2 Design Methodology

To support reporting across multiple vCenters and ZVMs, each combination is referred to as a POD in the example script. I.E Site1

vCenter and ZVM is ZVRPRODPOD1 and Site 2 is ZVRDRPOD1, this is repeated twice to show the ability to report on multiple PODs

and should be configured to your own environment settings.

4.3 Daily Email Report

Following is a complete example script with comments on configuration required:

################################################

# Description:

# This script automates the creation of multiple reports across many Zerto Virtual Managers and vCenters

################################################

# Requirements:

# 1. Run PowerShell as administrator with command "Set-ExecutionPolcity unrestricted"

# 2. Verify script server has connectivity to all vCenters, ZVMs and an SMTP server

# 3. Install VMware PowerCLI 6.0

# 4. Configure variables in “Set Credentials for all vCenters & ZVMs”, “SMTP Email Profile Settings” and set “Creating vCenter & ZVM Mappings to report on”

# 5. Credentials configured have read access to vCenter and view/edit VPG permissions in ZVM

# 6. To store credentials securely consider using:

# https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Encryption-45709b87

# 7. The password needs to be decrypted for use by the Zerto API which sends it over HTTPs to keep it secure

# 8. Add additional email lists if required and increment the number

# 9. Each combination of a vCenters and ZVM is referred to as a POD, add your PODs into the Create-vCenterArray function on line 24 and remove eisting

# 10. Start with default reports and customize from line 2500

# 11. Run the script manually or schedule using windows task scheduler

# 12. Recommended to run for the first time in PowerShell ISE for troubleshooting

# 13. The script isn’t configured to use transcription for logging of exceptions

################################################

# Set Credentials for all vCenters & ZVMs

################################################

$Username = "[email protected]"

$Password = "Zerto1234!"

$CSVDirectory = "C:\ZVRReports\"

# Configure target ZVM resource report sampling rate, by default daily, if left as daily then set the below to false and all ZVMs should be configured to the same setting

$ResourceReportHourlySample = "TRUE"

################################################

# SMTP Email Profile Settings

################################################

$EmailList1 = "[email protected]"

$EmailFrom = "[email protected]"

$SMTPServer = "localhost"

Page 28: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 28 OF 134

$SMTPPort = "25"

$SMTPUser = "username"

$SMTPPassword = "password"

$SMTPSSLEnabled = "FALSE"

# Creating SMTP Profiles

$SMTPProfile1 = @("$EmailFrom",“$SMTPServer”,”$SMTPPort”,”$SMTPUser”,”$SMTPPassword”,”$SMTPSSLEnabled”)

################################################

# Creating vCenter & ZVM Mappings to report on - change this to match environment

################################################

Function Create-vCenterArray{

$vCenterArray = @()

# Zerto Demo LAB 1

$vCenterArrayLine = new-object PSObject

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value "ZVRPRODPOD1"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourcevCenter" -Value "192.168.0.81"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourceZVM" -Value "192.168.0.31"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetPOD" -Value "ZVRDRPOD1"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetvCenter" -Value "192.168.0.82"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetZVM" -Value "192.168.0.32"

$vCenterArray += $vCenterArrayLine

# Zerto Demo LAB 2

$vCenterArrayLine = new-object PSObject

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value "ZVRPRODPOD2"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourcevCenter" -Value "192.168.0.81"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "SourceZVM" -Value "192.168.0.31"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetPOD" -Value "ZVRDRPOD2"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetvCenter" -Value "192.168.0.82"

$vCenterArrayLine | Add-Member -MemberType NoteProperty -Name "TargetZVM" -Value "192.168.0.32"

$vCenterArray += $vCenterArrayLine

# Outputting array to function

$vCenterArray

}

# Running function created

$vCenterArray = Create-vCenterArray

################################################################################################################################################

# Nothing to configure below this line to receive the default reports

################################################################################################################################################

################################################

# Building HTML settings for Email reports

################################################

$TableFont = "#FFFFFF"

$TableBackground = "#B20000"

$TableBorder = "#e60000"

$ReportHTMLTableStyle = @"

<style type="text/css">

.tg {border-collapse:collapse;border-spacing:0;border-color:#aaa;}

.tg td{font-family:Arial, sans-serif;font-size:10px;padding:10px 5px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;border-color:#aaa;color:#333;background-color:#ffffff;border-top-width:1px;border-bottom-width:1px;}

.tg th{font-family:Arial, sans-serif;font-size:10px;font-weight:bold;padding:10px 5px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;border-color:#aaa;color:$TableFont ;background-color:$TableBorder;border-top-width:1px;border-bottom-width:1px;}

.tg .tg-foxd{background-color:$TableBackground;vertical-align:top;text-align:left}

.tg .tg-yw4l{vertical-align:top}

.caption {font-family:Arial, sans-serif;font-size:11px;font-weight:bold;color:$TableFont;}

</style>

"@

################################################

# Creating CSV Save Function

################################################

Function Save-CSV{

Param($Array,$CSVFileName,$CSVDirectory)

# Saving file to directory specified then returning file name to use for email

$Timestamp = get-date

$Now = $TimeStamp.ToString("yyyy-MM-dd HH-mm-ss ")

$CSVName = $Now + $CSVFileName

$CSVFile = $CSVDirectory + $CSVName + ".csv"

$Array | Export-CSV -NoTypeInformation $CSVFile

$CSVFile

}

Page 29: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 29 OF 134

################################################

# Creating Time function

################################################

Function Get-Time{

$Timestamp = get-date

$Now = $TimeStamp.ToString("yyyy-MM-dd HH-mm-ss ")

$Now

}

################################################

# Creating Email Function

################################################

Function Email-ZVRReport{

Param($EmailTo,$Subject,$Body,$Attachment,$SMTPProfile)

# Getting SMTP Profile Settings

$EmailFrom = $SMTPProfile[0]

$SMTPServer = $SMTPProfile[1]

$SMTPPort = $SMTPProfile[2]

$SMTPUser = $SMTPProfile[3]

$SMTPPassword = $SMTPProfile[4]

$SMTPSSLEnabled = $SMTPProfile[5]

# Building SMTP settings based on settings

$emailsetting = New-Object System.Net.Mail.MailMessage

$emailsetting.to.add($EmailTo)

$emailsetting.from = $EmailFrom

$emailsetting.IsBodyHTML = "TRUE"

$emailsetting.subject = $Subject

$emailsetting.body = $Body

# Adding attachments

if ($Attachment -ne $null)

{

# Performing for each to support multiple attachments

foreach ($_ in $Attachment)

{

$emailattachmentsetting = new-object System.Net.Mail.Attachment $_

$emailsetting.attachments.add($emailattachmentsetting)

# invoke-expression $AttachmentCommand

# End of for each attachment below

}

# End of for each attachment above

}

# Creating SMTP object

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);

# Enabling SSL if set

if ($SMTPSSLEnabled -eq "TRUE")

{

$smtp.EnableSSL = "TRUE"

}

# Setting credentials

$smtp.Credentials = New-Object System.Net.NetworkCredential($SMTPUser, $SMTPPassword);

# Sending the Email

Try

{

$smtp.send($emailsetting)

}

Catch [system.exception]

{

# Trying email again

$smtp.send($emailsetting)

}

# End of email function

}

################################################

# Creating Report arrays

################################################

$ProtectedVPGArray = @()

$ProtectedVMArray = @()

Page 30: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 30 OF 134

$TargetVRAArray = @()

$UnprotectedVMArray = @()

$TargetDatastoreArray = @()

$VPGArray = @()

$VMArray = @()

$VMVolumeArray = @()

$VMNICArray = @()

$PODSummaryArray = @()

################################################

# Creating Vm Status Array

################################################

Function Create-VMStatusArray {

$VMStatusArray = @()

# Status 0

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "0"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Initializing"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is being initialized. This includes when a VPG is created and during initial sync."

$VMStatusArray += $VMStatusArrayLine

# Status 1

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "1"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "MeetingSLA"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is meeting the SLA specification."

$VMStatusArray += $VMStatusArrayLine

# Status 2

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "2"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "NotMeetingSLA"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is not meeting the SLA for both the journal history and RPO SLA settings."

$VMStatusArray += $VMStatusArrayLine

# Status 3

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "3"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "HistoryNotMeetingSLA"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is not meeting the SLA specification for the journal history."

$VMStatusArray += $VMStatusArrayLine

# Status 4

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "4"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "RpoNotMeetingSLA"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is not meeting the SLA specification for the RPO SLA setting."

$VMStatusArray += $VMStatusArrayLine

# Status 5

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "5"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "FailingOver"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is in a Failover operation."

$VMStatusArray += $VMStatusArrayLine

# Status 6

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "6"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Moving"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is in a Move operation."

$VMStatusArray += $VMStatusArrayLine

# Status 7

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "7"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Deleting"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG is being deleted."

$VMStatusArray += $VMStatusArrayLine

# Status 8

$VMStatusArrayLine = new-object PSObject

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "8"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Recovered"

$VMStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "The VPG has been recovered."

Page 31: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 31 OF 134

$VMStatusArray += $VMStatusArrayLine

# Outputting array to function

$VMStatusArray

}

# Running function created

$VMStatusArray = Create-VMStatusArray

################################################

# Creating Event Status Array

################################################

Function Create-EventStatusArray {

$EventStatusArray = @()

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "14"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "STR0001"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Datastore not accessible"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "15"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "STR0002"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Datastore is full"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "16"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "STR0004"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Datastore low in space"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "32"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0003"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG has low journal history"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "33"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0004"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG has low journal history"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "34"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0005"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG in error state"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "35"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0006"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG missing configuration details"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "36"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0007"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG replication paused"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "37"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0008"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG rollback failed"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 32: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 32 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "38"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0009"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG target RPO exceeded"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "39"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0010"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG target RPO exceeded"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "40"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0011"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG test overdue"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "41"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0012"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG test overdue"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "42"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0014"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG waiting for commit or rollback"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "43"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0015"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Resources not enough to support VPG "

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "44"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0016"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Resources pool not found"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "45"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0017"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG protection paused"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "46"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0018"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VMs in VPG not configured with a storage profile"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "47"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0019"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile disabled"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "48"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0020"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile not found"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 33: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 33 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "49"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0021"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile not found"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "50"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0022"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile disabled"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "51"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0023"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile not found"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "52"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0024"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile does not include active datastores"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "53"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0025"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "vApp network mapping not defined"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "54"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0026"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery storage profile changed"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "55"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0027"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG includes VMs that are no longer protected"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "56"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0028"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Corrupted Org vDC network mapping"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "57"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0035"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG protected resources not in ZORG"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "58"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0036"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VPG recovery resources not in ZORG"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "59"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0037"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal history is compromised"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 34: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 34 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "60"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0038"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal history is compromised"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "61"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0039"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "RDM has an odd number of blocks"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "62"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0040"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Virtual machine hardware mismatch with recovery site"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "63"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0041"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Virtual machine running Windows 2003"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "64"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0042"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery network not found"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "65"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VPG0043"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Cross-replication"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "66"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0001"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Host without VRA"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "67"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0002"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA without IP"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "68"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0003"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Host IP changes"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "69"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0004"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA lost IP"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "70"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0005"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRAs not connected"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 35: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 35 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "71"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0006"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Datastore for journal disk is full"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "72"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0007"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "I/O error to journal"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "73"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0008"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery disk and VMs missing"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "74"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0009"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery disk missing"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "75"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0010"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery disks turned off"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "76"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0011"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery disk inaccessible"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "77"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0012"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Cannot write to recovery disk"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "78"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0013"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "I/O error to recovery disk"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "79"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0014"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Cloned disks turned off"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "80"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0015"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Cloned disk inaccessible"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "81"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0016"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Datastore for clone disk is full"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 36: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 36 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "82"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0017"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "I/O error to clone"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "83"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0018"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Protected disk and VM missing"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "84"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0019"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Protected disk missing"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "85"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0020"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VM powered off"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "86"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0021"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VM disk inaccessible"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "87"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0022"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VM disk incompatible"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "88"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0023"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA cannot be registered"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "89"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0024"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA removed"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "90"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0025"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "I/O synchronization"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "91"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0026"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Recovery disk removed"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "92"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0027"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal disk removed"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 37: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 37 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "93"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0028"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA powered off"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "94"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0029"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA memory low"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "95"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0030"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal size mismatch"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "96"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0032"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA out-of-date"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "97"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0035"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "VRA reconciliation"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "98"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0037"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Local MAC Address Conflict"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "99"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0038"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "MAC Address Conflict"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "100"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0039"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal reached configured limit"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "101"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0040"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Journal space low"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "102"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0049"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Host rollback failed"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "103"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "VRA0050"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Wrong host password"

$EventStatusArray += $EventStatusArrayLine

# Status line

Page 38: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 38 OF 134

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "108"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0001"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "No connection to hypervisor manager"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "109"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0002"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "No connection to VRA"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "110"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0003"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "No connection to site"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "111"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0004"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Peer site out-of-date"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "112"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0005"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Zerto Virtual Manager space low"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "113"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0006"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Upgrade available"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "114"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0007"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Cannot upgrade"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "115"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0008"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Version mismatch"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "116"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0009"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Internal error"

$EventStatusArray += $EventStatusArrayLine

# Status line

$EventStatusArrayLine = new-object PSObject

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "117"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Identifier" -Value "ZVM0010"

$EventStatusArrayLine | Add-Member -MemberType NoteProperty -Name "Description" -Value "Synchronization between Zerto Virtual Managers"

$EventStatusArray += $EventStatusArrayLine

# Outputting

$EventStatusArray

}

# Running function created

$EventStatusArray = Create-EventStatusArray

################################################

# Creating Priority Array

Page 39: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 39 OF 134

################################################

Function Create-VMPriorityArray {

$VMPriorityArray = @()

# Priority 1

$VMPriorityArrayLine = new-object PSObject

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "1"

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "High"

$VMPriorityArray += $VMPriorityArrayLine

# Priority 2

$VMPriorityArrayLine = new-object PSObject

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "2"

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Medium"

$VMPriorityArray += $VMPriorityArrayLine

# Priority 3

$VMPriorityArrayLine = new-object PSObject

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Number" -Value "3"

$VMPriorityArrayLine | Add-Member -MemberType NoteProperty -Name "Name" -Value "Low"

$VMPriorityArray += $VMPriorityArrayLine

# Outputting

$VMPriorityArray

}

$VMPriorityArray = Create-VMPriorityArray

################################################

# Building Reports per POD

################################################

foreach ($POD in $vCenterArray)

{

# Setting variables

$SourcePOD = $POD.SourcePOD

$SourcevCenter = $POD.SourcevCenter

$SourceZVM = $POD.SourceZVM

$TargetPOD = $POD.TargetPOD

$TargetvCenter = $POD.TargetvCenter

$TargetZVM = $POD.TargetZVM

################################################

# Connecting to source vCenter for source VM info

################################################

Try

{

write-host "Connecting to vCenter:$SourcevCenter"

connect-viserver -Server $SourcevCenter -User $Username -Password $Password

$SourcevCenterAuthentication = "PASS"

}

Catch {

$SourcevCenterAuthentication = "FAIL"

}

# Connecting to Target vCenter for target info

Try

{

connect-viserver -Server $TargetvCenter -User $Username -Password $Password

$TargetvCenterAuthentication = "PASS"

}

Catch {

$TargetvCenterAuthentication = "FAIL"

}

# Catching failed vCenter authentication, only running reports for POD if it passses

if (($TargetvCenterAuthentication -eq "PASS") -and ($SourcevCenterAuthentication -eq "PASS"))

{

################################################

# Setting Cert Policy - required for successful auth with the Source Zerto API

################################################

add-type @"

using System.Net;

using System.Security.Cryptography.X509Certificates;

public class TrustAllCertsPolicy : ICertificatePolicy {

public bool CheckValidationResult(

Page 40: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 40 OF 134

ServicePoint srvPoint, X509Certificate certificate,

WebRequest request, int certificateProblem) {

return true;

}

}

"@

[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

################################################

# Building Source Zerto API string and invoking API

################################################

$SourceZVMBaseURL = "https://" + $SourceZVM + ":"+"9669"+"/v1/"

# Authenticating with Zerto APIs

$SourceZVMSessionURL = $SourceZVMBaseURL + "session/add"

$SourceZVMAuthInfo = ("{0}:{1}" -f $Username,$Password)

$SourceZVMAuthInfo = [System.Text.Encoding]::UTF8.GetBytes($SourceZVMAuthInfo)

$SourceZVMAuthInfo = [System.Convert]::ToBase64String($SourceZVMAuthInfo)

$SourceZVMHeaders = @{Authorization=("Basic {0}" -f $SourceZVMAuthInfo)}

$SourceZVMSessionBody = '{"AuthenticationMethod": "1"}'

$TypeJSON = "application/json"

$TypeXML = "application/xml"

Try

{

$SourceZVMSessionResponse = Invoke-WebRequest -Uri $SourceZVMSessionURL -Headers $SourceZVMHeaders -Method POST -Body $SourceZVMSessionBody -ContentType $TypeJSON

$SourceZVMAuthentication = "PASS"

}

Catch {

$SourceZVMAuthentication = "FAIL"

}

#Extracting x-zerto-session from the response, and adding it to the actual API

$SourceZVMSession = $SourceZVMSessionResponse.headers.get_item("x-zerto-session")

$SourceZVMSessionHeader_JSON = @{"x-zerto-session"=$SourceZVMSession; "Accept"=$TypeJSON}

$SourceZVMSessionHeader_XML = @{"x-zerto-session"=$SourceZVMSession; "Accept"=$TypeXML}

if ($SourceZVMAuthentication -eq "PASS")

{

# Get SiteIdentifier for later in the script

$SourceSiteInfoURL = $SourceZVMBaseURL+"localsite"

$SourceSiteInfoCMD = Invoke-RestMethod -Uri $SourceSiteInfoURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

$SourceLocalSiteIdentifier = $SourceSiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

}

################################################

# Setting Cert Policy for 2nd API call - required for successful auth with Target Zerto API - has to be run again

################################################

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 Taret Zerto API string and invoking API

################################################

$TargetZVMBaseURL = "https://" + $TargetZVM + ":"+"9669"+"/v1/"

$TargetZVMBaseResourceReportURL = "https://" + $TargetZVM + ":"+"9669"

# Authenticating with Zerto APIs

$TargetZVMSessionURL = $TargetZVMBaseURL + "session/add"

$TargetZVMAuthInfo = ("{0}:{1}" -f $Username,$Password)

$TargetZVMAuthInfo = [System.Text.Encoding]::UTF8.GetBytes($TargetZVMAuthInfo)

$TargetZVMAuthInfo = [System.Convert]::ToBase64String($TargetZVMAuthInfo)

$TargetZVMHeaders = @{Authorization=("Basic {0}" -f $TargetZVMAuthInfo)}

$TargetZVMSessionBody = '{"AuthenticationMethod": "1"}'

Page 41: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 41 OF 134

$TypeJSON = "application/json"

$TypeXML = "application/xml"

Try

{

$TargetZVMSessionResponse = Invoke-WebRequest -Uri $TargetZVMSessionURL -Headers $TargetZVMHeaders -Method POST -Body $TargetZVMSessionBody -ContentType $TypeJSON

$TargetZVMAuthentication = "PASS"

}

Catch {

$TargetZVMAuthentication = "FAIL"

}

#Extracting x-zerto-session from the response, and adding it to the actual API

$TargetZVMSession = $TargetZVMSessionResponse.headers.get_item("x-zerto-session")

$TargetZVMSessionHeader = @{"x-zerto-session"=$TargetZVMSession; "Accept"=$TypeJSON}

if ($TargetZVMAuthentication -eq "PASS")

{

# Get SiteIdentifier for later in the script

$TargetSiteInfoURL = $TargetZVMBaseURL+"localsite"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $TargetZVMSessionHeader -ContentType $TypeJSON

$TargetLocalSiteIdentifier = $TargetSiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

}

################################################

# Getting last resource report sample, for use in email reports

################################################

if ($ResourceReportHourlySample -eq "TRUE")

{

$NowDateTime = get-date -Format "yyyy-MM-dd HH:mm:ss"

$ThenDateTime = (get-date).AddHours(-1).ToString("yyyy-MM-dd HH:mm:ss")

}

else

{

$StartDateTime = get-date -Format "yyyy-MM-dd"

$EndDateTime = (get-date).AddDays(1).ToString("yyyy-MM-dd")

}

# QueryResourceReport with entries from the last hour

$ResourceReprtString = "/ZvmService/ResourcesReport/getSamples?fromTimeString="

$ResourceReportURL = $TargetZVMBaseResourceReportURL + $ResourceReprtString + $ThenDateTime + "&toTimeString=" + $NowDateTime + "&startIndex=0&count=500"

$ResourceReport = Invoke-RestMethod -Uri $ResourceReportURL -TimeoutSec 100 -Headers $TargetZVMSessionHeader -ContentType $TypeJSON

################################################

# Creating ProtectedVPGArray

################################################

# Getting VPGs

$ProtectedVPGsURL = $SourceZVMBaseURL+"vpgs"

$ProtectedVPGsCMD = Invoke-RestMethod -Uri $ProtectedVPGsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

foreach ($VPG in $ProtectedVPGsCMD)

{

$VPGName = $VPG.VpgName

$VPGIdentifier = $VPG.VpgIdentifier

$VMCount = $VPG.VmsCount

$PriorityNumber = $VPG.Priority

$RPO = $VPG.ActualRPO

$StatusNumber = $VPG.Status

$SizeInGb = $VPG.UsedStorageInMB / 1024

$SizeInGb = [math]::Round($SizeInGb,2)

# Converting priority

$VPGPriority = $VMPriorityArray | Where-Object {$_.Number -eq $PriorityNumber} | select -ExpandProperty Name

# Converting VM status

$VPGStatus = $VMStatusArray | Where-Object {$_.Number -eq $StatusNumber} | select -ExpandProperty Name

$VPGStatusDescription = $VMStatusArray | Where-Object {$_.Number -eq $StatusNumber} | select -ExpandProperty Description

# Getting VPG Journal size

$VPGResourceReport = $ResourceReport | Where-Object {$_.VpgName -eq $VPGName}

# Calculating total Journal usage

$VPGJournalUsage = $VPGResourceReport.RecoveryJournalUsedStorageInGB

$VPGTotalJournalUsage = 0

foreach ($_ in $VPGJournalUsage)

{

$VPGTotalJournalUsage += $_

Page 42: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 42 OF 134

}

$VPGTotalJournalUsage = [math]::Round($VPGTotalJournalUsage,2)

# Getting Alerts for the VPG for past 24 hours

$Tomorrow = (get-date).AddDays(1)

$Yesterday = (get-date).AddDays(-1)

# Building URL

$VPGAlertsURL = $SourceZVMBaseURL+"alerts?"+"startDate=$Yesterday&endDate=$Tomorrow&vpgIdentifier={$VPGIdentifier}&isDismissed=false"

# Getting events

$VPGAlertsCMD = Invoke-RestMethod -Uri $VPGAlertsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

$VPGLastAlert = $VPGAlertsCMD | select * -First 1

# Getting description of last alert

$VPGLastAlertIdentifier = $VPGLastAlert.HelpIdentifier

$VPGLastAlertDescription = $EventStatusArray | Where-Object {$_.Identifier -eq $VPGLastAlertIdentifier} | select -expandproperty Description

# Calculating RPO violations in last 24 hours

$VPGRPOAlerts = $VPGAlertsCMD | Where-Object {$_.HelpIdentifier -eq "VPG0009" -or $_.HelpIdentifier -eq "VPG0009"} | Measure-Object | select -ExpandProperty Count

# Adding to array

$ProtectedVPGArrayLine = new-object PSObject

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value $SourcePOD

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "TargetPOD" -Value $TargetPOD

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "VMCount" -Value $VMCount

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "Priority" -Value $VPGPriority

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "RPO" -Value $RPO

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "RPOAlerts" -Value $VPGRPOAlerts

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "Status" -Value $VPGStatus

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "SizeInGb" -Value $SizeInGb

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "JournalSizeInGb" -Value $VPGTotalJournalUsage

$ProtectedVPGArrayLine | Add-Member -MemberType NoteProperty -Name "AlertDescription" -Value $VPGLastAlertDescription

$ProtectedVPGArray += $ProtectedVPGArrayLine

}

# Getting VMs

$ProtectedVMsURL = $SourceZVMBaseURL+"vms"

$ProtectedVMsCMD = Invoke-RestMethod -Uri $ProtectedVMsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Adding to array

$ProtectedVMs = $ProtectedVMsCMD | Sort-Object VpgName

foreach ($VM in $ProtectedVMs)

{

$VPGName = $VM.VpgName

$VMName = $VM.VmName

$StatusNumber = $VM.Status

$PriorityNumber = $VM.Priority

$RPO = $VM.ActualRPO

$SizeInGb = $VM.UsedStorageInMB / 1024

$SizeInGb = [math]::Round($SizeInGb,2)

$VMDisks = $VM.Volumes.Count

# Converting priority

$VMPriority = $VMPriorityArray | Where-Object {$_.Number -eq $PriorityNumber} | select -ExpandProperty Name

# Converting VM status

$VMStatus = $VMStatusArray | Where-Object {$_.Number -eq $StatusNumber} | select -ExpandProperty Name

$VMStatusDescription = $VMStatusArray | Where-Object {$_.Number -eq $StatusNumber} | select -ExpandProperty Description

# Gettong VM Journal size

$VMResourceReport = $ResourceReport | Where-Object {$_.VmName -eq $VMName} | select -First 1

$VMSourceCluster = $VMResourceReport.SourceCluster

$VMTargetCluster = $VMResourceReport.TargetCluster

# Calculating total Journal usage

$VMJournalUsage = $VMResourceReport.RecoveryJournalUsedStorageInGB

$VMTotalJournalUsage = 0

foreach ($_ in $VMJournalUsage)

{

$VMTotalJournalUsage += $_

}

$VMTotalJournalUsage = [math]::Round($VMTotalJournalUsage,2)

# Creating array line

$ProtectedVMArrayLine = new-object PSObject

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value "$SourcePOD"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "SourceCluster" -Value "$VMSourceCluster"

Page 43: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 43 OF 134

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "TargetPOD" -Value "$TargetPOD"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "TargetCluster" -Value "$VMTargetCluster"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value "$VPGName"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value "$VMName"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "Priority" -Value "$VMPriority"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "RPO" -Value "$RPO"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "Status" -Value "$VMStatus"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "Disks" -Value "$VMDisks"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "SizeInGb" -Value "$SizeInGb"

$ProtectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "JournalSizeInGb" -Value "$VMTotalJournalUsage"

$ProtectedVMArray += $ProtectedVMArrayLine

}

################################################

# Creating TargetVRAArray

################################################

$TargetZVMHostsURL = $TargetZVMBaseURL+"virtualizationsites/"+$TargetLocalSiteIdentifier+"/hosts"

$TargetZVMHostsCMD = Invoke-RestMethod -Uri $TargetZVMHostsURL -TimeoutSec 100 -Headers $TargetZVMSessionHeader -ContentType $TypeJSON

$TargetZVMVRAsURL = $TargetZVMBaseURL+"vras"

$TargetZVMVRAsCMD = Invoke-RestMethod -Uri $TargetZVMVRAsURL -TimeoutSec 100 -Headers $TargetZVMSessionHeader -ContentType $TypeJSON

$TargetZVMVRAs = $TargetZVMVRAsCMD | Select-Object VraName,HostIdentifier,VraGroup,RecoveryCounters -Unique

# For each VRA

foreach ($TargetVRA in $TargetZVMVRAs)

{

$VRAName = $TargetVRA.VraName

$VRACluster = get-vm $VRAName | Get-Cluster | select -expandproperty Name

$VRAHostIdentifier = $TargetVRA.HostIdentifier

$VRAVMs = $TargetVRA.RecoveryCounters.Vms

$VRAHostIdentifier = $TargetVRA.HostIdentifier

$VRAVolumes = $TargetVRA.RecoveryCounters.Volumes

$VRAVpgs = $TargetVRA.RecoveryCounters.Vpgs

$VRAGroup = $TargetVRA.VraGroup

# Getting hostname

$VRAHostname = $TargetZVMHostsCMD | Where-Object {$_.HostIdentifier -eq $VRAHostIdentifier} | select -ExpandProperty VirtualizationHostName

# Getting over commit data from resource report

$TargetVraData = $ResourceReport | Where-Object {$_.TargetVraName -eq $VRAName} | Select-Object NumberOfvCpu,CpuUsedInMhz,MemoryInMB,ActiveGuestMemoryInMB,BandwidthInBytes,RecoveryVolumesUsedStorageInGB,RecoveryJournalUsedStorageInGB

# Calculating total CPUs

$TargetVraNumberOfvCPU = $TargetVraData.NumberOfvCpu

$TotalTargetVraNumberOfvCPU = 0

foreach ($_ in $TargetVraNumberOfvCPU)

{

$TotalTargetVraNumberOfvCPU += $_

}

# Calculating total CPU mhz

$TargetVraCpuUsedInMhz = $TargetVraData.CpuUsedInMhz

$TotalTargetVraCpuUsedInMhz = 0

foreach ($_ in $TargetVraCpuUsedInMhz)

{

$TotalTargetVraCpuUsedInMhz += $_

}

$TotalTargetVraCpuUsedInGhz = $TotalTargetVraCpuUsedInMhz / 1000

$TotalTargetVraCpuUsedInGhz = [math]::Round($TotalTargetVraCpuUsedInGhz,2)

# Calculating total MemoryInMB

$TargetVraMemoryInMB = $TargetVraData.MemoryInMB

$TotalTargetVraMemoryInMB = 0

foreach ($_ in $TargetVraMemoryInMB)

{

$TotalTargetVraMemoryInMB += $_

}

$TotalTargetVraMemoryInGB = $TotalTargetVraMemoryInMB / 1024

$TotalTargetVraMemoryInGB = [math]::Round($TotalTargetVraMemoryInGB,2)

# Calculating total ActiveGuestMemoryInMB

$TargetVraActiveGuestMemoryInMB = $TargetVraData.ActiveGuestMemoryInMB

$TotalTargetVraActiveGuestMemoryInMB = 0

foreach ($_ in $TargetVraActiveGuestMemoryInMB)

{

$TotalTargetVraActiveGuestMemoryInMB += $_

Page 44: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 44 OF 134

}

$TotalTargetVraActiveGuestMemoryInGB = $TotalTargetVraActiveGuestMemoryInMB / 1024

$TotalTargetVraActiveGuestMemoryInGB = [math]::Round($TotalTargetVraActiveGuestMemoryInGB,2)

# Calculating total BandwidthInBytes

$TargetVraBandwidthInBytes = $TargetVraData.BandwidthInBytes

$TotalTargetVraBandwidthInBytes = 0

foreach ($_ in $TargetVraBandwidthInBytes)

{

$TotalTargetVraBandwidthInBytes += $_

}

# Calculating total RecoveryVolumesUsedStorageInGB & TB

$TargetVraRecoveryVolumesUsedStorageInGB = $TargetVraData.RecoveryVolumesUsedStorageInGB

$TotalTargetVraRecoveryVolumesUsedStorageInGB = 0

foreach ($_ in $TargetVraRecoveryVolumesUsedStorageInGB)

{

$TotalTargetVraRecoveryVolumesUsedStorageInGB += $_

}

$TotalTargetVraRecoveryVolumesUsedStorageInTB = $TotalTargetVraRecoveryVolumesUsedStorageInGB / 1024

$TotalTargetVraRecoveryVolumesUsedStorageInTB = [math]::Round($TotalTargetVraRecoveryVolumesUsedStorageInTB,2)

# Calculating total RecoveryJournalUsedStorageInGB

$TargetVraRecoveryJournalUsedStorageInGB = $TargetVraData.RecoveryJournalUsedStorageInGB

$TotalTargetVraRecoveryJournalUsedStorageInGB = 0

foreach ($_ in $TargetVraRecoveryJournalUsedStorageInGB)

{

$TotalTargetVraRecoveryJournalUsedStorageInGB += $_

}

$TotalTargetVraRecoveryJournalUsedStorageInTB = $TotalTargetVraRecoveryJournalUsedStorageInGB / 1024

$TotalTargetVraRecoveryJournalUsedStorageInTB = [math]::Round($TotalTargetVraRecoveryJournalUsedStorageInTB,2)

# Creating array

$TargetVRAArrayLine = new-object PSObject

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "TargetPOD" -Value $TargetPOD

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRACluster" -Value $VRACluster

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRAName" -Value $VRAName

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "ESXiHostname" -Value $VRAHostname

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRAVPGs" -Value $VRAVpgs

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRAVMs" -Value $VRAVMs

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRAVolumes" -Value $VRAVolumes

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRABandwidthInBytes" -Value $TotalTargetVraBandwidthInBytes

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRARecoveryVolumesInGB" -Value $TotalTargetVraRecoveryVolumesUsedStorageInGB

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VraRecoveryVolumesInTB" -Value $TotalTargetVraRecoveryVolumesUsedStorageInTB

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRARecoveryJournalsInGB" -Value $TotalTargetVraRecoveryJournalUsedStorageInGB

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRARecoveryJournalsInTB" -Value $TotalTargetVraRecoveryJournalUsedStorageInTB

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VMNumberOfvCPU" -Value $TotalTargetVraNumberOfvCPU

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VMCpuUsedInGhz" -Value $TotalTargetVraCpuUsedInGhz

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VMMemoryInGB" -Value $TotalTargetVraMemoryInGB

$TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VMActiveMemoryInGB" -Value $TotalTargetVraActiveGuestMemoryInGB

$TargetVRAArray += $TargetVRAArrayLine

}

################################################

# Creating UnprotectedVMArray

################################################

# Using ZVR API to get VMs

$SourceZVMUnprotectedVMsURL = $SourceZVMBaseURL+"virtualizationsites/"+$SourceLocalSiteIdentifier+"/vms"

$SourceZVMUnprotectedVMsCMD = Invoke-RestMethod -Uri $SourceZVMUnprotectedVMsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# For each unprotected VM

foreach ($VM in $SourceZVMUnprotectedVMsCMD)

{

# Getting vCenter VM ID from ZVR ID

$VMName = $VM.VmName

$VMZVRID = $VM.VmIdentifier

$Separator = "."

$VMZVRIDSplit = $VMZVRID.split($Separator)

$VMID = $VMZVRIDSplit[1]

$VMID = "VirtualMachine-" + $VMID

# Using vCenter VM ID to get more info

# Getting cluster info

Page 45: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 45 OF 134

$VMCluster = get-vm -Id $VMID | Get-Cluster | select -expandproperty Name -First 1

$VMInfo = get-vm -Id $VMID | select Folder,NumCPU,MemoryGB,HardDisks,NetworkAdapters,UsedSpaceGB -First 1

$VMFolder = $VMInfo.Folder

$VMNumCPU = $VMInfo.NumCpu

$VMMemoryGB = $VMInfo.MemoryGB

$VMMemoryGB = [math]::Round($VMMemoryGB,2)

$VMHardDisks = $VMInfo.HardDisks.Count

$VMNICS = $VMInfo.NetworkAdapters.Count

$VMUsedSpaceGB = $VMInfo.UsedSpaceGB

$VMUsedSpaceGB = [math]::Round($VMUsedSpaceGB,2)

# Building array line

$UnprotectedVMArrayLine = new-object PSObject

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value "$SourcePOD"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolder" -Value "$VMFolder"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value "$VMName"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "VMCluster" -Value "$VMCluster"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "NumCPU" -Value "$VMNumCPU"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "MemoryGB" -Value "$VMMemoryGB"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "NICS" -Value "$VMNICS"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "HardDisks" -Value "$VMHardDisks"

$UnprotectedVMArrayLine | Add-Member -MemberType NoteProperty -Name "UsedSpaceGB" -Value "$VMUsedSpaceGB"

$UnprotectedVMArray += $UnprotectedVMArrayLine

}

################################################

# Creating TargetDatastoreArray

################################################

$TargetDatastoresURL = $TargetZVMBaseURL+"virtualizationsites/"+$TargetLocalSiteIdentifier+"/datastores"

$TargetDatastoresCMD = Invoke-RestMethod -Uri $TargetDatastoresURL -TimeoutSec 100 -Headers $TargetZVMSessionHeader -ContentType $TypeJSON

# For each datastore

foreach ($DS in $TargetDatastoresCMD)

{

# Getting vCenter VM ID from ZVR ID

$DSName = $DS.DatastoreName

$DSZVRID = $DS.DatastoreIdentifier

$Separator = "."

$DSZVRIDSplit = $DSZVRID.split($Separator)

$DSID = $DSZVRIDSplit[1]

$DSID = "Datastore-" + $DSID

# Using vCenter to get more info

$DSCluster = Get-Datastore -Id $DSID | Get-DatastoreCluster | select -ExpandProperty Name -First 1

$DSInfo = Get-Datastore -Id $DSID | select * -First 1

$DSCapacityGB = $DSInfo.CapacityGB

$DSCapacityGB = [math]::Round($DSCapacityGB)

$DSFreeSpaceGB = $DSInfo.FreeSpaceGB

$DSFreeSpaceGB = [math]::Round($DSFreeSpaceGB)

$DSFreePercentage = ($DSFreeSpaceGB / $DSCapacityGB) * 100

$DSFreePercentage = [math]::Round($DSFreePercentage)

# Finding if datastore is used for replication

$ResourceReportTargetDatastores = $ResourceReport | select -ExpandProperty TargetDatastores

# Checking if DSName found in any target VM replica datastores

if ($ResourceReportTargetDatastores -match $DSName)

{

$DSUsedByZVR = "TRUE"

}

else

{

$DSUsedByZVR = "FALSE"

}

# Building array line

$TargetDatastoreArrayLine = new-object PSObject

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "PODName" -Value $TargetPOD

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "DatastoreCluster" -Value "$DSCluster"

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "DatastoreName" -Value "$DSName"

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "UsedByZVR" -Value "$DSUsedByZVR"

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "CapacityGB" -Value "$DSCapacityGB"

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "FreeSpaceGB" -Value "$DSFreeSpaceGB"

Page 46: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 46 OF 134

$TargetDatastoreArrayLine | Add-Member -MemberType NoteProperty -Name "FreePercent" -Value "$DSFreePercentage"

$TargetDatastoreArray += $TargetDatastoreArrayLine

}

################################################

# Creating VPGArray, VMArray, VMVolumeArray, VMNICArray

################################################

# URL to create VPG settings

$CreateVPGURL = $SourceZVMBaseURL+"vpgSettings"

# Build List of VPGs

$vpgListApiUrl = $SourceZVMBaseURL+"vpgs"

$vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

# Build List of VMs

$vmListApiUrl = $SourceZVMBaseURL+"vms"

$vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

# Select IDs from the API array

$zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,vmscount,vpgidentifier

$vmListarray = $vmList.ArrayOfVmApi.VmApi | select-object *

################################################

# Starting for each VPG action of collecting ZVM VPG data

################################################

foreach ($VPGLine in $zertoprotectiongrouparray)

{

$VPGidentifier = $VPGLine.vpgidentifier

$VPGOrganization = $VPGLine.OrganizationName

$VPGVMCount = $VPGLine.VmsCount

$JSON =

"{

""VpgIdentifier"":""$VPGidentifier""

}"

################################################

# Posting the VPG JSON Request to the API

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $SourceZVMSessionHeader_JSON

$ValidVPGSettingsIdentifier = $true

}

Catch {

$ValidVPGSettingsIdentifier = $false

}

################################################

# Getting VPG settings from API

################################################

# Skipping if unable to obtain valid VPG setting identifier

if ($ValidVPGSettingsIdentifier -eq $true)

{

$VPGSettingsURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier

$VPGSettings = Invoke-RestMethod -Uri $VPGSettingsURL -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting recovery site ID (needed anyway for network settings)

$VPGRecoverySiteIdentifier = $VPGSettings.Basic.RecoverySiteIdentifier

# Getting site info

$VISitesURL = $SourceZVMBaseURL+"virtualizationsites"

$VISitesCMD = Invoke-RestMethod -Uri $VISitesURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting network info

$VINetworksURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/networks"

$VINetworksCMD = Invoke-RestMethod -Uri $VINetworksURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting datastore info

$VIDatastoresURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/datastores"

$VIDatastoresCMD = Invoke-RestMethod -Uri $VIDatastoresURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting datastore cluster info

$VIDatastoreClustersURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/datastoreclusters"

$VIDatastoreClustersCMD = Invoke-RestMethod -Uri $VIDatastoreClustersURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting folder info

$VIFoldersURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/folders"

$VIFoldersCMD = Invoke-RestMethod -Uri $VIFoldersURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting cluster info

Page 47: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 47 OF 134

$VIClustersURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/hostclusters"

$VIClustersCMD = Invoke-RestMethod -Uri $VIClustersURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting host info

$VIHostsURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/hosts"

$VIHostsCMD = Invoke-RestMethod -Uri $VIHostsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting resource pool info

$VIResourcePoolsURL = $SourceZVMBaseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/resourcepools"

$VIResourcePoolsCMD = Invoke-RestMethod -Uri $VIResourcePoolsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting all VPG Settings

$VPGJournalHistoryInHours = $VPGSettings.Basic.JournalHistoryInHours

$VPGName = $VPGSettings.Basic.Name

$VPGPriortiy = $VPGSettings.Basic.Priority

$VPGProtectedSiteIdentifier = $VPGSettings.Basic.ProtectedSiteIdentifier

$VPGRpoInSeconds = $VPGSettings.Basic.RpoInSeconds

$VPGServiceProfileIdentifier = $VPGSettings.Basic.ServiceProfileIdentifier

$VPGTestIntervalInMinutes = $VPGSettings.Basic.TestIntervalInMinutes

$VPGUseWanCompression = $VPGSettings.Basic.UseWanCompression

$VPGZorgIdentifier = $VPGSettings.Basic.ZorgIdentifier

# Getting Boot Group IDs

$VPGBootGroups = $VPGSettings.BootGroups.BootGroups

$VPGBootGroupCount = $VPGSettings.BootGroups.BootGroups.Count

$VPGBootGroupNames = $VPGSettings.BootGroups.BootGroups.Name

$VPGBootGroupDelays = $VPGSettings.BootGroups.BootGroups.BootDelayInSeconds

$VPGBootGroupIdentifiers = $VPGSettings.BootGroups.BootGroups.BootGroupIdentifier

# Getting Journal info

$VPGJournalDatastoreClusterIdentifier = $VPGSettings.Journal.DatastoreClusterIdentifier

$VPGJournalDatastoreIdentifier = $VPGSettings.Journal.DatastoreIdentifier

$VPGJournalHardLimitInMB = $VPGSettings.Journal.Limitation.HardLimitInMB

$VPGJournalHardLimitInPercent = $VPGSettings.Journal.Limitation.HardLimitInPercent

$VPGJournalWarningThresholdInMB = $VPGSettings.Journal.Limitation.WarningThresholdInMB

$VPGJournalWarningThresholdInPercent = $VPGSettings.Journal.Limitation.WarningThresholdInPercent

# Getting Network IDs

$VPGFailoverNetworkID = $VPGSettings.Networks.Failover.Hypervisor.DefaultNetworkIdentifier

$VPGFailoverTestNetworkID = $VPGSettings.Networks.FailoverTest.Hypervisor.DefaultNetworkIdentifier

# Getting recovery info

$VPGDefaultDatastoreIdentifier = $VPGSettings.Recovery.DefaultDatastoreIdentifier

$VPGDefaultFolderIdentifier = $VPGSettings.Recovery.DefaultFolderIdentifier

$VPGDefaultHostClusterIdentifier = $VPGSettings.Recovery.DefaultHostClusterIdentifier

$VPGDefaultHostIdentifier = $VPGSettings.Recovery.DefaultHostIdentifier

$VPGResourcePoolIdentifier = $VPGSettings.Recovery.ResourcePoolIdentifier

# Getting scripting info

$VPGScriptingPreRecovery = $VPGSettings.Scripting.PreRecovery

$VPGScriptingPostRecovery = $VPGSettings.Scripting.PostRecovery

# Getting VM IDs in VPG

$VPGVMIdentifiers = $VPGSettings.VMs.VmIdentifier

################################################

# Translating Zerto IDs from VPG settings to friendly vSphere names

################################################

# Getting site names

$VPGProtectedSiteName = $VISitesCMD | Where-Object {$_.SiteIdentifier -eq $VPGProtectedSiteIdentifier} | select -ExpandProperty VirtualizationSiteName

$VPGRecoverySiteName = $VISitesCMD | Where-Object {$_.SiteIdentifier -eq $VPGRecoverySiteIdentifier} | select -ExpandProperty VirtualizationSiteName

# Getting network names

$VPGFailoverNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VPGFailoverNetworkID} | Select -ExpandProperty VirtualizationNetworkName

$VPGFailoverTestNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VPGFailoverTestNetworkID} | Select -ExpandProperty VirtualizationNetworkName

# Getting datastore cluster name

$VPGJournalDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VPGJournalDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore names

$VPGDefaultDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VPGDefaultDatastoreIdentifier} | select -ExpandProperty DatastoreName

$VPGJournalDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VPGJournalDatastoreIdentifier} | select -ExpandProperty DatastoreName

# Getting folder name

$VPGDefaultFolderName = $VIFoldersCMD | Where-Object {$_.FolderIdentifier -eq $VPGDefaultFolderIdentifier} | select -ExpandProperty FolderName

# Getting cluster name

$VPGDefaultHostClusterName = $VIClustersCMD | Where-Object {$_.ClusterIdentifier -eq $VPGDefaultHostClusterIdentifier} | select -ExpandProperty VirtualizationClusterName

# Getting host name

$VPGDefaultHostName = $VIHostsCMD | Where-Object {$_.HostIdentifier -eq $VPGDefaultHostIdentifier} | select -ExpandProperty VirtualizationHostName

# Getting resource pool name

Page 48: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 48 OF 134

$VPGResourcePoolName = $VIResourcePoolsCMD | Where-Object {$_.ResourcePoolIdentifier -eq $VPGResourcePoolIdentifier} | select -ExpandProperty ResourcepoolName

################################################

# Adding all VPG setting info to $VPGArray

################################################

$VPGArrayLine = new-object PSObject

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value $SourcePOD

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGOrganization" -Value $VPGOrganization

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGVMCount" -Value $VPGVMCount

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGPriortiy" -Value $VPGPriortiy

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGProtectedSiteName" -Value $VPGProtectedSiteName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGProtectedSiteIdentifier" -Value $VPGProtectedSiteIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRecoverySiteName" -Value $VPGRecoverySiteName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRecoverySiteIdentifier" -Value $VPGRecoverySiteIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGRpoInSeconds" -Value $VPGRpoInSeconds

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGServiceProfileIdentifier" -Value $VPGServiceProfileIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGTestIntervalInMinutes" -Value $VPGTestIntervalInMinutes

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGUseWanCompression" -Value $VPGUseWanCompression

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGZorgIdentifier" -Value $VPGZorgIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupCount" -Value $VPGBootGroupCount

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupNames" -Value $VPGBootGroupNames

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupDelays" -Value $VPGBootGroupDelays

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGBootGroupIdentifiers" -Value $VPGBootGroupIdentifiers

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHistoryInHours" -Value $VPGJournalHistoryInHours

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreClusterName" -Value $VPGJournalDatastoreClusterName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreClusterIdentifier" -Value $VPGJournalDatastoreClusterIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreName" -Value $VPGJournalDatastoreName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalDatastoreIdentifier" -Value $VPGJournalDatastoreIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHardLimitInMB" -Value $VPGJournalHardLimitInMB

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalHardLimitInPercent" -Value $VPGJournalHardLimitInPercent

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalWarningThresholdInMB" -Value $VPGJournalWarningThresholdInMB

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGJournalWarningThresholdInPercent" -Value $VPGJournalWarningThresholdInPercent

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverNetworkName" -Value $VPGFailoverNetworkName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverNetworkID" -Value $VPGFailoverNetworkID

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverTestNetworkName" -Value $VPGFailoverTestNetworkName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailoverTestNetworkID" -Value $VPGFailoverTestNetworkID

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultDatastoreName" -Value $VPGDefaultDatastoreName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultDatastoreIdentifier" -Value $VPGDefaultDatastoreIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultFolderName" -Value $VPGDefaultFolderName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultFolderIdentifier" -Value $VPGDefaultFolderIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostClusterName" -Value $VPGDefaultHostClusterName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostClusterIdentifier" -Value $VPGDefaultHostClusterIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostName" -Value $VPGDefaultHostName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGDefaultHostIdentifier" -Value $VPGDefaultHostIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGResourcePoolName" -Value $VPGResourcePoolName

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGResourcePoolIdentifier" -Value $VPGResourcePoolIdentifier

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGScriptingPreRecovery" -Value $VPGScriptingPreRecovery

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGScriptingPostRecovery" -Value $VPGScriptingPostRecovery

$VPGArray += $VPGArrayLine

################################################

# Starting for each VM ID action for collecting ZVM VM data

################################################

foreach ($_ in $VPGVMIdentifiers)

{

$VMIdentifier = $_

# Get VMs settings

$GetVMSettingsURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier

$GetVMSettings = Invoke-RestMethod -Method Get -Uri $GetVMSettingsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_JSON -ContentType $TypeJSON

# Getting the VM name and disk usage

$VMNameArray = $vmListarray | where-object {$_.VmIdentifier -eq $VMIdentifier} | Select-Object *

$VMName = $VMNameArray.VmName

$VMProvisionedStorageInMB = $VMNameArray.ProvisionedStorageInMB

$VMUsedStorageInMB = $VMNameArray.UsedStorageInMB

# Setting variables from the API

$VMVolumeCount = $GetVMSettings.Volumes.Count

Page 49: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 49 OF 134

$VMNICCount = $GetVMSettings.Nics.Count

$VMBootGroupIdentifier = $GetVMSettings.BootGroupIdentifier

$VMJournalDatastoreClusterIdentifier = $GetVMSettings.Journal.DatastoreClusterIdentifier

$VMJournalDatastoreIdentifier = $GetVMSettings.Journal.DatastoreIdentifier

$VMJournalHardLimitInMB = $GetVMSettings.Journal.Limitation.HardLimitInMB

$VMJournalHardLimitInPercent = $GetVMSettings.Journal.Limitation.HardLimitInPercent

$VMJournalWarningThresholdInMB = $GetVMSettings.Journal.Limitation.WarningThresholdInMB

$VMJournalWarningThresholdInPercent = $GetVMSettings.Journal.Limitation.WarningThresholdInPercent

$VMDatastoreClusterIdentifier = $GetVMSettings.Recovery.DatastoreClusterIdentifier

$VMDatastoreIdentifier = $GetVMSettings.Recovery.DatastoreIdentifier

$VMFolderIdentifier = $GetVMSettings.Recovery.FolderIdentifier

$VMHostClusterIdentifier = $GetVMSettings.Recovery.HostClusterIdentifier

$VMHostIdentifier = $GetVMSettings.Recovery.HostIdentifier

$VMResourcePoolIdentifier = $GetVMSettings.Recovery.ResourcePoolIdentifier

################################################

# Translating Zerto IDs from VM settings to friendly vSphere names

################################################

# Getting boot group

$VMBootGroupName = $VPGBootGroups | Where-Object {$_.BootGroupIdentifier -eq $VMBootGroupIdentifier} | select -ExpandProperty Name

$VMBootGroupDelay = $VPGBootGroups | Where-Object {$_.BootGroupIdentifier -eq $VMBootGroupIdentifier} | select -ExpandProperty BootDelayInSeconds

# Getting datastore cluster name

$VMJournalDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMJournalDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

$VMDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore name

$VMJournalDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMJournalDatastoreIdentifier} | select -ExpandProperty DatastoreName

$VMDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMDatastoreIdentifier} | select -ExpandProperty DatastoreName

# Getting folder name

$VMFolderName = $VIFoldersCMD | Where-Object {$_.FolderIdentifier -eq $VMFolderIdentifier} | select -ExpandProperty FolderName

# Getting cluster name

$VMHostClusterName = $VIClustersCMD | Where-Object {$_.ClusterIdentifier -eq $VMHostClusterIdentifier} | select -ExpandProperty VirtualizationClusterName

# Getting host name

$VMHostName = $VIHostsCMD | Where-Object {$_.HostIdentifier -eq $VMHostIdentifier} | select -ExpandProperty VirtualizationHostName

# Getting resource pool name

$VMResourcePoolName = $VIResourcePoolsCMD | Where-Object {$_.ResourcePoolIdentifier -eq $VMResourcePoolIdentifier} | select -ExpandProperty ResourcepoolName

################################################

# Adding all VM setting info to $VMArray

################################################

$VMArrayLine = new-object PSObject

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value $SourcePOD

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICCount" -Value $VMNICCount

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeCount" -Value $VMVolumeCount

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMProvisionedStorageInMB" -Value $VMProvisionedStorageInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMUsedStorageInMB" -Value $VMUsedStorageInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupName" -Value $VMBootGroupName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupDelay" -Value $VMBootGroupDelay

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootGroupIdentifier" -Value $VMBootGroupIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreClusterName" -Value $VMJournalDatastoreClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreClusterIdentifier" -Value $VMJournalDatastoreClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreName" -Value $VMJournalDatastoreName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalDatastoreIdentifier" -Value $VMJournalDatastoreIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalHardLimitInMB" -Value $VMJournalHardLimitInMB

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMJournalHardLimitInPercent" -Value $VMJournalHardLimitInPercent

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreClusterName" -Value $VMDatastoreClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreClusterIdentifier" -Value $VMDatastoreClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreName" -Value $VMDatastoreName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreIdentifier" -Value $VMDatastoreIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolderName" -Value $VMFolderName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMFolderIdentifier" -Value $VMFolderIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostClusterName" -Value $VMHostClusterName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostClusterIdentifier" -Value $VMHostClusterIdentifier

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostName" -Value $VMHostName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMHostIdentifier" -Value $VMHostIdentifier

Page 50: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 50 OF 134

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMResourcePoolName" -Value $VMResourcePoolName

$VMArrayLine | Add-Member -MemberType NoteProperty -Name "VMResourcePoolIdentifier" -Value $VMResourcePoolIdentifier

$VMArray += $VMArrayLine

################################################

# Get VM Volume settings for the current VPG

################################################

$GetVMSettingVolumesURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/volumes"

$GetVMSettingVolumes = Invoke-RestMethod -Method Get -Uri $GetVMSettingVolumesURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

$GetVMSettingVolumeIDs = $GetVMSettingVolumes.ArrayOfVpgSettingsVmVolumeApi.VpgSettingsVmVolumeApi | select-object VolumeIdentifier -ExpandProperty VolumeIdentifier

################################################

# Starting for each VM Volume ID action for collecting ZVM VM Volume data

################################################

foreach ($_ in $GetVMSettingVolumeIDs)

{

$VMVolumeID = $_

# Getting API data for volume

$GetVMSettingVolumeURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/volumes/"+$VMVolumeID

$GetVMSettingVolume = Invoke-RestMethod -Method Get -Uri $GetVMSettingVolumeURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

# Setting values

$VMVolumeDatastoreClusterIdentifier = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.DatastoreClusterIdentifier

$VMVolumeDatastoreIdentifier = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.DatastoreIdentifier

$VMVolumeIsSWAP = $GetVMSettingVolume.VpgSettingsVmVolumeApi.IsSwap

$VMVolumeIsThin = $GetVMSettingVolume.VpgSettingsVmVolumeApi.Datastore.IsThin

# Getting datastore cluster name

$VMVolumeDatastoreClusterName = $VIDatastoreClustersCMD | Where-Object {$_.DatastoreClusterIdentifier -eq $VMVolumeDatastoreClusterIdentifier} | select -ExpandProperty DatastoreClusterName

# Getting datastore name

$VMVolumeDatastoreName = $VIDatastoresCMD | Where-Object {$_.DatastoreIdentifier -eq $VMVolumeDatastoreIdentifier} | select -ExpandProperty DatastoreName

################################################

# Adding all VM Volume setting info to $VMVolumeArray

################################################

$VMVolumeArrayLine = new-object PSObject

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value $SourcePOD

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeID" -Value $VMVolumeID

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeIsSWAP" -Value $VMVolumeIsSWAP

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeIsThin" -Value $VMVolumeIsThin

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreClusterName" -Value $VMVolumeDatastoreClusterName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreClusterIdentifier" -Value $VMVolumeDatastoreClusterIdentifier

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreName" -Value $VMVolumeDatastoreName

$VMVolumeArrayLine | Add-Member -MemberType NoteProperty -Name "VMVolumeDatastoreIdentifier" -Value $VMVolumeDatastoreIdentifier

$VMVolumeArray += $VMVolumeArrayLine

}

################################################

# Get VM Nic settings for the current VPG

################################################

$GetVMSettingNICsURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics"

$GetVMSettingNICs = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

$VMNICIDs = $GetVMSettingNICs.ArrayOfVpgSettingsVmNicApi.VpgSettingsVmNicApi | select-object NicIdentifier -ExpandProperty NicIdentifier

################################################

# Starting for each VM NIC ID action for collecting ZVM VM NIC data

################################################

foreach ($_ in $VMNICIDs)

{

$VMNICIdentifier = $_

$GetVMSettingNICURL = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics/"+$VMNICIdentifier

$GetVMSettingNIC = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

# Building arrays

$VMSettingNICIDArray1 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor

$VMSettingNICIDArray2 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor.IpConfig

$VMSettingNICIDArray3 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor

$VMSettingNICIDArray4 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor.IpConfig

# Setting failover values

$VMNICFailoverDNSSuffix = $VMSettingNICIDArray1.DnsSuffix

Page 51: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 51 OF 134

$VMNICFailoverNetworkIdentifier = $VMSettingNICIDArray1.NetworkIdentifier

$VMNICFailoverShouldReplaceMacAddress = $VMSettingNICIDArray1.ShouldReplaceMacAddress

$VMNICFailoverGateway = $VMSettingNICIDArray2.Gateway

$VMNIsFailoverDHCP = $VMSettingNICIDArray2.IsDhcp

$VMNICFailoverPrimaryDns = $VMSettingNICIDArray2.PrimaryDns

$VMNICFailoverSecondaryDns = $VMSettingNICIDArray2.SecondaryDns

$VMNICFailoverStaticIp = $VMSettingNICIDArray2.StaticIp

$VMNICFailoverSubnetMask = $VMSettingNICIDArray2.SubnetMask

# Nulling blank content

if ($VMNICFailoverDNSSuffix.nil -eq $true){$VMNICFailoverDNSSuffix = $null}

if ($VMNICFailoverGateway.nil -eq $true){$VMNICFailoverGateway = $null}

if ($VMNICFailoverPrimaryDns.nil -eq $true){$VMNICFailoverPrimaryDns = $null}

if ($VMNICFailoverSecondaryDns.nil -eq $true){$VMNICFailoverSecondaryDns = $null}

if ($VMNICFailoverStaticIp.nil -eq $true){$VMNICFailoverStaticIp = $null}

if ($VMNICFailoverSubnetMask.nil -eq $true){$VMNICFailoverSubnetMask = $null}

# Setting failover test values

$VMNICFailoverTestDNSSuffix = $VMSettingNICIDArray3.DnsSuffix

$VMNICFailoverTestNetworkIdentifier = $VMSettingNICIDArray3.NetworkIdentifier

$VMNICFailoverTestShouldReplaceMacAddress = $VMSettingNICIDArray3.ShouldReplaceMacAddress

$VMNICFailoverTestGateway = $VMSettingNICIDArray4.Gateway

$VMNIsFailoverTestDHCP = $VMSettingNICIDArray4.IsDhcp

$VMNICFailoverTestPrimaryDns = $VMSettingNICIDArray4.PrimaryDns

$VMNICFailoverTestSecondaryDns = $VMSettingNICIDArray4.SecondaryDns

$VMNICFailoverTestStaticIp = $VMSettingNICIDArray4.StaticIp

$VMNICFailoverTestSubnetMask = $VMSettingNICIDArray4.SubnetMask

# Nulling blank content

if ($VMNICFailoverTestDNSSuffix.nil -eq $true){$VMNICFailoverTestDNSSuffix = $null}

if ($VMNICFailoverTestGateway.nil -eq $true){$VMNICFailoverTestGateway = $null}

if ($VMNICFailoverTestPrimaryDns.nil -eq $true){$VMNICFailoverTestPrimaryDns = $null}

if ($VMNICFailoverTestSecondaryDns.nil -eq $true){$VMNICFailoverTestSecondaryDns = $null}

if ($VMNICFailoverTestStaticIp.nil -eq $true){$VMNICFailoverTestStaticIp = $null}

if ($VMNICFailoverTestSubnetMask.nil -eq $true){$VMNICFailoverTestSubnetMask = $null}

# Mapping Network IDs to Names

$VMNICFailoverNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

$VMNICFailoverTestNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverTestNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

################################################

# Adding all VM NIC setting info to $VMNICArray

################################################

$VMNICArrayLine = new-object PSObject

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "SourcePOD" -Value $SourcePOD

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICIdentifier" -Value $VMNICIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverNetworkName" -Value $VMNICFailoverNetworkName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverNetworkIdentifier" -Value $VMNICFailoverNetworkIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDNSSuffix" -Value $VMNICFailoverDNSSuffix

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverShouldReplaceMacAddress" -Value $VMNICFailoverShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverGateway" -Value $VMNICFailoverGateway

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDHCP" -Value $VMNIsFailoverDHCP

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverPrimaryDns" -Value $VMNICFailoverPrimaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSecondaryDns" -Value $VMNICFailoverSecondaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverStaticIp" -Value $VMNICFailoverStaticIp

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSubnetMask" -Value $VMNICFailoverSubnetMask

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestNetworkName" -Value $VMNICFailoverTestNetworkName

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestNetworkIdentifier" -Value $VMNICFailoverTestNetworkIdentifier

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDNSSuffix" -Value $VMNICFailoverTestDNSSuffix

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestShouldReplaceMacAddress" -Value $VMNICFailoverTestShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestGateway" -Value $VMNICFailoverTestGateway

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDHCP" -Value $VMNIsFailoverTestDHCP

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestPrimaryDns" -Value $VMNICFailoverTestPrimaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSecondaryDns" -Value $VMNICFailoverTestSecondaryDns

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestStaticIp" -Value $VMNICFailoverTestStaticIp

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSubnetMask" -Value $VMNICFailoverTestSubnetMask

$VMNICArray += $VMNICArrayLine

Page 52: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 52 OF 134

# End of per VM NIC actions below

}

# End of per VM NIC actions above

#

# End of per VM actions below

}

# End of per VM actions above

################################################

# Deleting VPG edit settings ID (same as closing the edit screen on a VPG in the ZVM without making any changes)

################################################

Try

{

Invoke-RestMethod -Method Delete -Uri $VPGSettingsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader_XML -ContentType $TypeXML

}

Catch [system.exception]

{

}

#

# End of check for valid VPG settings ID below

}

# End of check for valid VPG settings ID above

#

# End of per VPG actions below

}

# End of per VPG actions above

#

################################################

# Building Report No.x - Zerto designed report, summary of PODs

################################################

# Building Source POD Summary data

$PODProtectedArray = $ProtectedVPGArray | Where-Object {$_.SourcePOD -eq $SourcePOD}

$PODTotalVPGs = $PODProtectedArray | Measure-Object | select -ExpandProperty Count

$PODTotalVPGsMeetingSLA = $PODProtectedArray | Where-Object {$_.Status -eq "MeetingSLA"} | Measure-Object | select -ExpandProperty Count

$PODTotalVPGsNotMeetingSLA = $PODProtectedArray | Where-Object {$_.Status -ne "MeetingSLA"} | Measure-Object | select -ExpandProperty Count

$PODTotalHighPriorityVPGs = $PODProtectedArray | Where-Object {$_.Priority -eq "High"} | Measure-Object | select -ExpandProperty Count

$PODTotalMediumPriorityVPGs = $PODProtectedArray | Where-Object {$_.Priority -eq "Medium"} | Measure-Object | select -ExpandProperty Count

$PODTotalLowPriorityVPGs = $PODProtectedArray | Where-Object {$_.Priority -eq "Low"} | Measure-Object | select -ExpandProperty Count

$PODAverageRPO = $PODProtectedArray | select RPO | Measure-Object | select -ExpandProperty Count

$PODTotalProtectedSizeGB = ($PODProtectedArray.SizeInGb | Measure-Object -Sum).Sum

$PODTotalProtectedSizeTB = $PODTotalProtectedSizeGB / 1024

$PODTotalProtectedSizeTB = [math]::Round($PODTotalProtectedSizeTB,2)

$PODTotalJournalSizeGB = ($PODProtectedArray.JournalSizeInGb | Measure-Object -Sum).Sum

$PODTotalJournalSizeTB = $PODTotalJournalSizeGB / 1024

$PODTotalJournalSizeTB = [math]::Round($PODTotalJournalSizeTB,2)

# Getting Protected VM totals

$PODProtectedVMArray = $ProtectedVMArray | Where-Object {$_.SourcePOD -eq $SourcePOD}

$PODProtectedVMs = $PODProtectedVMArray | Measure-Object | select -ExpandProperty Count

# Getting UnProtected VM totals

$PODUnProtectedVMArray = $UnprotectedVMArray | Where-Object {$_.SourcePOD -eq $SourcePOD}

$PODUnProtectedVMs = $PODUnProtectedVMArray | Measure-Object | select -ExpandProperty Count

# POD total VMs

$PODTotalVMs = $PODProtectedVMs + $PODUnProtectedVMs

# Adding array line

$PODSummaryArrayLine = new-object PSObject

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "PODName" -Value "$SourcePOD"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "VMs" -Value "$PODTotalVMs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "VMsUnProtected" -Value "$PODUnProtectedVMs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "VMsProtected" -Value "$PODProtectedVMs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "VPGs" -Value "$PODTotalVPGs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "MeetingSLA" -Value "$PODTotalVPGsMeetingSLA"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "NotMeetingSLA" -Value "$PODTotalVPGsNotMeetingSLA"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "AverageRPO" -Value "$PODAverageRPO"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "HighPriority" -Value "$PODTotalHighPriorityVPGs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "MediumPriority" -Value "$PODTotalMediumPriorityVPGs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "LowPriority" -Value "$PODTotalLowPriorityVPGs"

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "ProtectedSizeTB" -Value "$PODTotalProtectedSizeTB"

Page 53: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 53 OF 134

$PODSummaryArrayLine | Add-Member -MemberType NoteProperty -Name "JournalSizeTB" -Value "$PODTotalJournalSizeTB"

$PODSummaryArray += $PODSummaryArrayLine

# Disconnecting from target vCenter, no longer needed

Disconnect-VIServer * -confirm:$false

# End of failed vCenter auth below

}

# End of failed vCenter auth above

else

{

# Failed vCenter auth, not running reports for POD

write-host "Failed to login to vCenter:$SourcevCenter

Skipping reports for POD:$SourcePOD"

}

# End of for each POD below

}

# End of for each POD above

#

################################################

# Function for building HTML table for ProtectedVPGArray

################################################

Function Create-ProtectedVPGArrayTable {

Param($Array,$TableCaption)

$ProtectedVPGArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">SourcePOD</th>

<th class="tg-foxd">TargetPOD</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMCount</th>

<th class="tg-foxd">Priority</th>

<th class="tg-foxd">RPO</th>

<th class="tg-foxd">RPOAlerts</th>

<th class="tg-foxd">Status</th>

<th class="tg-foxd">SizeInGB</th>

<th class="tg-foxd">JournalSizeInGB</th>

<th class="tg-foxd">AlertDescription</th>

</tr>

"@

# Building HTML table

$ProtectedVPGArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$SourcePOD = $_.SourcePOD

$TargetPOD = $_.TargetPOD

$VPGName = $_.VPGName

$VMCount = $_.VMCount

$Priority = $_.Priority

$RPO = $_.RPO

$RPOAlerts = $_.RPOAlerts

$Status = $_.Status

$SizeInGb = $_.SizeInGb

$JournalSizeInGb = $_.JournalSizeInGb

$AlertDescription = $_.AlertDescription

# Building HTML table row

$ProtectedVPGArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$SourcePOD</td>

<td class=""tg-yw4l"">$TargetPOD</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VMCount</td>

<td class=""tg-yw4l"">$Priority</td>

<td class=""tg-yw4l"">$RPO</td>

<td class=""tg-yw4l"">$RPOAlerts</td>

<td class=""tg-yw4l"">$Status</td>

Page 54: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 54 OF 134

<td class=""tg-yw4l"">$SizeInGb</td>

<td class=""tg-yw4l"">$JournalSizeInGb</td>

<td class=""tg-yw4l"">$AlertDescription</td>

</tr>

"

# Adding rows to table

$ProtectedVPGArrayHTMLTable += $ProtectedVPGArrayHTMLTableRow

}

# Compiling End of HTML email

$ProtectedVPGArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$ProtectedVPGArrayHTMLTable = $ProtectedVPGArrayHTMLTableStart + $ProtectedVPGArrayHTMLTable + $ProtectedVPGArrayHTMLTableEnd

$ProtectedVPGArrayHTMLTable

}

################################################

# Function for building HTML table for ProtectedVMArray

################################################

Function Create-ProtectedVMArrayTable {

Param($Array,$TableCaption)

$ProtectedVMArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">SourcePOD</th>

<th class="tg-foxd">SourceCluster</th>

<th class="tg-foxd">TargetPOD</th>

<th class="tg-foxd">TargetCluster</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMName</th>

<th class="tg-foxd">Priority</th>

<th class="tg-foxd">Status</th>

<th class="tg-foxd">RPO</th>

<th class="tg-foxd">Disks</th>

<th class="tg-foxd">SizeInGB</th>

<th class="tg-foxd">JournalSizeInGB</th>

</tr>

"@

# Building HTML table

$ProtectedVMArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$SourcePOD = $_.SourcePOD

$SourceCluster = $_.SourceCluster

$TargetPOD = $_.TargetPOD

$TargetCluster = $_.TargetCluster

$VPGName = $_.VPGName

$VMName = $_.VMName

$Priority = $_.Priority

$Status = $_.Status

$RPO = $_.RPO

$Disks = $_.Disks

$SizeInGb = $_.SizeInGb

$JournalSizeInGb = $_.JournalSizeInGb

# Building HTML table row

$ProtectedVMArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$SourcePOD</td>

<td class=""tg-yw4l"">$SourceCluster</td>

<td class=""tg-yw4l"">$TargetPOD</td>

<td class=""tg-yw4l"">$TargetCluster</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VMName</td>

Page 55: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 55 OF 134

<td class=""tg-yw4l"">$Priority</td>

<td class=""tg-yw4l"">$Status</td>

<td class=""tg-yw4l"">$RPO</td>

<td class=""tg-yw4l"">$Disks</td>

<td class=""tg-yw4l"">$SizeInGb</td>

<td class=""tg-yw4l"">$JournalSizeInGb</td>

</tr>

"

# Adding rows to table

$ProtectedVMArrayHTMLTable += $ProtectedVMArrayHTMLTableRow

}

# Compiling End of HTML email

$ProtectedVMArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$ProtectedVMArrayHTMLTable = $ProtectedVMArrayHTMLTableStart + $ProtectedVMArrayHTMLTable + $ProtectedVMArrayHTMLTableEnd

$ProtectedVMArrayHTMLTable

# End of ProtectedVMArrayTable function

}

################################################

# Function for building HTML table for TargetVRAArray

################################################

Function Create-TargetVRAArrayTable {

Param($Array,$TableCaption)

$TargetVRAArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">TargetPOD</th>

<th class="tg-foxd">VRACluster</th>

<th class="tg-foxd">RecoveryVRAName</th>

<th class="tg-foxd">ESXiHostname</th>

<th class="tg-foxd">VRAVPGs</th>

<th class="tg-foxd">VRAVMs</th>

<th class="tg-foxd">VRAVolumes</th>

<th class="tg-foxd">VRAVolumesTB</th>

<th class="tg-foxd">VRAJournalsTB</th>

<th class="tg-foxd">VMNumbervCPU</th>

<th class="tg-foxd">VMCpuUsedGhz</th>

<th class="tg-foxd">VMMemoryGB</th>

<th class="tg-foxd">VMActiveMemoryGB</th>

</tr>

"@

# Building HTML table

$TargetVRAArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$TargetPOD = $_.TargetPOD

$TargetCluster = $_.VRACluster

$VRAName = $_.VRAName

$ESXiHostname = $_.ESXiHostname

$VRAVPGs = $_.VRAVPGs

$VRAVMs = $_.VRAVMs

$VRAVolumes = $_.VRAVolumes

$VRARecoveryVolumesInTB = $_.VRARecoveryVolumesInTB

$VRARecoveryJournalsInTB = $_.VRARecoveryJournalsInTB

$VMNumberOfvCPU = $_.VMNumberOfvCPU

$VMCpuUsedInGhz = $_.VMCpuUsedInGhz

$VMMemoryInGB = $_.VMMemoryInGB

$VMActiveMemoryInGB = $_.VMActiveMemoryInGB

# Building HTML table row

$TargetVRAArrayHTMLTableRow = "

<tr>

Page 56: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 56 OF 134

<td class=""tg-yw4l"">$TargetPOD</td>

<td class=""tg-yw4l"">$TargetCluster</td>

<td class=""tg-yw4l"">$VRAName</td>

<td class=""tg-yw4l"">$ESXiHostname</td>

<td class=""tg-yw4l"">$VRAVPGs</td>

<td class=""tg-yw4l"">$VRAVMs</td>

<td class=""tg-yw4l"">$VRAVolumes</td>

<td class=""tg-yw4l"">$VRARecoveryVolumesInTB</td>

<td class=""tg-yw4l"">$VRARecoveryJournalsInTB</td>

<td class=""tg-yw4l"">$VMNumberOfvCPU</td>

<td class=""tg-yw4l"">$VMCpuUsedInGhz</td>

<td class=""tg-yw4l"">$VMMemoryInGB</td>

<td class=""tg-yw4l"">$VMActiveMemoryInGB</td>

</tr>

"

# Adding rows to table

$TargetVRAArrayHTMLTable += $TargetVRAArrayHTMLTableRow

}

# Compiling End of HTML email

$TargetVRAArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$TargetVRAArrayHTMLTable = $TargetVRAArrayHTMLTableStart + $TargetVRAArrayHTMLTable + $TargetVRAArrayHTMLTableEnd

$TargetVRAArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for UnprotectedVMArrayTable

################################################

Function Create-UnprotectedVMArrayTable {

Param($Array,$TableCaption)

$UnprotectedVMArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">SourcePOD</th>

<th class="tg-foxd">VMFolder</th>

<th class="tg-foxd">VMName</th>

<th class="tg-foxd">VMCluster</th>

<th class="tg-foxd">NumCPU</th>

<th class="tg-foxd">MemoryGB</th>

<th class="tg-foxd">NICS</th>

<th class="tg-foxd">HardDisks</th>

<th class="tg-foxd">UsedSpaceGB</th>

</tr>

"@

# Building HTML table

$UnprotectedVMArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$SourcePOD = $_.SourcePOD

$VMFolder = $_.VMFolder

$VMName = $_.VMName

$VMCluster = $_.VMCluster

$NumCPU = $_.NumCPU

$MemoryGB = $_.MemoryGB

$NICS = $_.NICS

$HardDisks = $_.HardDisks

$UsedSpaceGB = $_.UsedSpaceGB

# Building HTML table row

$UnprotectedVMArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$SourcePOD</td>

Page 57: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 57 OF 134

<td class=""tg-yw4l"">$VMFolder</td>

<td class=""tg-yw4l"">$VMName</td>

<td class=""tg-yw4l"">$VMCluster</td>

<td class=""tg-yw4l"">$NumCPU</td>

<td class=""tg-yw4l"">$MemoryGB</td>

<td class=""tg-yw4l"">$NICS</td>

<td class=""tg-yw4l"">$HardDisks</td>

<td class=""tg-yw4l"">$UsedSpaceGB</td>

</tr>

"

# Adding rows to table

$UnprotectedVMArrayHTMLTable += $UnprotectedVMArrayHTMLTableRow

}

# Compiling End of HTML email

$UnprotectedVMArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$UnprotectedVMArrayHTMLTable = $UnprotectedVMArrayHTMLTableStart + $UnprotectedVMArrayHTMLTable + $UnprotectedVMArrayHTMLTableEnd

$UnprotectedVMArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for TargetDatastoreArray

################################################

Function Create-TargetDatastoreArrayTable {

Param($Array,$TableCaption)

$TargetDatastoreArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">DatastoreCluster</th>

<th class="tg-foxd">DatastoreName</th>

<th class="tg-foxd">UsedByZVR</th>

<th class="tg-foxd">CapacityGB</th>

<th class="tg-foxd">FreeSpaceGB</th>

<th class="tg-foxd">FreePercent</th>

</tr>

"@

# Building HTML table

$TargetDatastoreArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$PODName = $_.PODName

$DatastoreCluster = $_.DatastoreCluster

$DatastoreName = $_.DatastoreName

$UsedByZVR = $_.UsedByZVR

$CapacityGB = $_.CapacityGB

$FreeSpaceGB = $_.FreeSpaceGB

$FreePercent = $_.FreePercent

# Building HTML table row

$TargetDatastoreArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$DatastoreCluster</td>

<td class=""tg-yw4l"">$DatastoreName</td>

<td class=""tg-yw4l"">$UsedByZVR</td>

<td class=""tg-yw4l"">$CapacityGB</td>

<td class=""tg-yw4l"">$FreeSpaceGB</td>

<td class=""tg-yw4l"">$FreePercent</td>

</tr>

"

# Adding rows to table

Page 58: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 58 OF 134

$TargetDatastoreArrayHTMLTable += $TargetDatastoreArrayHTMLTableRow

}

# Compiling End of HTML email

$TargetDatastoreArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$TargetDatastoreArrayHTMLTable = $TargetDatastoreArrayHTMLTableStart + $TargetDatastoreArrayHTMLTable + $TargetDatastoreArrayHTMLTableEnd

$TargetDatastoreArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for VPGArray

################################################

Function Create-VPGArrayTable {

Param($Array,$TableCaption)

$VPGArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMCount</th>

<th class="tg-foxd">Priortiy</th>

<th class="tg-foxd">ProtectedSiteName</th>

<th class="tg-foxd">RecoverySiteName</th>

<th class="tg-foxd">RpoInSeconds</th>

<th class="tg-foxd">TestIntervalInMinutes</th>

<th class="tg-foxd">UseWanCompression</th>

<th class="tg-foxd">BootGroupCount</th>

<th class="tg-foxd">BootGroupNames</th>

<th class="tg-foxd">BootGroupDelays</th>

<th class="tg-foxd">JournalHistoryInHours</th>

<th class="tg-foxd">JournalDatastoreClusterName</th>

<th class="tg-foxd">JournalDatastoreName</th>

<th class="tg-foxd">JournalHardLimitInMB</th>

<th class="tg-foxd">JournalHardLimitInPercent</th>

<th class="tg-foxd">JournalWarningThresholdInMB</th>

<th class="tg-foxd">JournalWarningThresholdInPercent</th>

<th class="tg-foxd">FailoverNetworkName</th>

<th class="tg-foxd">FailoverTestNetworkName</th>

<th class="tg-foxd">DefaultDatastoreName</th>

<th class="tg-foxd">DefaultFolderName</th>

<th class="tg-foxd">DefaultHostClusterName</th>

<th class="tg-foxd">DefaultHostName</th>

</tr>

"@

# Building HTML table

$VPGArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$PODName = $_.SourcePOD

$VPGName = $_.VPGName

$VPGidentifier = $_.VPGidentifier

$VPGOrganization = $_.VPGOrganization

$VPGVMCount = $_.VPGVMCount

$VPGPriortiy = $_.VPGPriortiy

$VPGProtectedSiteName = $_.VPGProtectedSiteName

$VPGProtectedSiteIdentifier = $_.VPGProtectedSiteIdentifier

$VPGRecoverySiteName = $_.VPGRecoverySiteName

$VPGRecoverySiteIdentifier = $_.VPGRecoverySiteIdentifier

$VPGRpoInSeconds = $_.VPGRpoInSeconds

$VPGServiceProfileIdentifier = $_.VPGServiceProfileIdentifier

$VPGTestIntervalInMinutes = $_.VPGTestIntervalInMinutes

Page 59: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 59 OF 134

$VPGUseWanCompression = $_.VPGUseWanCompression

$VPGZorgIdentifier = $_.VPGZorgIdentifier

$VPGBootGroupCount = $_.VPGBootGroupCount

$VPGBootGroupNames = $_.VPGBootGroupNames

$VPGBootGroupDelays = $_.VPGBootGroupDelays

$VPGBootGroupIdentifiers = $_.VPGBootGroupIdentifiers

$VPGJournalHistoryInHours = $_.VPGJournalHistoryInHours

$VPGJournalDatastoreClusterName = $_.VPGJournalDatastoreClusterName

$VPGJournalDatastoreClusterIdentifier = $_.VPGJournalDatastoreClusterIdentifier

$VPGJournalDatastoreName = $_.VPGJournalDatastoreName

$VPGJournalDatastoreIdentifier = $_.VPGJournalDatastoreIdentifier

$VPGJournalHardLimitInMB = $_.VPGJournalHardLimitInMB

$VPGJournalHardLimitInPercent = $_.VPGJournalHardLimitInPercent

$VPGJournalWarningThresholdInMB = $_.VPGJournalWarningThresholdInMB

$VPGJournalWarningThresholdInPercent = $_.VPGJournalWarningThresholdInPercent

$VPGFailoverNetworkName = $_.VPGFailoverNetworkName

$VPGFailoverNetworkID = $_.VPGFailoverNetworkID

$VPGFailoverTestNetworkName = $_.VPGFailoverTestNetworkName

$VPGFailoverTestNetworkID = $_.VPGFailoverTestNetworkID

$VPGDefaultDatastoreName = $_.VPGDefaultDatastoreName

$VPGDefaultDatastoreIdentifier = $_.VPGDefaultDatastoreIdentifier

$VPGDefaultFolderName = $_.VPGDefaultFolderName

$VPGDefaultFolderIdentifier = $_.VPGDefaultFolderIdentifier

$VPGDefaultHostClusterName = $_.VPGDefaultHostClusterName

$VPGDefaultHostClusterIdentifier = $_.VPGDefaultHostClusterIdentifier

$VPGDefaultHostName = $_.VPGDefaultHostName

$VPGDefaultHostIdentifier = $_.VPGDefaultHostIdentifier

$VPGResourcePoolName = $_.VPGResourcePoolName

$VPGResourcePoolIdentifier = $_.VPGResourcePoolIdentifier

$VPGScriptingPreRecovery = $_.VPGScriptingPreRecovery

$VPGScriptingPostRecovery = $_.VPGScriptingPostRecovery

# Building HTML table row

$VPGArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VPGVMCount</td>

<td class=""tg-yw4l"">$VPGPriortiy</td>

<td class=""tg-yw4l"">$VPGProtectedSiteName</td>

<td class=""tg-yw4l"">$VPGRecoverySiteName</td>

<td class=""tg-yw4l"">$VPGRpoInSeconds</td>

<td class=""tg-yw4l"">$VPGTestIntervalInMinutes</td>

<td class=""tg-yw4l"">$VPGUseWanCompression</td>

<td class=""tg-yw4l"">$VPGBootGroupCount</td>

<td class=""tg-yw4l"">$VPGBootGroupNames</td>

<td class=""tg-yw4l"">$VPGBootGroupDelays</td>

<td class=""tg-yw4l"">$VPGJournalHistoryInHours</td>

<td class=""tg-yw4l"">$VPGJournalDatastoreClusterName</td>

<td class=""tg-yw4l"">$VPGJournalDatastoreName</td>

<td class=""tg-yw4l"">$VPGJournalHardLimitInMB</td>

<td class=""tg-yw4l"">$VPGJournalHardLimitInPercent</td>

<td class=""tg-yw4l"">$VPGJournalWarningThresholdInMB</td>

<td class=""tg-yw4l"">$VPGJournalWarningThresholdInPercent</td>

<td class=""tg-yw4l"">$VPGFailoverNetworkName</td>

<td class=""tg-yw4l"">$VPGFailoverTestNetworkName</td>

<td class=""tg-yw4l"">$VPGDefaultDatastoreName</td>

<td class=""tg-yw4l"">$VPGDefaultFolderName</td>

<td class=""tg-yw4l"">$VPGDefaultHostClusterName</td>

<td class=""tg-yw4l"">$VPGDefaultHostName</td>

</tr>

"

# Adding rows to table

$VPGArrayHTMLTable += $VPGArrayHTMLTableRow

}

# Compiling End of HTML email

$VPGArrayHTMLTableEnd = @"

Page 60: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 60 OF 134

</table>

<br>

"@

# Compiling Final HTML

$VPGArrayHTMLTable = $VPGArrayHTMLTableStart + $VPGArrayHTMLTable + $VPGArrayHTMLTableEnd

$VPGArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for VMArray

################################################

Function Create-VMArrayTable {

Param($Array,$TableCaption)

$VMArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMName</th>

<th class="tg-foxd">NICCount</th>

<th class="tg-foxd">VolumeCount</th>

<th class="tg-foxd">ProvisionedStorageInMB</th>

<th class="tg-foxd">UsedStorageInMB</th>

<th class="tg-foxd">BootGroupName</th>

<th class="tg-foxd">BootGroupDelay</th>

<th class="tg-foxd">JournalDatastoreClusterName</th>

<th class="tg-foxd">JournalDatastoreName</th>

<th class="tg-foxd">JournalHardLimitInMB</th>

<th class="tg-foxd">JournalHardLimitInPercent</th>

<th class="tg-foxd">DatastoreClusterName</th>

<th class="tg-foxd">DatastoreName</th>

<th class="tg-foxd">FolderName</th>

<th class="tg-foxd">HostClusterName</th>

<th class="tg-foxd">HostName</th>

</tr>

"@

# Building HTML table

$VMArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$PODName = $_.SourcePOD

$VPGName = $_.VPGName

$VPGidentifier = $_.VPGidentifier

$VMName = $_.VMName

$VMIdentifier = $_.VMIdentifier

$VMNICCount = $_.VMNICCount

$VMVolumeCount = $_.VMVolumeCount

$VMProvisionedStorageInMB = $_.VMProvisionedStorageInMB

$VMUsedStorageInMB = $_.VMUsedStorageInMB

$VMBootGroupName = $_.VMBootGroupName

$VMBootGroupDelay = $_.VMBootGroupDelay

$VMBootGroupIdentifier = $_.VMBootGroupIdentifier

$VMJournalDatastoreClusterName = $_.VMJournalDatastoreClusterName

$VMJournalDatastoreClusterIdentifier = $_.VMJournalDatastoreClusterIdentifier

$VMJournalDatastoreName = $_.VMJournalDatastoreName

$VMJournalDatastoreIdentifier = $_.VMJournalDatastoreIdentifier

$VMJournalHardLimitInMB = $_.VMJournalHardLimitInMB

$VMJournalHardLimitInPercent = $_.VMJournalHardLimitInPercent

$VMDatastoreClusterName = $_.VMDatastoreClusterName

$VMDatastoreClusterIdentifier = $_.VMDatastoreClusterIdentifier

$VMDatastoreName = $_.VMDatastoreName

$VMDatastoreIdentifier = $_.VMDatastoreIdentifier

$VMFolderName = $_.VMFolderName

$VMFolderIdentifier = $_.VMFolderIdentifier

Page 61: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 61 OF 134

$VMHostClusterName = $_.VMHostClusterName

$VMHostClusterIdentifier = $_.VMHostClusterIdentifier

$VMHostName = $_.VMHostName

$VMHostIdentifier = $_.VMHostIdentifier

$VMResourcePoolName = $_.VMResourcePoolName

$VMResourcePoolIdentifier = $_.VMResourcePoolIdentifier

# Building HTML table row

$VMArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VMName</td>

<td class=""tg-yw4l"">$VMNICCount</td>

<td class=""tg-yw4l"">$VMVolumeCount</td>

<td class=""tg-yw4l"">$VMProvisionedStorageInMB</td>

<td class=""tg-yw4l"">$VMUsedStorageInMB</td>

<td class=""tg-yw4l"">$VMBootGroupName</td>

<td class=""tg-yw4l"">$VMBootGroupDelay</td>

<td class=""tg-yw4l"">$VMJournalDatastoreClusterName</td>

<td class=""tg-yw4l"">$VMJournalDatastoreName</td>

<td class=""tg-yw4l"">$VMJournalHardLimitInMB</td>

<td class=""tg-yw4l"">$VMJournalHardLimitInPercent</td>

<td class=""tg-yw4l"">$VMDatastoreClusterName</td>

<td class=""tg-yw4l"">$VMDatastoreName</td>

<td class=""tg-yw4l"">$VMFolderName</td>

<td class=""tg-yw4l"">$VMHostClusterName</td>

<td class=""tg-yw4l"">$VMHostName</td>

</tr>

"

# Adding rows to table

$VMArrayHTMLTable += $VMArrayHTMLTableRow

}

# Compiling End of HTML email

$VMArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$VMArrayHTMLTable = $VMArrayHTMLTableStart + $VMArrayHTMLTable + $VMArrayHTMLTableEnd

$VMArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for VMVolumeArray

################################################

Function Create-VMVolumeArrayTable {

Param($Array,$TableCaption)

$VMVolumeArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMName</th>

<th class="tg-foxd">VolumeID</th>

<th class="tg-foxd">VolumeIsSWAP</th>

<th class="tg-foxd">VolumeIsThin</th>

<th class="tg-foxd">VolumeDatastoreClusterName</th>

<th class="tg-foxd">VolumeDatastoreName</th>

</tr>

"@

# Building HTML table

$VMVolumeArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

Page 62: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 62 OF 134

$PODName = $_.SourcePOD

$VPGName = $_.VPGName

$VPGidentifier = $_.VPGidentifier

$VMName = $_.VMName

$VMIdentifier = $_.VMIdentifier

$VMVolumeID = $_.VMVolumeID

$VMVolumeIsSWAP = $_.VMVolumeIsSWAP

$VMVolumeIsThin = $_.VMVolumeIsThin

$VMVolumeDatastoreClusterName = $_.VMVolumeDatastoreClusterName

$VMVolumeDatastoreClusterIdentifier = $_.VMVolumeDatastoreClusterIdentifier

$VMVolumeDatastoreName = $_.VMVolumeDatastoreName

$VMVolumeDatastoreIdentifier = $_.VMVolumeDatastoreIdentifier

# Building HTML table row

$VMVolumeArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VMName</td>

<td class=""tg-yw4l"">$VMVolumeID</td>

<td class=""tg-yw4l"">$VMVolumeIsSWAP</td>

<td class=""tg-yw4l"">$VMVolumeIsThin</td>

<td class=""tg-yw4l"">$VMVolumeDatastoreClusterName</td>

<td class=""tg-yw4l"">$VMVolumeDatastoreName</td>

</tr>

"

# Adding rows to table

$VMVolumeArrayHTMLTable += $VMVolumeArrayHTMLTableRow

}

# Compiling End of HTML email

$VMVolumeArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$VMVolumeArrayHTMLTable = $VMVolumeArrayHTMLTableStart + $VMVolumeArrayHTMLTable + $VMVolumeArrayHTMLTableEnd

$VMVolumeArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for VMNICArray

################################################

Function Create-VMNICArrayTable {

Param($Array,$TableCaption)

$VMNICArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">VPGName</th>

<th class="tg-foxd">VMName</th>

<th class="tg-foxd">VMNICIdentifier</th>

<th class="tg-foxd">FailoverNetworkName</th>

<th class="tg-foxd">FailoverDNSSuffix</th>

<th class="tg-foxd">FailoverShouldReplaceMacAddress</th>

<th class="tg-foxd">FailoverGateway</th>

<th class="tg-foxd">FailoverDHCP</th>

<th class="tg-foxd">FailoverPrimaryDns</th>

<th class="tg-foxd">FailoverSecondaryDns</th>

<th class="tg-foxd">FailoverStaticIp</th>

<th class="tg-foxd">FailoverSubnetMask</th>

<th class="tg-foxd">FailoverTestNetworkName</th>

<th class="tg-foxd">FailoverTestDNSSuffix</th>

<th class="tg-foxd">FailoverTestShouldReplaceMacAddress</th>

<th class="tg-foxd">FailoverTestGateway</th>

<th class="tg-foxd">FailoverTestDHCP</th>

<th class="tg-foxd">FailoverTestPrimaryDns</th>

Page 63: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 63 OF 134

<th class="tg-foxd">FailoverTestSecondaryDns</th>

<th class="tg-foxd">FailoverTestStaticIp</th>

<th class="tg-foxd">FailoverTestSubnetMask</th>

</tr>

"@

# Building HTML table

$VMNICArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$PODName = $_.SourcePOD

$VPGName = $_.VPGName

$VPGidentifier = $_.VPGidentifier

$VMName = $_.VMName

$VMNICIdentifier = $_.VMIdentifier

$VMNICIdentifier = $_.VMNICIdentifier

$VMNICFailoverNetworkName = $_.VMNICFailoverNetworkName

$VMNICFailoverNetworkIdentifier = $_.VMNICFailoverNetworkIdentifier

$VMNICFailoverDNSSuffix = $_.VMNICFailoverDNSSuffix

$VMNICFailoverShouldReplaceMacAddress = $_.VMNICFailoverShouldReplaceMacAddress

$VMNICFailoverGateway = $_.VMNICFailoverGateway

$VMNICFailoverDHCP = $_.VMNICFailoverDHCP

$VMNICFailoverPrimaryDns = $_.VMNICFailoverPrimaryDns

$VMNICFailoverSecondaryDns = $_.VMNICFailoverSecondaryDns

$VMNICFailoverStaticIp = $_.VMNICFailoverStaticIp

$VMNICFailoverSubnetMask = $_.VMNICFailoverSubnetMask

$VMNICFailoverTestNetworkName = $_.VMNICFailoverTestNetworkName

$VMNICFailoverTestNetworkIdentifier = $_.VMNICFailoverTestNetworkIdentifier

$VMNICFailoverTestDNSSuffix = $_.VMNICFailoverTestDNSSuffix

$VMNICFailoverTestShouldReplaceMacAddress = $_.VMNICFailoverTestShouldReplaceMacAddress

$VMNICFailoverTestGateway = $_.VMNICFailoverTestGateway

$VMNICFailoverTestDHCP = $_.VMNICFailoverTestDHCP

$VMNICFailoverTestPrimaryDns = $_.VMNICFailoverTestPrimaryDns

$VMNICFailoverTestSecondaryDns = $_.VMNICFailoverTestSecondaryDns

$VMNICFailoverTestStaticIp = $_.VMNICFailoverTestStaticIp

$VMNICFailoverTestSubnetMask = $_.VMNICFailoverTestSubnetMask

# Building HTML table row

$VMNICArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$VPGName</td>

<td class=""tg-yw4l"">$VMName</td>

<td class=""tg-yw4l"">$VMNICIdentifier</td>

<td class=""tg-yw4l"">$VMNICFailoverNetworkName</td>

<td class=""tg-yw4l"">$VMNICFailoverDNSSuffix</td>

<td class=""tg-yw4l"">$VMNICFailoverShouldReplaceMacAddress</td>

<td class=""tg-yw4l"">$VMNICFailoverGateway</td>

<td class=""tg-yw4l"">$VMNICFailoverDHCP</td>

<td class=""tg-yw4l"">$VMNICFailoverPrimaryDns</td>

<td class=""tg-yw4l"">$VMNICFailoverSecondaryDns</td>

<td class=""tg-yw4l"">$VMNICFailoverStaticIp</td>

<td class=""tg-yw4l"">$VMNICFailoverSubnetMask</td>

<td class=""tg-yw4l"">$VMNICFailoverTestNetworkName</td>

<td class=""tg-yw4l"">$VMNICFailoverTestDNSSuffix</td>

<td class=""tg-yw4l"">$VMNICFailoverTestShouldReplaceMacAddress</td>

<td class=""tg-yw4l"">$VMNICFailoverTestGateway</td>

<td class=""tg-yw4l"">$VMNICFailoverTestDHCP</td>

<td class=""tg-yw4l"">$VMNICFailoverTestPrimaryDns</td>

<td class=""tg-yw4l"">$VMNICFailoverTestSecondaryDns</td>

<td class=""tg-yw4l"">$VMNICFailoverTestStaticIp</td>

<td class=""tg-yw4l"">$VMNICFailoverTestSubnetMask</td>

</tr>

"

# Adding rows to table

$VMNICArrayHTMLTable += $VMNICArrayHTMLTableRow

}

Page 64: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 64 OF 134

# Compiling End of HTML email

$VMNICArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$VMNICArrayHTMLTable = $VMNICArrayHTMLTableStart + $VMNICArrayHTMLTable + $VMNICArrayHTMLTableEnd

$VMNICArrayHTMLTable

# End of TargetVRAArrayTable function

}

################################################

# Function for building HTML table for PODSummaryArray

################################################

Function Create-PODSummaryArrayTable {

Param($Array,$TableCaption)

$PODSummaryArrayHTMLTableStart = @"

<table class="tg">

<caption><span class="caption">$TableCaption</span></caption>

<tr>

<th class="tg-foxd">PODName</th>

<th class="tg-foxd">VMs</th>

<th class="tg-foxd">Protected</th>

<th class="tg-foxd">UnProtected</th>

<th class="tg-foxd">VPGs</th>

<th class="tg-foxd">MeetingSLA</th>

<th class="tg-foxd">NotMeetingSLA</th>

<th class="tg-foxd">AverageRPO</th>

<th class="tg-foxd">HighPriority</th>

<th class="tg-foxd">MediumPriority</th>

<th class="tg-foxd">LowPriority</th>

<th class="tg-foxd">ProtectedSizeTB</th>

<th class="tg-foxd">JournalSizeTB</th>

</tr>

"@

# Building HTML table

$PODSummaryArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

$PODName = $_.PODName

$VMs = $_.VMs

$VMsUnProtected = $_.VMsUnProtected

$VMsProtected = $_.VMsProtected

$VPGs = $_.VPGs

$MeetingSLA = $_.MeetingSLA

$NotMeetingSLA = $_.NotMeetingSLA

$AverageRPO = $_.AverageRPO

$HighPriority = $_.HighPriority

$MediumPriority = $_.MediumPriority

$LowPriority = $_.LowPriority

$ProtectedSizeTB = $_.ProtectedSizeTB

$JournalSizeTB = $_.JournalSizeTB

# Building HTML table row

$PODSummaryArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$PODName</td>

<td class=""tg-yw4l"">$VMs</td>

<td class=""tg-yw4l"">$VMsProtected</td>

<td class=""tg-yw4l"">$VMsUnProtected</td>

<td class=""tg-yw4l"">$VPGs</td>

<td class=""tg-yw4l"">$MeetingSLA</td>

<td class=""tg-yw4l"">$NotMeetingSLA</td>

<td class=""tg-yw4l"">$AverageRPO</td>

<td class=""tg-yw4l"">$HighPriority</td>

<td class=""tg-yw4l"">$MediumPriority</td>

<td class=""tg-yw4l"">$LowPriority</td>

Page 65: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 65 OF 134

<td class=""tg-yw4l"">$ProtectedSizeTB</td>

<td class=""tg-yw4l"">$JournalSizeTB</td>

</tr>

"

# Adding rows to table

$PODSummaryArrayHTMLTable += $PODSummaryArrayHTMLTableRow

}

# Compiling End of HTML email

$PODSummaryArrayHTMLTableEnd = @"

</table>

<br>

"@

# Compiling Final HTML

$PODSummaryArrayHTMLTable = $PODSummaryArrayHTMLTableStart + $PODSummaryArrayHTMLTable + $PODSummaryArrayHTMLTableEnd

$PODSummaryArrayHTMLTable

# End of TargetVRAArrayTable function

}

########################################################################################################################

# Customize reports below

########################################################################################################################

#########################################################################

# Building & Sending Report - POD Summary Report

#########################################################################

# Setting Email subject

$Subject = "Zerto POD Summary Report"

# Creating Tables for Email Body

# Table1

$PODSummaryArraySorted = $PODSummaryArray | Sort-Object PODName

$PODSummaryArrayHTML = Create-PODSummaryArrayTable -Array $PODSummaryArraySorted -TableCaption "POD Summary"

# Table2

$VPGAlerts = $ProtectedVPGArray | Where-Object {$_.Status -ne "MeetingSLA" -or $_.RPOAlerts -ge "1"} | Sort-Object SourcePOD,VPGName

if ($VPGAlertArraySorted -ne $null)

{

$VPGAlertArrayHTML = Create-ProtectedVPGArrayTable -Array $VPGAlerts -TableCaption "All VPG Violations by POD and VPGName"

}

else

{

$VPGAlertArrayHTML = $null

}

# Table2

$TargetDatastoreAlerts = $TargetDatastoreArray | where-object {$_.UsedByZVR -eq "TRUE" -and $_.FreePercent -le "35"} | Sort-Object PODName,FreeSpaceGB

# Only creating table if entries exist

if ($TargetDatastoreAlerts -ne $null)

{

$TargetDatastoreAlertHTML = Create-TargetDatastoreArrayTable -Array $TargetDatastoreAlerts -TableCaption "ZVR Datastores with less than 35% FreeSpace"

}

else

{

$TargetDatastoreAlertHTML = $null

}

# Table3

$ProtectedVPGArraySorted = $ProtectedVPGArray | Sort-Object SourcePOD,VPGName

$ProtectedVPGArrayHTML = Create-ProtectedVPGArrayTable -Array $ProtectedVPGArraySorted -TableCaption "All VPGs by POD and VPGName"

# Table4

$ProtectedVMArraySorted = $ProtectedVMArray | Sort-Object SourcePOD,SourceCluster,VPGName,VMName

$ProtectedVMArrayHTML = Create-ProtectedVMArrayTable -Array $ProtectedVMArraySorted -TableCaption "Protected VMs by POD, Cluster, VPGName and VMName"

# Table5

$UnprotectedVMArraySorted = $UnprotectedVMArray | Sort-Object SourcePOD,VMFolder,VMName

$UnprotectedVMArrayHTML = Create-UnprotectedVMArrayTable -Array $UnprotectedVMArraySorted -TableCaption "UnProtected VMs by POD, Folder and VMName"

# Table6

$TargetVRAArraySorted = $TargetVRAArray | Sort-Object TargetPOD,VRAName

$TargetVRAArrayHTML = Create-TargetVRAArrayTable -Array $TargetVRAArraySorted -TableCaption "VRAs by TargetPOD and VRAName"

# Table7

$TargetDatastoreArraySorted = $TargetDatastoreArray | where-object {$_.UsedByZVR -eq "TRUE"} | Sort-Object PODName,FreeSpaceGB

$TargetDatastoreArrayHTML = Create-TargetDatastoreArrayTable -Array $TargetDatastoreArraySorted -TableCaption "All ZVR Datastores by POD and least FreeSpace"

# Building Email Body

Page 66: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 66 OF 134

$Body = $ReportHTMLTableStyle + $PODSummaryArrayHTML + $VPGAlertArrayHTML + $TargetDatastoreAlertHTML + $ProtectedVPGArrayHTML + $ProtectedVMArrayHTML + $UnprotectedVMArrayHTML + $TargetVRAArrayHTML + $TargetDatastoreArrayHTML

# Saving CSVs of sorted arrays to disk, required to then email

$EmailAttachment1 = Save-CSV -Array $PODSummaryArraySorted -CSVFileName "PODSummaryArray" -CSVDirectory $CSVDirectory

# $EmailAttachment2 = Save-CSV -Array $VPGArray -CSVFileName "VPGArray2" -CSVDirectory $CSVDirectory

# Combining attachments if multiple are required

# $MultipleAttachments = @("$EmailAttachment1","$EmailAttachment2")

# Sending the email

Email-ZVRReport -EmailTo $EmailList1 -Subject $Subject -Body $Body -SMTPProfile $SMTPProfile1 -Attachment $EmailAttachment1

#########################################################################

# Building & Sending Report - VPG and VM Settings Report

#########################################################################

# Setting Email subject

$Subject = "Zerto VPG and VM Settings Report"

# Creating Tables for Email Body

# VPG settings table

$VPGArraySorted1 = $VPGArray | Sort-Object PODName,VPGName

$VPGArrayHTMLTable1 = Create-VPGArrayTable -Array $VPGArraySorted1 -TableCaption "VPG Settings by PODName and VPGName"

# VM settings table

$VMArraySorted1 = $VMArray | Sort-Object PODName,VPGName,VMName

$VMArrayHTMLTable1 = Create-VMArrayTable -Array $VMArraySorted1 -TableCaption "VM Settings by PODName, VPGName and VMName"

# Volume settings table

$VMVolumeArraySorted1 = $VMVolumeArray | Sort-Object PODName,VPGName,VMName,VMVolumeID

$VMVolumeArrayHTMLTable1 = Create-VMVolumeArrayTable -Array $VMVolumeArraySorted1 -TableCaption "Volume Settings by PODName, VPGName, VMName and VMVolumeID"

# NIC settings table

$VMNICArraySorted1 = $VMNICArray | Sort-Object PODName,VPGName,VMName,VMNICIdentifier

$VMNICArrayHTMLTable1 = Create-VMNICArrayTable -Array $VMNICArraySorted1 -TableCaption "NIC Settings by PODName, VPGName, VMName and VMNICIdentifier"

# Building Email Body

$Body = $ReportHTMLTableStyle + $VPGArrayHTMLTable1 + $VMArrayHTMLTable1 + $VMVolumeArrayHTMLTable1 + $VMNICArrayHTMLTable1

# Saving CSVs of sorted arrays to disk, required to then email

$EmailAttachment1 = Save-CSV -Array $VPGArraySorted1 -CSVFileName "ZVRVPGSettings" -CSVDirectory $CSVDirectory

$EmailAttachment2 = Save-CSV -Array $VMArraySorted1 -CSVFileName "ZVRVMSettings" -CSVDirectory $CSVDirectory

$EmailAttachment3 = Save-CSV -Array $VMVolumeArraySorted1 -CSVFileName "ZVRVolumeSettings" -CSVDirectory $CSVDirectory

$EmailAttachment4 = Save-CSV -Array $VMNICArraySorted1 -CSVFileName "ZVRNICSettings" -CSVDirectory $CSVDirectory

# Combining attachments if multiple are required

$MultipleAttachments = @("$EmailAttachment1","$EmailAttachment2","$EmailAttachment3","$EmailAttachment4")

# Sending the email

Email-ZVRReport -EmailTo $EmailList1 -Subject $Subject -Body $Body -SMTPProfile $SMTPProfile1 -Attachment $MultipleAttachments

Page 67: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 67 OF 134

5 AUTOMATING DEPLOYMENT

5.1 Use Cases

The simple interface of Zerto makes the initial deployment a very simple task. However, the number of clicks required can become cumbersome and error-prone at scale when you are protecting hundreds to thousands of VMs across hundreds of hypervisor hosts. To resolve these challenges, the REST API can be utilized to not only automate the deployment of Virtual Replication Appliances (VRAs), but it can also be used to create the Virtual Protection Groups (VPGs). All examples given in this section of the document will include the full script due to the increased length of the examples. Comments are used throughout the examples to explain each component. When first testing automation scripts it is recommended to use non-production test VMs or hypervisor hosts. Powered-On Test VMs with no OS installed and a 1GB thin VMDK are ideal for VM protection automation testing due to the speed at which they are protected once a VPG is configured.

5.2 Bulk Automated VRA Deployment

To begin create a VRADeploymentESXiHosts.csv containing all the hosts and VRA settings to use for VRA deployment with the following column headings:

• ESXiHostName • DatastoreName

• PortGroupName

• VRAGroupName

• MemoryInGB

• DefaultGateway

• SubnetMask

• VRAIPAddress Ensure that the names of ESXi hosts, datastores and port groups are all 100% correct otherwise the script will fail. VRA Groups should be configured per physical datacenter and so will usually match your vCenter name. Following is an example:

The CSV can now be utilized to deploy the VRAs one by one, by configuring the variables in the following script: ################################################

# Configure the variables below

################################################

$LogDataDir = "C:\ZVRAPIBulkVRAScript\"

$ESXiHostCSV = "C:\ZVRAPIBulkVRAScript\VRADeploymentESXiHosts.csv"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Password123"

$SecondsBetweenVRADeployments = "120"

Page 68: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 68 OF 134

##################################################################################

# Nothing to configure below this line - Starting the main function of the script

##################################################################################

################################################

# Setting log directory for engine and current month

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentTime = get-date -format hh.mm.ss

$CurrentLogDataDir = $LogDataDir + $CurrentMonth

$CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt"

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

}

start-transcript -path $CurrentLogDataFile -NoClobber

################################################

# Setting Cert Policy - required for successful auth with the Zerto API

################################################

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 Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# Get SiteIdentifier for getting Network Identifier later in the script

$SiteInfoURL = $BaseURL+"localsite"

$SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$SiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

$VRAInstallURL = $BaseURL+"vras"

################################################

# Importing the CSV of ESXi hosts to deploy VRA to

################################################

$ESXiHostCSVImport = Import-Csv $ESXiHostCSV

################################################

# Starting Install Process for each ESXi host specified in the CSV

################################################

foreach ($ESXiHost in $ESXiHostCSVImport)

{

# Setting variables for ease of use throughout script

$VRAESXiHostName = $ESXiHost.ESXiHostName

$VRADatastoreName = $ESXiHost.DatastoreName

Page 69: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 69 OF 134

$VRAPortGroupName = $ESXiHost.PortGroupName

$VRAGroupName = $ESXiHost.VRAGroupName

$VRAMemoryInGB = $ESXiHost.MemoryInGB

$VRADefaultGateway = $ESXiHost.DefaultGateway

$VRASubnetMask = $ESXiHost.SubnetMask

$VRAIPAddress = $ESXiHost.VRAIPAddress

# Get NetworkIdentifier for API

$APINetworkURL = $BaseURL+"virtualizationsites/$SiteIdentifier/networks"

$APINetworkCMD = Invoke-RestMethod -Uri $APINetworkURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$NetworkIdentifier = $APINetworkCMD | Where-Object {$_.VirtualizationNetworkName -eq $VRAPortGroupName} | Select -ExpandProperty NetworkIdentifier

# Get HostIdentifier for API

$APIHostURL = $BaseURL+"virtualizationsites/$SiteIdentifier/hosts"

$APIHostCMD = Invoke-RestMethod -Uri $APIHostURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$VRAESXiHostID = $APIHostCMD | Where-Object {$_.VirtualizationHostName -eq $VRAESXiHostName} | Select -ExpandProperty HostIdentifier

# Get DatastoreIdentifier for API

$APIDatastoreURL = $BaseURL+"virtualizationsites/$SiteIdentifier/datastores"

$APIDatastoreCMD = Invoke-RestMethod -Uri $APIDatastoreURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$VRADatastoreID = $APIDatastoreCMD | Where-Object {$_.DatastoreName -eq $VRADatastoreName} | Select -ExpandProperty DatastoreIdentifier

# Creating JSON Body for API settings

$JSON =

"{

""DatastoreIdentifier"": ""$VRADatastoreID"",

""GroupName"": ""$VRAGroupName"",

""HostIdentifier"": ""$VRAESXiHostID"",

""HostRootPassword"":null,

""MemoryInGb"": ""$VRAMemoryInGB"",

""NetworkIdentifier"": ""$NetworkIdentifier"",

""UsePublicKeyInsteadOfCredentials"":true,

""VraNetworkDataApi"": {

""DefaultGateway"": ""$VRADefaultGateway"",

""SubnetMask"": ""$VRASubnetMask"",

""VraIPAddress"": ""$VRAIPAddress"",

""VraIPConfigurationTypeApi"": ""Static""

}

}"

write-host "Executing $JSON"

# Now trying API install cmd

Try

{

Invoke-RestMethod -Method Post -Uri $VRAInstallURL -Body $JSON -ContentType $TypeJSON -Headers $zertoSessionHeader

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

# Waiting xx seconds before deploying the next VRA

write-host "Waiting $SecondsBetweenVRADeployments seconds before deploying the next VRA or stopping"

sleep $SecondsBetweenVRADeployments

# End of per Host operations below

}

# End of per Host operations above

################################################

# Stopping logging

################################################

Stop-Transcript

Page 70: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 70 OF 134

5.3 Bulk Automated VPG Creation – ZVM Only

This example is only for a Zerto Virtual Manager (ZVM) that is not managed by a Zerto Cloud Manager (ZCM) and therefore does not use Zerto Service Profiles. Bulk VM protection can be achieved using 2 CSV files. The first containing a list of Virtual Protection Groups (VPGs) with the VPG settings and the second a list of VMs to protect with their respective VPGs. VPG names must be unique, any duplicate entries will break the script. Friendly vSphere names are used for all the VPG settings which must match as they are shown in vCenter. For the VPG settings create a CSV with the following columns:

• VPGName

• JournalHistoryInHours

• ReplicationPriority

• RecoverySiteName

• RpoAlertInSeconds

• TestIntervalInMinutes

• ClusterName

• FailoverNetwork

• TestNetwork

• DatastoreName

• JournalDatastore

• JournalHardLimitInMB

• JournalWarningThresholdInMB

• vCenterFolder The RecoverySiteName is the target ZVM name and the default test interval 262080 shown below is recommended as per:

Now create a CSV containing the VM names, with respective VPGs, with the following columns:

• VMName

• VPGName The script supports multiple VMs per VPG, but keep in mind that in ZVR versions 4.5 and earlier a VM can only exist in 1 VPG at once when building out your list. Here you can see an example of this:

Page 71: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 71 OF 134

Once both CSVs have been configured, set the variables at the top of the below script to automate bulk VM protection:

################################################

# Configure the variables below

################################################

$LogDataDir = "C:\ZVRBulkVMProtection\"

$VPGList = "C:\ZVRBulkVMProtection\ZVRBulkVMProtectionv1b-VPGs.csv"

$VMList = "C:\ZVRBulkVMProtection\ZVRBulkVMProtectionv1b-VMs.csv"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

$TimeToWaitBetweenVPGCreation = "120"

####################################################################################################

# Nothing to configure below this line - Starting the main function of the script

####################################################################################################

################################################

# Setting log directory and starting transcript logging

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentTime = get-date -format hh.mm.ss

$CurrentLogDataDir = $LogDataDir + $CurrentMonth

$CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt"

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

}

start-transcript -path $CurrentLogDataFile -NoClobber

################################################

# Setting Cert Policy - required for successful auth with the Zerto API

################################################

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 Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

# Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# URL to create VPG settings

Page 72: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 72 OF 134

$CreateVPGURL = $BaseURL+"vpgSettings"

################################################

# Importing the CSV of Profiles to use for VM Protection

################################################

$VPGCSVImport = Import-Csv $VPGList

$VMCSVImport = Import-Csv $VMList

################################################

# Running the creation process by VPG, as a VPG can contain multiple VMs

################################################

foreach ($VPG in $VPGCSVImport)

{

$VPGName = $VPG.VPGName

$ReplicationPriority = $VPG.ReplicationPriority

$RecoverySiteName = $VPG.RecoverySiteName

$ClusterName = $VPG.ClusterName

$FailoverNetwork = $VPG.FailoverNetwork

$TestNetwork = $VPG.TestNetwork

$DatastoreName = $VPG.DatastoreName

$JournalDatastore = $VPG.JournalDatastore

$vCenterFolder = $VPG.vCenterFolder

$JournalHistoryInHours = $VPG.JournalHistoryInHours

$RpoAlertInSeconds = $VPG.RpoAlertInSeconds

$TestIntervalInMinutes = $VPG.TestIntervalInMinutes

$JournalHardLimitInMB = $VPG.JournalHardLimitInMB

$JournalWarningThresholdInMB = $VPG.JournalWarningThresholdInMB

# Getting list of VMs for the VPG

$VPGVMs = $VMCSVImport | Where {$_.VPGName -Match "$VPGName"}

$VPGVMNames = $VPGVMs.VMName

# Logging and showing action

write-host "Creating Protection Group:$VPGName for VMs:$VPGVMNames"

################################################

# Getting Identifiers for VPG settings

################################################

# Get SiteIdentifier for getting Local Identifier later in the script

$SiteInfoURL = $BaseURL+"localsite"

$SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

# Get SiteIdentifier for getting Identifiers

$TargetSiteInfoURL = $BaseURL+"virtualizationsites"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$TargetSiteIdentifier = $TargetSiteInfoCMD | Where-Object {$_.VirtualizationSiteName -eq $RecoverySiteName} | select SiteIdentifier -ExpandProperty SiteIdentifier

# Get NetworkIdentifiers for API

$VISiteInfoURL1 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/networks"

$VISiteInfoCMD1 = Invoke-RestMethod -Uri $VISiteInfoURL1 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FailoverNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $FailoverNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

$TestNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $TestNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

# Get ClusterIdentifier for API

$VISiteInfoURL2 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hostclusters"

$VISiteInfoCMD2 = Invoke-RestMethod -Uri $VISiteInfoURL2 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ClusterIdentifier = $VISiteInfoCMD2 | Where-Object {$_.VirtualizationClusterName -eq $ClusterName} | Select ClusterIdentifier -ExpandProperty ClusterIdentifier

# Get ServiceProfileIdenfitifer for API

$VISiteServiceProfileURL = $BaseURL+"serviceprofiles"

$VISiteServiceProfileCMD = Invoke-RestMethod -Uri $VISiteServiceProfileURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ServiceProfileIdentifier = $VISiteServiceProfileCMD | Where-Object {$_.Description -eq $ServiceProfile} | Select ServiceProfileIdentifier -ExpandProperty ServiceProfileIdentifier

# Get DatastoreIdentifiers for API

$VISiteInfoURL3 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastores"

$VISiteInfoCMD3 = Invoke-RestMethod -Uri $VISiteInfoURL3 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$DatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $DatastoreName} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

$JournalDatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $JournalDatastore} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

# Get Folders for API

$VISiteInfoURL4 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/folders"

$VISiteInfoCMD4 = Invoke-RestMethod -Uri $VISiteInfoURL4 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FolderIdentifier = $VISiteInfoCMD4 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select FolderIdentifier -ExpandProperty FolderIdentifier

################################################

# Getting a VM identifier for each VM to be protected and adding it to the VMIDarray

################################################

Page 73: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 73 OF 134

# Reseting VM identifier list, required for creating multiple protection groups

$VMIdentifierList = $null

$VMIDArray = @()

# Running for each VM operation against the VPG name

foreach ($VMLine in $VPGVMNames)

{

write-host "$VMLine"

$VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms"

$VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$VMIdentifier = $VMInfoCMD | Where-Object {$_.VmName -eq $VMLine} | select VmIdentifier -ExpandProperty VmIdentifier

# Adding VM ID to array

$VMIDArrayLine = new-object PSObject

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMID" -Value $VMIdentifier

$VMIDArray += $VMIDArrayLine

}

################################################

# Building JSON Request for posting VPG settings to API

################################################

$JSONMain =

"{

""Backup"": null,

""Basic"": {

""JournalHistoryInHours"": ""$JournalHistoryInHours"",

""Name"": ""$VPGName"",

""Priority"": ""$ReplicationPriority"",

""ProtectedSiteIdentifier"": ""$LocalSiteIdentifier"",

""RecoverySiteIdentifier"": ""$TargetSiteIdentifier"",

""RpoInSeconds"": ""$RpoAlertInSeconds"",

""ServiceProfileIdentifier"": null,

""TestIntervalInMinutes"": ""$TestIntervalInMinutes"",

""UseWanCompression"": true,

""ZorgIdentifier"": null

},

""BootGroups"": {

""BootGroups"": [

{

""BootDelayInSeconds"": 0,

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000000"",

""Name"": ""Default""

}

]

},

""Journal"": {

""DatastoreClusterIdentifier"":null,

""DatastoreIdentifier"":""$DatastoreIdentifier"",

""Limitation"":{

""HardLimitInMB"":""$JournalHardLimitInMB"",

""HardLimitInPercent"":null,

""WarningThresholdInMB"":""$JournalWarningThresholdInMB"",

""WarningThresholdInPercent"":null

}

},

""Networks"": {

""Failover"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$FailoverNetworkIdentifier""

}

},

""FailoverTest"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$TestNetworkIdentifier""

}

}

},

""Recovery"": {

""DefaultDatastoreIdentifier"":""$DatastoreIdentifier"",

Page 74: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 74 OF 134

""DefaultFolderIdentifier"":""$FolderIdentifier"",

""DefaultHostClusterIdentifier"":""$ClusterIdentifier"",

""DefaultHostIdentifier"":null,

""ResourcePoolIdentifier"":null

},

""Scripting"": {

""PostBackup"": null,

""PostRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

},

""PreRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

}

},

""Vms"": ["

# Resetting VMs if a previous VPG was created in this run of the script

$JSONVMs = $null

# Creating JSON request per VM using the VM array for all the VMs in the VPG

foreach ($VM in $VMIDArray)

{

$VMID = $VM.VMID

$JSONVMsLine = "{""VmIdentifier"":""$VMID""}"

# Running if statement to check if this is the first VM in the array, if not then a comma is added to string

if ($JSONVMs -ne $null)

{

$JSONVMsLine = "," + $JSONVMsLine

}

$JSONVMs = $JSONVMs + $JSONVMsLine

}

# Creating the end of the JSON request

$JSONEnd = "]

}"

# Putting the JSON request elements together and outputting the request

$JSON = $JSONMain + $JSONVMs + $JSONEnd

write-host "Running JSON request below:

$JSON"

################################################

# Posting the VPG JSON Request to the API

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader

write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier"

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Confirming VPG settings from API

################################################

$ConfirmVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"

$ConfirmVPGSettingCMD = Invoke-RestMethod -Uri $ConfirmVPGSettingURL -Headers $zertosessionHeader -ContentType $TypeJSON

################################################

# Committing the VPG settings to be created

################################################

$CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit"

write-host "Commiting VPG creation for VPG:$VPGName with URL:

$CommitVPGSettingURL"

Try

{

Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100

Page 75: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 75 OF 134

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG

################################################

write-host "Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG or stopping script if on the last VPG"

sleep $TimeToWaitBetweenVPGCreation

#

# End of per VPG actions below

}

# End of per VPG actions above

#

################################################

# Stopping logging

################################################

Stop-Transcript

Page 76: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 76 OF 134

5.4 Bulk Automated VPG Creation – ZVM & ZCM

This example is only for a Zerto Virtual Manager (ZVM) that is managed by a Zerto Cloud Manager (ZCM) and therefores requires the use Zerto Service Profiles in the REST API. Bulk VM protection can be achieved using 2 CSV files. The first containing a list of Virtual Protection Groups (VPGs) with the VPG settings and the second a list of VMs to protect with their respective VPGs. VPG names must be unique, any duplicate entries will break the script. Friendly vSphere names are used for all the VPG settings which must match as they are shown in vCenter. For the VPG settings create a CSV with the following columns:

• VPGName

• ServiceProfile

• ReplicationPriority

• RecoverySiteName

• ClusterName

• FailoverNetwork

• TestNetwork

• DatastoreName

• JournalDatastore

• vCenterFolder The RecoverySiteName is the target ZVM name and the Service Profile should be created in the ZCM in advance, it cannot be the service profile that already exists when the ZCM is deployed it must be a new profile as per the below example CSV:

Now create a CSV containing the VM names, with respective VPGs, with the following columns:

• VMName

• VPGName The script supports multiple VMs per VPG, but keep in mind that in ZVR versions 4.5 and earlier a VM can only exist in 1 VPG at once when building out your list. Here you can see an example of this:

Page 77: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 77 OF 134

Once both CSVs have been configured, set the variables at the top of the below script to automate bulk VM protection: ################################################

# Configure the variables below

################################################

$LogDataDir = "C:\ZVRBulkVMProtection\"

$VPGList = "C:\BulkVMProtection\ZVRBulkVMProtectionv1a-VPGs.csv"

$VMList = "C:\BulkVMProtection\ZVRBulkVMProtectionv1a-VMs.csv"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

$TimeToWaitBetweenVPGCreation = "120"

####################################################################################################

# Nothing to configure below this line - Starting the main function of the script

####################################################################################################

################################################

# Setting log directory and starting transcript logging

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentTime = get-date -format hh.mm.ss

$CurrentLogDataDir = $LogDataDir + $CurrentMonth

$CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\BulkVPGCreationLog-" + $CurrentTime + ".txt"

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

}

start-transcript -path $CurrentLogDataFile -NoClobber

################################################

# Setting Cert Policy - required for successful auth with the Zerto API without connecting to vsphere using PowerCLI

################################################

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 Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $ContentType

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# URL to create VPG settings

$CreateVPGURL = $BaseURL+"vpgSettings"

Page 78: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 78 OF 134

################################################

# Importing the CSV of Profiles to use for VM Protection

################################################

$VPGCSVImport = Import-Csv $VPGList

$VMCSVImport = Import-Csv $VMList

################################################

# Running the creation process by VPG, as a VPG can contain multiple VMs

################################################

foreach ($VPG in $VPGCSVImport)

{

$VPGName = $VPG.VPGName

$ServiceProfile = $VPG.ServiceProfile

$ReplicationPriority = $VPG.ReplicationPriority

$RecoverySiteName = $VPG.RecoverySiteName

$ClusterName = $VPG.ClusterName

$FailoverNetwork = $VPG.FailoverNetwork

$TestNetwork = $VPG.TestNetwork

$DatastoreName = $VPG.DatastoreName

$JournalDatastore = $VPG.JournalDatastore

$vCenterFolder = $VPG.vCenterFolder

# Getting list of VMs for the VPG

$VPGVMs = $VMCSVImport | Where {$_.VPGName -Match "$VPGName"}

$VPGVMNames = $VPGVMs.VMName

# Logging and showing action

write-host "Creating Protection Group:$VPGName for VMs:$VPGVMNames"

################################################

# Getting Identifiers for VPG settings

################################################

# Get SiteIdentifier for getting Local Identifier later in the script

$SiteInfoURL = $BaseURL+"localsite"

$SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

# Get SiteIdentifier for getting Identifiers

$TargetSiteInfoURL = $BaseURL+"virtualizationsites"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$TargetSiteIdentifier = $TargetSiteInfoCMD | Where-Object {$_.VirtualizationSiteName -eq $RecoverySiteName} | select SiteIdentifier -ExpandProperty SiteIdentifier

# Get NetworkIdentifiers for API

$VISiteInfoURL1 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/networks"

$VISiteInfoCMD1 = Invoke-RestMethod -Uri $VISiteInfoURL1 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$FailoverNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $FailoverNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

$TestNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $TestNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

# Get ClusterIdentifier for API

$VISiteInfoURL2 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hostclusters"

$VISiteInfoCMD2 = Invoke-RestMethod -Uri $VISiteInfoURL2 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$ClusterIdentifier = $VISiteInfoCMD2 | Where-Object {$_.VirtualizationClusterName -eq $ClusterName} | Select ClusterIdentifier -ExpandProperty ClusterIdentifier

# Get ServiceProfileIdenfitifer for API

$VISiteServiceProfileURL = $BaseURL+"serviceprofiles"

$VISiteServiceProfileCMD = Invoke-RestMethod -Uri $VISiteServiceProfileURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$ServiceProfileIdentifier = $VISiteServiceProfileCMD | Where-Object {$_.Description -eq $ServiceProfile} | Select ServiceProfileIdentifier -ExpandProperty ServiceProfileIdentifier

# Get DatastoreIdentifiers for API

$VISiteInfoURL3 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastores"

$VISiteInfoCMD3 = Invoke-RestMethod -Uri $VISiteInfoURL3 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$DatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $DatastoreName} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

$JournalDatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $JournalDatastore} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

# Get Folders for API

$VISiteInfoURL4 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/folders"

$VISiteInfoCMD4 = Invoke-RestMethod -Uri $VISiteInfoURL4 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$FolderIdentifier = $VISiteInfoCMD4 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select FolderIdentifier -ExpandProperty FolderIdentifier

################################################

# Getting a VM identifier for each VM to be protected and adding it to the VMIDarray

################################################

# Reseting VM identifier list, required for creating multiple protection groups

$VMIdentifierList = $null

$VMIDArray = @()

# Running for each VM operation against the VPG name

foreach ($VMLine in $VPGVMNames)

Page 79: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 79 OF 134

{

write-host "$VMLine"

$VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms"

$VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $ContentType

$VMIdentifier = $VMInfoCMD | Where-Object {$_.VmName -eq $VMLine} | select VmIdentifier -ExpandProperty VmIdentifier

# Adding VM ID to array

$VMIDArrayLine = new-object PSObject

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMID" -Value $VMIdentifier

$VMIDArray += $VMIDArrayLine

}

################################################

# Building JSON Request for posting VPG settings to API

################################################

$JSONMain =

"{

""Backup"": null,

""Basic"": {

""JournalHistoryInHours"": null,

""Name"": ""$VPGName"",

""Priority"": ""$ReplicationPriority"",

""ProtectedSiteIdentifier"": ""$LocalSiteIdentifier"",

""RecoverySiteIdentifier"": ""$TargetSiteIdentifier"",

""RpoInSeconds"": null,

""ServiceProfileIdentifier"": ""$ServiceProfileIdentifier"",

""TestIntervalInMinutes"": null,

""UseWanCompression"": true,

""ZorgIdentifier"": null

},

""BootGroups"": {

""BootGroups"": [

{

""BootDelayInSeconds"": 0,

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000000"",

""Name"": ""Default""

}

]

},

""Journal"": {

""DatastoreClusterIdentifier"":null,

""DatastoreIdentifier"":""$DatastoreIdentifier"",

""Limitation"":{

""HardLimitInMB"":null,

""HardLimitInPercent"":null,

""WarningThresholdInMB"":null,

""WarningThresholdInPercent"":null

}

},

""Networks"": {

""Failover"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$FailoverNetworkIdentifier""

}

},

""FailoverTest"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$TestNetworkIdentifier""

}

}

},

""Recovery"": {

""DefaultDatastoreIdentifier"":""$DatastoreIdentifier"",

""DefaultFolderIdentifier"":""$FolderIdentifier"",

""DefaultHostClusterIdentifier"":""$ClusterIdentifier"",

""DefaultHostIdentifier"":null,

""ResourcePoolIdentifier"":null

},

Page 80: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 80 OF 134

""Scripting"": {

""PostBackup"": null,

""PostRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

},

""PreRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

}

},

""Vms"": ["

# Resetting VMs if a previous VPG was created in this run of the script

$JSONVMs = $null

# Creating JSON request per VM using the VM array for all the VMs in the VPG

foreach ($VM in $VMIDArray)

{

$VMID = $VM.VMID

$JSONVMsLine = "{""VmIdentifier"":""$VMID""}"

# Running if statement to check if this is the first VM in the array, if not then a comma is added to string

if ($JSONVMs -ne $null)

{

$JSONVMsLine = "," + $JSONVMsLine

}

$JSONVMs = $JSONVMs + $JSONVMsLine

}

# Creating the end of the JSON request

$JSONEnd = "]

}"

# Putting the JSON request elements together and outputting the request

$JSON = $JSONMain + $JSONVMs + $JSONEnd

write-host "Running JSON request below:

$JSON"

################################################

# Posting the VPG JSON Request to the API

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader

write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier"

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Confirming VPG settings from API

################################################

$ConfirmVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"

$ConfirmVPGSettingCMD = Invoke-RestMethod -Uri $ConfirmVPGSettingURL -Headers $zertosessionHeader -ContentType $TypeJSON

################################################

# Committing the VPG settings to be created

################################################

$CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit"

write-host "Commiting VPG creation for VPG:$VPGName with URL:

$CommitVPGSettingURL"

Try

{

Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

Page 81: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 81 OF 134

################################################

# Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG

################################################

write-host "Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG or stopping script if on the last VPG"

sleep $TimeToWaitBetweenVPGCreation

#

# End of per VPG actions below

}

# End of per VPG actions above

#

################################################

# Stopping logging

################################################

Stop-Transcript

Page 82: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 82 OF 134

5.5 Bulk Automated VPG Creation with Boot Groups & Re-IP – ZVM Only

Bulk VM protection can be achieved using 2 CSV files. The first containing a list of Virtual Protection Groups (VPGs) with the VPG settings and the second a list of VMs to protect with their respective VPGs. VPG names must be unique, any duplicate entries will break the script. Friendly vSphere names are used for all the VPG settings which must match as they are shown in vCenter. This example also includes the ability to specify a VM boot group, 2 by default, and to automatically configure re-IP addressing on the 1st network adapter in the VM. For the VPG settings create a CSV with the following columns:

• VPGName

• ReplicationPriority

• RecoverySiteName

• ClusterName

• FailoverNetwork

• TestNetwork

• DatastoreName

• JournalDatastore

• vCenterFolder

• BootGroupDelay The RecoverySiteName is the target ZVM name and the Service Profile should be created in the ZCM in advance, it cannot be the service profile that already exists when the ZCM is deployed it must be a new profile as per the below example CSV:

Now create a CSV containing the VM names, with respective VPGs, with the following columns:

• VMName

• VPGName

• BootGroupName

• VMNICFailoverNetworkName

• VMNICFailoverDNSSuffix

• VMNICFailoverShouldReplaceMacAddress

• VMNICFailoverGateway

• VMNICFailoverDHCP

• VMNICFailoverPrimaryDns

• VMNICFailoverSecondaryDns

• VMNICFailoverStaticIp

• VMNICFailoverSubnetMask

• VMNICFailoverTestNetworkName

• VMNICFailoverTestDNSSuffix

• VMNICFailoverTestShouldReplaceMacAddress

Page 83: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 83 OF 134

• VMNICFailoverTestGateway

• VMNICFailoverTestDHCP

• VMNICFailoverTestPrimaryDns

• VMNICFailoverTestSecondaryDns

• VMNICFailoverTestStaticIp

• VMNICFailoverTestSubnetMask The script supports multiple VMs per VPG, but keep in mind that in ZVR versions 4.5 and earlier a VM can only exist in 1 VPG at once when building out your list. Here you can see an example of this:

Once both CSVs have been configured, set the variables at the top of the below script to automate bulk VM protection:

################################################

# Configure the variables below ################################################ $LogDataDir = "C:\ZVRBulkVMProtection\" $VPGList = "C:\BulkVMProtectionWithRe-IP\ZVRBulkVMProtectionvVPGs.csv" $VMList = "C:\BulkVMProtectionWithRe-IP\ZVRBulkVMProtectionVMs.csv" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!" $TimeToWaitBetweenVPGCreation = "120" ######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################ # Setting Cert Policy - required for successful auth with the Zerto API without connecting to vsphere using PowerCLI

################################################

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 ################################################ # Connecting to vCenter - if required uncomment line below ################################################ # connect-viserver -Server $vCenterServer -User $vCenterUser -Password $vCenterPassword

################################################

# Building Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs

Page 84: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 84 OF 134

$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" $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON #Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } # URL to create VPG settings

$CreateVPGURL = $BaseURL+"vpgSettings" ################################################ # Importing the CSV of Profiles to use for VM Protection ################################################ $VPGCSVImport = Import-Csv $VPGList $VMCSVImport = Import-Csv $VMList ################################################ # Running the creation process by VPG, as a VPG can contain multiple VMs

################################################ foreach ($VPG in $VPGCSVImport) { $VPGName = $VPG.VPGName $ReplicationPriority = $VPG.ReplicationPriority $RecoverySiteName = $VPG.RecoverySiteName $ClusterName = $VPG.ClusterName $FailoverNetwork = $VPG.FailoverNetwork

$TestNetwork = $VPG.TestNetwork $DatastoreName = $VPG.DatastoreName $JournalDatastore = $VPG.JournalDatastore $vCenterFolder = $VPG.vCenterFolder $JournalHistoryInHours = $VPG.JournalHistoryInHours $RpoAlertInSeconds = $VPG.RpoAlertInSeconds $TestIntervalInMinutes = $VPG.TestIntervalInMinutes $JournalHardLimitInMB = $VPG.JournalHardLimitInMB

$JournalWarningThresholdInMB = $VPG.JournalWarningThresholdInMB $BootGroupDelay = $VPG.BootGroupDelay # Getting list of VMs for the VPG $VPGVMs = $VMCSVImport | Where {$_.VPGName -Match "$VPGName"} $VPGVMNames = $VPGVMs.VMName # Logging and showing action write-host "Creating Protection Group:$VPGName for VMs:$VPGVMNames"

################################################

# Getting Identifiers for VPG settings ################################################ # Get SiteIdentifier for getting Local Identifier later in the script $SiteInfoURL = $BaseURL+"localsite" $SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON $LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

# Get SiteIdentifier for getting Identifiers $TargetSiteInfoURL = $BaseURL+"virtualizationsites"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON $TargetSiteIdentifier = $TargetSiteInfoCMD | Where-Object {$_.VirtualizationSiteName -eq $RecoverySiteName} | select SiteIdentifier -ExpandProperty SiteIdentifier # Getting VM identifiers $VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms" $VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON # Get NetworkIdentifiers for API $VISiteInfoURL1 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/networks" $VISiteInfoCMD1 = Invoke-RestMethod -Uri $VISiteInfoURL1 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FailoverNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $FailoverNetwork} | Select -ExpandProperty NetworkIdentifier

$TestNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $TestNetwork} | Select -ExpandProperty NetworkIdentifier # Get ClusterIdentifier for API $VISiteInfoURL2 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hostclusters" $VISiteInfoCMD2 = Invoke-RestMethod -Uri $VISiteInfoURL2 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

Page 85: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 85 OF 134

$ClusterIdentifier = $VISiteInfoCMD2 | Where-Object {$_.VirtualizationClusterName -eq $ClusterName} | Select -ExpandProperty ClusterIdentifier # Get DatastoreIdentifiers for API $VISiteInfoURL3 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastores" $VISiteInfoCMD3 = Invoke-RestMethod -Uri $VISiteInfoURL3 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON $DatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $DatastoreName} | Select -ExpandProperty DatastoreIdentifier

$JournalDatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $JournalDatastore} | Select -ExpandProperty DatastoreIdentifier # Get Folders for API $VISiteInfoURL4 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/folders" $VISiteInfoCMD4 = Invoke-RestMethod -Uri $VISiteInfoURL4 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON $FolderIdentifier = $VISiteInfoCMD4 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select -ExpandProperty FolderIdentifier ################################################ # Building JSON Request for posting VPG settings to API ################################################

$JSONMain = "{ ""Backup"": null, ""Basic"": { ""JournalHistoryInHours"": ""$JournalHistoryInHours"", ""Name"": ""$VPGName"", ""Priority"": ""$ReplicationPriority"", ""ProtectedSiteIdentifier"": ""$LocalSiteIdentifier"",

""RecoverySiteIdentifier"": ""$TargetSiteIdentifier"", ""RpoInSeconds"": ""$RpoAlertInSeconds"", ""ServiceProfileIdentifier"": null, ""TestIntervalInMinutes"": ""$TestIntervalInMinutes"", ""UseWanCompression"": true, ""ZorgIdentifier"": null }, ""BootGroups"": {

""BootGroups"": [ { ""BootDelayInSeconds"": ""$BootGroupDelay"", ""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000001"", ""Name"": ""Group1"" }, { ""BootDelayInSeconds"": ""0"",

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000002"", ""Name"": ""Group2"" } ] }, ""Journal"": { ""DatastoreClusterIdentifier"":null,

""DatastoreIdentifier"":""$DatastoreIdentifier"",

""Limitation"":{ ""HardLimitInMB"":""$JournalHardLimitInMB"", ""HardLimitInPercent"":null, ""WarningThresholdInMB"":""$JournalWarningThresholdInMB"", ""WarningThresholdInPercent"":null }

}, ""Networks"": {

""Failover"":{ ""Hypervisor"":{ ""DefaultNetworkIdentifier"":""$FailoverNetworkIdentifier"" } }, ""FailoverTest"":{ ""Hypervisor"":{ ""DefaultNetworkIdentifier"":""$TestNetworkIdentifier""

}

} }, ""Recovery"": { ""DefaultDatastoreIdentifier"":""$DatastoreIdentifier"",

Page 86: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 86 OF 134

""DefaultFolderIdentifier"":""$FolderIdentifier"", ""DefaultHostClusterIdentifier"":""$ClusterIdentifier"", ""DefaultHostIdentifier"":null, ""ResourcePoolIdentifier"":null },

""Scripting"": { ""PostBackup"": null, ""PostRecovery"": { ""Command"": null, ""Parameters"": null, ""TimeoutInSeconds"": 0 }, ""PreRecovery"": {

""Command"": null, ""Parameters"": null, ""TimeoutInSeconds"": 0 } }, ""Vms"": [" # Resetting VMs if a previous VPG was created in this run of the script $JSONVMs = $null

# Creating JSON request per VM using the VM array for all the VMs in the VPG foreach ($VM in $VPGVMs) { $VMName = $VM.VMName $BootGroupName = $VM.BootGroupName $VMSettings = $VMInfoCMD | Where-Object {$_.VmName -eq $VMName} | select * $VMIdentifier = $VMSettings | select -ExpandProperty VmIdentifier # Getting VM NIC settings

$VMNICFailoverNetworkName = $VM.VMNICFailoverNetworkName $VMNICFailoverDNSSuffix = $VM.VMNICFailoverDNSSuffix $VMNICFailoverShouldReplaceMacAddress = $VM.VMNICFailoverShouldReplaceMacAddress $VMNICFailoverGateway = $VM.VMNICFailoverGateway $VMNICFailoverDHCP = $VM.VMNICFailoverDHCP $VMNICFailoverPrimaryDns = $VM.VMNICFailoverPrimaryDns $VMNICFailoverSecondaryDns = $VM.VMNICFailoverSecondaryDns $VMNICFailoverStaticIp = $VM.VMNICFailoverStaticIp

$VMNICFailoverSubnetMask = $VM.VMNICFailoverSubnetMask $VMNICFailoverTestNetworkName = $VM.VMNICFailoverTestNetworkName $VMNICFailoverTestDNSSuffix = $VM.VMNICFailoverTestDNSSuffix $VMNICFailoverTestShouldReplaceMacAddress = $VM.VMNICFailoverTestShouldReplaceMacAddress $VMNICFailoverTestGateway = $VM.VMNICFailoverTestGateway $VMNICFailoverTestDHCP = $VM.VMNICFailoverTestDHCP $VMNICFailoverTestPrimaryDns = $VM.VMNICFailoverTestPrimaryDns

$VMNICFailoverTestSecondaryDns = $VM.VMNICFailoverTestSecondaryDns

$VMNICFailoverTestStaticIp = $VM.VMNICFailoverTestStaticIp $VMNICFailoverTestSubnetMask = $VM.VMNICFailoverTestSubnetMask # Setting answers to lower case for API to process $VMNICFailoverShouldReplaceMacAddress = $VMNICFailoverShouldReplaceMacAddress.ToLower() $VMNICFailoverDHCP = $VMNICFailoverDHCP.ToLower() $VMNICFailoverTestShouldReplaceMacAddress = $VMNICFailoverTestShouldReplaceMacAddress.ToLower()

$VMNICFailoverTestDHCP = $VMNICFailoverTestDHCP.ToLower() # Translating network names to ZVR Network Identifiers

$VMNICFailoverNetworkIdentifier = $VISiteInfoCMD1 | where-object {$_.VirtualizationNetworkName -eq $VMNICFailoverNetworkName} | select -ExpandProperty NetworkIdentifier

$VMNICFailoverTestNetworkIdentifier = $VISiteInfoCMD1 | where-object {$_.VirtualizationNetworkName -eq $VMNICFailoverTestNetworkName} | select -ExpandProperty NetworkIdentifier

# Setting boot group ID if ($BootGroupName -eq "Group1") { $BootGroupIdentifier = "00000000-0000-0000-0000-000000000001" } else

{

$BootGroupIdentifier = "00000000-0000-0000-0000-000000000002" } ##################### # Building JSON start

Page 87: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 87 OF 134

##################### $VMJSONStart = " { ""BootGroupIdentifier"":""$BootGroupIdentifier"", ""VmIdentifier"":""$VMIdentifier"",

""Nics"":[" ##################### # Building NIC JSON ##################### # NIC JSON $VMJSONNIC = " { ""Failover"":{

""Hypervisor"":{ ""DnsSuffix"":""$VMNICFailoverDNSSuffix"", ""IpConfig"":{ ""Gateway"":""$VMNICFailoverGateway"", ""IsDhcp"":$VMNICFailoverDHCP, ""PrimaryDns"":""$VMNICFailoverPrimaryDns"", ""SecondaryDns"":""$VMNICFailoverSecondaryDns"", ""StaticIp"":""$VMNICFailoverStaticIp"",

""SubnetMask"":""$VMNICFailoverSubnetMask"" }, ""NetworkIdentifier"":""$VMNICFailoverNetworkIdentifier"", ""ShouldReplaceMacAddress"":$VMNICFailoverShouldReplaceMacAddress } }, ""FailoverTest"":{ ""Hypervisor"":{

""DnsSuffix"":""$VMNICFailoverTestDNSSuffix"", ""IpConfig"":{ ""Gateway"":""$VMNICFailoverTestGateway"", ""IsDhcp"":$VMNICFailoverTestDHCP, ""PrimaryDns"":""$VMNICFailoverTestPrimaryDns"", ""SecondaryDns"":""$VMNICFailoverTestSecondaryDns"", ""StaticIp"":""$VMNICFailoverTestStaticIp"", ""SubnetMask"":""$VMNICFailoverTestSubnetMask""

}, ""NetworkIdentifier"":""$VMNICFailoverTestNetworkIdentifier"", ""ShouldReplaceMACAddress"":$VMNICFailoverTestShouldReplaceMacAddress } }, ""NicIdentifier"":""Network adapter 1"" }"

#####################

# Building end of JSON ##################### $VMJSONEnd = "] }" ##################### # Putting JSON together

##################### $JSONVMsLine = $VMJSONStart + $VMJSONNIC + $VMJSONEnd

# Running if statement to check if this is the first VM in the array, if not then a comma is added to string if ($JSONVMs -ne $null) { $JSONVMsLine = "," + $JSONVMsLine } $JSONVMs = $JSONVMs + $JSONVMsLine # End of for each VM below

}

# End of for each VM above # # Creating the end of the JSON request $JSONEnd = "],

Page 88: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 88 OF 134

}" # Putting the JSON request elements together and outputting the request $JSON = $JSONMain + $JSONVMs + $JSONEnd write-host "Running JSON request below: $JSON"

################################################ # Posting the VPG JSON Request to the API ################################################ Try { $VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier" }

Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } ################################################ # Committing the VPG settings to be created ################################################ $CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit"

write-host "Commiting VPG creation for VPG:$VPGName with URL: $CommitVPGSettingURL" Try { Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100 } Catch { Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force } ################################################ # Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG ################################################ write-host "Waiting $TimeToWaitBetweenVPGCreation seconds before creating the next VPG or stopping script if on the last VPG" sleep $TimeToWaitBetweenVPGCreation #

# End of per VPG actions below } # End of per VPG actions above

Page 89: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 89 OF 134

6 AUTOMATING VM PROTECTION

6.1 Use Cases

The Zerto interface makes the protection of new VMs a very simple task using the create VPG workflow. This does however require manual processes to be followed for new VMs to be protected. In many large organizations where new VMs are being created daily this can lead to significant overheads. By leveraging the REST API and PowerShell, Zerto can be fully automated to protect new VMs to remove this burden and reduce the time to protection for new VMs and applications. Automated VM protection can be achieved both through PowerShell, or as part of a workflow in vRealize Orchestrator (vRO). This document will give examples of how to achieve both and the examples given will include the full script due to the increased length. Comments are used throughout the examples to explain each component. When first testing automation scripts it is recommended to use non-production test VMs. These should be Powered-On with no OS installed and a 1GB thin VMDK due to the speed at which they are protected once a VPG is configured.

6.2 Automating VM Protection by vSphere Folder - ZVM Only

This example is for a Zerto Virtual Manager (ZVM) that is not managed by a Zerto Cloud Manager (ZCM) and therefore does not use ZCM service profiles. The script can be used standalone or as part of vRealize Orchestrater workflow if desired. As the script interacts with vSphere folders, PowerCLI is a requirement of the examples given. To start, configure the below vSphere folders or define your own desired folder structure and configure Test VMs for testing initial protection:

In the above example VMs that require protection should be placed into the “ZVRVMsToProtect” subfolders of “ZVRBootGroup1” or “ZVRBootGroup2”. This can be done manually or using the vRO folder workflows depending on the desired start order of VMs. Once protected the VMs will be moved to the “ZVRProtectedVMs” folder.

The VPG name will be derived from the characters before the hyphen, multiple VMs per VPG and boot group are supported and the VMs will automatically be moved to the “ZVRProtectedVMs” once protected. In the above example this means that 2 VPGs will be created, Customer1 and Customer2 with 2 VMs in the first VPG and 1 VM in the second to demonstrate the functionality. Now configure a CSV with the required VPG configuration settings using the following column headings:

• ProfileNo

• JournalHistoryInHours

• ReplicationPriority

• RecoverySiteName

• RpoAlertInSeconds

• TestIntervalInMinutes

• ClusterName

• FailoverNetwork

• TestNetwork

• DatastoreName

Page 90: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 90 OF 134

• JournalDatastore

• JournalHardLimitInMB

• JournalWarningThresholdInMB

• vCenterFolder

• BootGroupDelay The ProfileNo specified will be referenced at the start of the PowerShell script. Multiple scripts can be created to enable different VPG settings per workflow all from a single CSV containing multiple profiles. The RecoverySiteName is the target site ZVM name and columns for ClusterName, FailoverNetwork, TestNetwork, DatastoreName, JournalDatastore, vCenterFolder must match the friendly name of vSphere clusters, port groups for failover, test, datastore to store the VMs, journals and VM folder respectively. The BootGroupDelay is the number of seconds delay to insert between the 2 boot groups defined. Following is an example of the CSV configured:

To begin automating the VM protection configure the below variables in the following example PowerShell script: ################################################

# Configure the variables below using the Production vCenter & ZVM

################################################

$LogDataDir = "C:\ZVRAutomatedVMProtection\"

$ProfileCSV = "C: \ZVRAutomatedVMProtectionProfilesv1a.csv"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

$vCenterServer = "192.168.0.81"

$vCenterUser = "[email protected]"

$vCenterPassword = "Zerto1234!"

$VPGProfileNo = "1"

$VMsToProtectvCenterFolderName = "ZVRVMsToProtect"

$ProtectedVMvCenterFolderName = "ZVRProtectedVMs"

$NextVPGCreationDelay = "60"

####################################################################################################

# Nothing to configure below this line - Starting the main function of the script

####################################################################################################

################################################

# Setting log directory for engine and current month

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentLogDataDir = $LogDataDir + $CurrentMonth

$CurrentTime = get-date -format hh.mm.ss

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir

$CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\VPGCreationLog-" + $CurrentTime + ".txt"

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

}

start-transcript -path $CurrentLogDataFile -NoClobber

################################################

# Connecting to vCenter - required for successful authentication with Zerto API

################################################

connect-viserver -Server $vCenterServer -User $vCenterUser -Password $vCenterPassword

################################################

Page 91: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 91 OF 134

# Building Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# URL to create VPG settings

$CreateVPGURL = $BaseURL+"vpgSettings"

################################################

# Importing the CSV of Profiles to use for VM Protection

################################################

$ProfileCSVImport = Import-Csv $ProfileCSV

################################################

# Building an Array of all VMs to protect from the vSphere folder and setting the boot group ID

################################################

# Getting a list of all VMs

$VMsToProtect = get-vm * -Location $VMsToProtectvCenterFolderName | Select-Object Name -ExpandProperty Name

# Getting VM boot group info

$VMBootGroup1List = get-vm * -Location "ZVRBootGroup1" | Select-Object Name

$VMBootGroup2List = get-vm * -Location "ZVRBootGroup2" | Select-Object Name

# Setting VM boot group IDs

$VMBootGroup1ID = "00000000-0000-0000-0000-000000000001"

$VMBootGroup2ID = "00000000-0000-0000-0000-000000000002"

# Creating Tag array

$ZVRArray = @()

# Building Array of VMs with boot groups

foreach ($VM in $VMsToProtect)

{

$CurrentVM = $VM.Name

$VPGName = $CurrentVM -replace "-.*"

# Setting VM boot group info

$VMBootGroup1 = $VMBootGroup1List | where {$_.Name -eq "$CurrentVM"} | Select-Object Name -ExpandProperty Name

$VMBootGroup2 = $VMBootGroup2List | where {$_.Name -eq "$CurrentVM"} | Select-Object Name -ExpandProperty Name

# Using IF stattement to set correct boot group ID

if ($VMBootGroup1 -ccontains $CurrentVM)

{

$VMBootGroupID = $VMBootGroup1ID

}

if ($VMBootGroup2 -ccontains $CurrentVM)

{

$VMBootGroupID = $VMBootGroup2ID

}

# Creating Array and adding info for the current VM

$ZVRArrayLine = new-object PSObject

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $CurrentVM

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "BootGroupID" -Value $VMBootGroupID

$ZVRArray += $ZVRArrayLine

# End of for each VM below

}

################################################

# Loading the VPG settings from the CSV, including the ZertoServiceProfile to use

################################################

$ProfileSettings = $ProfileCSVImport | where {$_.ProfileNo -eq "$VPGProfileNo"}

$ReplicationPriority = $ProfileSettings.ReplicationPriority

$RecoverySiteName = $ProfileSettings.RecoverySiteName

Page 92: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 92 OF 134

$ClusterName = $ProfileSettings.ClusterName

$FailoverNetwork = $ProfileSettings.FailoverNetwork

$TestNetwork = $ProfileSettings.TestNetwork

$DatastoreName = $ProfileSettings.DatastoreName

$JournalDatastore = $ProfileSettings.JournalDatastore

$vCenterFolder = $ProfileSettings.vCenterFolder

$BootGroupDelay = $ProfileSettings.BootGroupDelay

$JournalHistoryInHours = $ProfileSettings.JournalHistoryInHours

$RpoAlertInSeconds = $ProfileSettings.RpoAlertInSeconds

$TestIntervalInMinutes = $ProfileSettings.TestIntervalInMinutes

$JournalHardLimitInMB = $ProfileSettings.JournalHardLimitInMB

$JournalWarningThresholdInMB = $ProfileSettings.JournalWarningThresholdInMB

################################################

# Creating List of VMs to Protect and profile settings from the Array then selecting unique VPG names

################################################

$VPGsToCreate = $ZVRArray | select VPGName -Unique

# Writing output of VMs to protect

if ($VMsToProtect -eq $null)

{

write-host "No VMs found to protect in vCenter folder:$VMsToProtectvCenterFolderName"

}

else

{

# Writing output of VMs to protect

write-host "Found the below VMs in the vCenter folder to protect:

$VMsToProtect"

}

################################################

# Running the creation process by VPGs to create from the $VPGsToCreate variable, as a VPG can contain multiple VMs

################################################

foreach ($VPG in $VPGsToCreate)

{

$VPGName = $VPG.VPGName

$VPGVMs = $ZVRArray | Where {$_.VPGName -Match "$VPGName"}

$VPGVMNames = $VPGVMs.VMName

# Need to get Zerto Identifier for each VM here

write-host "Creating Protection Group:$VPGName for VMs:$VPGVMNames"

################################################

# Getting the Zerto VM Identifiers for all the VMs to be created in this VPG

################################################

# Get SiteIdentifier for getting Local Identifier later in the script

$SiteInfoURL = $BaseURL+"localsite"

$SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

# Reseting VM identifier list and creating array, needed as this could be executed for multiple VPGs

$VMIdentifierList = $null

$VMIDArray = @()

# Performing for each VM to protect action

foreach ($VMLine in $VPGVMNames)

{

write-host "$VMLine"

# Getting VM IDs

$VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms"

$VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$VMIdentifier = $VMInfoCMD | Where-Object {$_.VmName -eq $VMLine} | select VmIdentifier -ExpandProperty VmIdentifier

$VMBootID = $ZVRArray | Where {$_.VMName -Match $VMLine } | Select-Object BootGroupID -ExpandProperty BootGroupID

# Adding VM ID and boot group to array for the API

$VMIDArrayLine = new-object PSObject

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMID" -Value $VMIdentifier

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootID" -Value $VMBootID

$VMIDArray += $VMIDArrayLine

}

################################################

# Getting Zerto identifiers based on the friendly names in the CSV to use for VPG creation

################################################

# Get SiteIdentifier for getting Identifiers

Page 93: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 93 OF 134

$TargetSiteInfoURL = $BaseURL+"virtualizationsites"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$TargetSiteIdentifier = $TargetSiteInfoCMD | Where-Object {$_.VirtualizationSiteName -eq $RecoverySiteName} | select SiteIdentifier -ExpandProperty SiteIdentifier

# Get NetworkIdentifiers for API

$VISiteInfoURL1 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/networks"

$VISiteInfoCMD1 = Invoke-RestMethod -Uri $VISiteInfoURL1 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FailoverNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $FailoverNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

$TestNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $TestNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

# Get ClusterIdentifier for API

$VISiteInfoURL2 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hostclusters"

$VISiteInfoCMD2 = Invoke-RestMethod -Uri $VISiteInfoURL2 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ClusterIdentifier = $VISiteInfoCMD2 | Where-Object {$_.VirtualizationClusterName -eq $ClusterName} | Select ClusterIdentifier -ExpandProperty ClusterIdentifier

# Get ServiceProfileIdenfitifer for API

$VISiteServiceProfileURL = $BaseURL+"serviceprofiles"

$VISiteServiceProfileCMD = Invoke-RestMethod -Uri $VISiteServiceProfileURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ServiceProfileIdentifier = $VISiteServiceProfileCMD | Where-Object {$_.Description -eq $ServiceProfile} | Select ServiceProfileIdentifier -ExpandProperty ServiceProfileIdentifier

# Get DatastoreIdentifiers for API

$VISiteInfoURL3 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastores"

$VISiteInfoCMD3 = Invoke-RestMethod -Uri $VISiteInfoURL3 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$DatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $DatastoreName} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

$JournalDatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $JournalDatastore} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

# Get Folders for API

$VISiteInfoURL4 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/folders"

$VISiteInfoCMD4 = Invoke-RestMethod -Uri $VISiteInfoURL4 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FolderIdentifier = $VISiteInfoCMD4 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select FolderIdentifier -ExpandProperty FolderIdentifier

# Outputting API results for easier troubleshooting

write-host "ZVR API Output:

$TargetSiteInfoCMD

$VISiteServiceProfileCMD

$VISiteInfoCMD1

$VISiteInfoCMD2

$VISiteInfoCMD3

$VISiteInfoCMD4"

################################################

# Building JSON Request for posting VPG settings to API

################################################

$JSONMain =

"{

""Backup"": null,

""Basic"": {

""JournalHistoryInHours"": ""$JournalHistoryInHours"",

""Name"": ""$VPGName"",

""Priority"": ""$ReplicationPriority"",

""ProtectedSiteIdentifier"": ""$LocalSiteIdentifier"",

""RecoverySiteIdentifier"": ""$TargetSiteIdentifier"",

""RpoInSeconds"": ""$RpoAlertInSeconds"",

""ServiceProfileIdentifier"": null,

""TestIntervalInMinutes"": ""$TestIntervalInMinutes"",

""UseWanCompression"": true,

""ZorgIdentifier"": null

},

""BootGroups"": {

""BootGroups"": [

{

""BootDelayInSeconds"": 0,

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000001"",

""Name"": ""Database""

},

{

""BootDelayInSeconds"": ""$BootGroupDelay"",

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000002"",

""Name"": ""Web""

}

]

},

""Journal"": {

Page 94: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 94 OF 134

""DatastoreClusterIdentifier"":null,

""DatastoreIdentifier"":""$DatastoreIdentifier"",

""Limitation"":{

""HardLimitInMB"":""$JournalHardLimitInMB"",

""HardLimitInPercent"":null,

""WarningThresholdInMB"":""$JournalWarningThresholdInMB"",

""WarningThresholdInPercent"":null

}

},

""Networks"": {

""Failover"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$FailoverNetworkIdentifier""

}

},

""FailoverTest"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$TestNetworkIdentifier""

}

}

},

""Recovery"": {

""DefaultDatastoreIdentifier"":""$DatastoreIdentifier"",

""DefaultFolderIdentifier"":""$FolderIdentifier"",

""DefaultHostClusterIdentifier"":""$ClusterIdentifier"",

""DefaultHostIdentifier"":null,

""ResourcePoolIdentifier"":null

},

""Scripting"": {

""PostBackup"": null,

""PostRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

},

""PreRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

}

},

""Vms"": ["

# Resetting VMs if a previous VPG was created in this run of the script

$JSONVMs = $null

# Creating JSON VM array for all the VMs in the VPG

foreach ($VM in $VMIDArray)

{

$VMID = $VM.VMID

$VMBootID = $VM.VMBootID

$JSONVMsLine = "{""VmIdentifier"":""$VMID"",""BootGroupIdentifier"":""$VMBootID""}"

# Running if statement to check if this is the first VM in the array, if not then a comma is added to string

if ($JSONVMs -ne $null)

{

$JSONVMsLine = "," + $JSONVMsLine

}

$JSONVMs = $JSONVMs + $JSONVMsLine

}

# Creating the end of the JSON request

$JSONEnd = "]

}"

# Putting the JSON request together and outputting the request

$JSON = $JSONMain + $JSONVMs + $JSONEnd

write-host "Running JSON request below:

$JSON"

################################################

# Posting the VPG JSON Request to the API

Page 95: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 95 OF 134

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader

write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier"

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Confirming VPG settings from API

################################################

$ConfirmVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"

$ConfirmVPGSettingCMD = Invoke-RestMethod -Uri $ConfirmVPGSettingURL -Headers $zertosessionHeader -ContentType $TypeJSON

################################################

# Committing the VPG settings to be created

################################################

$CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit"

write-host "CommitVPGSettingURL:$CommitVPGSettingURL"

Try

{

Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100

$VPGCreationStatus = "PASSED"

}

Catch {

$VPGCreationStatus = "FAILED"

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Performing vSphere folder change operation to indicate protected VM, only if succesfully protected

################################################

if ($VPGCreationStatus -eq "PASSED")

{

foreach ($_ in $VPGVMNames)

{

# Setting VM name

$VMName = $_

# Changing VM to new folder

write-host "Moving VM $VMName to Folder $ProtectedVMvCenterFolderName"

Move-VM -VM $VMName -Destination $ProtectedVMvCenterFolderName

# End of per VM folder change below

}

# End of per VM folder change below

#

# End of per VM folder action if protection succeeded below

}

# End of per VM folder action if protection succeeded above

#

################################################

# Waiting xx minute/s before creating the next VPG

################################################

write-host "Waiting $NextVPGCreationDelay seconds before processing next VPG or finishing script"

sleep $NextVPGCreationDelay

# End of per VPG actions below

}

# End of per VPG actions above

################################################

# Disconnecting from vCenter

################################################

disconnect-viserver $vCenterServer -Force -Confirm:$false

################################################

# Stopping logging

################################################

Page 96: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 96 OF 134

stop-transcript

Page 97: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 97 OF 134

6.3 Automating VM Protection by vSphere Folder - ZVM & ZCM

This example is for a Zerto Virtual Manager (ZVM) that is managed by a Zerto Cloud Manager (ZCM) and therefore requires the use of ZCM service profiles. The script can be used standalone or with vRealize Orchestrater workflows if desired. As the script interacts with vSphere folders, PowerCLI is a requirement of the examples given. To start, configure the below vSphere folders or define your own folder structure and configure Test VMs for initial protection:

In the above example VMs that require protection should be placed into the “ZVRVMsToProtect” subfolders of “ZVRBootGroup1” or “ZVRBootGroup2”. This can be done manually or using the vRO folder workflows depending on the desired start order of VMs. Once protected the VMs will be moved to the “ZVRProtectedVMs” folder. The VPG name will be derived from the characters before the hyphen, multiple VMs per VPG and boot group are supported and the VMs will automatically be moved to the “ZVRProtectedVMs” once protected. In the above example this means that 2 VPGs will be created, Customer1 and Customer2 with 2 VMs in the first VPG and 1 VM in the second to demonstrate the functionality. Now configure a CSV with the required VPG configuration settings using the following column headings:

• ProfileNo

• ZertoServiceProfile

• ReplicationPriority

• RecoverySiteName

• ClusterName

• FailoverNetwork

• TestNetwork

• DatastoreName

• JournalDatastore

• vCenterFolder

• BootGroupDelay The ProfileNo specified will be referenced at the start of the PowerShell script. Multiple scripts can be created to enable different VPG settings per workflow all from a single CSV containing multiple profiles. Each profile in a CSV must also reference a ZertoServiceProfile deployed from the ZCM. The Zerto Service Profile should be created in the ZCM in advance, it cannot be the service profile that already exists when the ZCM is deployed it must be a new profile. The RecoverySiteName is the target site ZVM name and columns for ClusterName, FailoverNetwork, TestNetwork, DatastoreName, JournalDatastore, vCenterFolder must match the friendly name of vSphere clusters, port groups for failover, test, datastore to store the VMs, journals and VM folder respectively. The BootGroupDelay is the number of seconds delay to insert between the 2 boot groups defined. Following is an example of the CSV configured:

Page 98: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 98 OF 134

To begin automating the VM protection configure the below variables in the following example PowerShell script: ################################################

# Configure the variables below using the Production vCenter & ZVM

################################################

$LogDataDir = "C:\ZVRAutomatedVMProtection\"

$ProfileCSV = "C:\ZVRAutomatedVMProtectionProfilesv1a.csv"

$ZertoServer = "192.168.0.31"

$ZertoPort = "9669"

$ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

$vCenterServer = "192.168.0.81"

$vCenterUser = "[email protected]"

$vCenterPassword = "Zerto1234!"

$VPGProfileNo = "1"

$VMsToProtectvCenterFolderName = "ZVRVMsToProtect"

$ProtectedVMvCenterFolderName = "ZVRProtectedVMs"

$NextVPGCreationDelay = "30"

####################################################################################

# Nothing to configure below this line - Starting the main function of the script

####################################################################################

################################################

# Setting log directory for engine and current month

################################################

$CurrentMonth = get-date -format MM.yy

$CurrentLogDataDir = $LogDataDir + $CurrentMonth

$CurrentTime = get-date -format hh.mm.ss

# Testing path exists to engine logging, if not creating it

$ExportDataDirTestPath = test-path $CurrentLogDataDir

$CurrentLogDataFile = $LogDataDir + $CurrentMonth + "\VPGCreationLog-" + $CurrentTime + ".txt"

if ($ExportDataDirTestPath -eq $False)

{

New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

}

start-transcript -path $CurrentLogDataFile -NoClobber

################################################

# Connecting to vCenter - required for successful authentication with Zerto API

################################################

connect-viserver -Server $vCenterServer -User $vCenterUser -Password $vCenterPassword

################################################

# Building Zerto API string and invoking API

################################################

$baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs

$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"

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

#Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON }

# URL to create VPG settings

$CreateVPGURL = $BaseURL+"vpgSettings"

################################################

# Importing the CSV of Profiles to use for VM Protection

################################################

$ProfileCSVImport = Import-Csv $ProfileCSV

################################################

# Building an Array of all VMs to protect from the vSphere folder and setting the boot group ID

################################################

Page 99: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 99 OF 134

# Getting a list of all VMs

$VMsToProtect = get-vm * -Location $VMsToProtectvCenterFolderName | Select-Object Name -ExpandProperty Name

# Getting VM boot group info

$VMBootGroup1List = get-vm * -Location "ZVRBootGroup1" | Select-Object Name

$VMBootGroup2List = get-vm * -Location "ZVRBootGroup2" | Select-Object Name

# Setting VM boot group IDs

$VMBootGroup1ID = "00000000-0000-0000-0000-000000000001"

$VMBootGroup2ID = "00000000-0000-0000-0000-000000000002"

# Creating Tag array

$ZVRArray = @()

# Building Array of VMs with boot groups

foreach ($VM in $VMsToProtect)

{

$CurrentVM = $VM.Name

$VPGName = $CurrentVM -replace "-.*"

# Setting VM boot group info

$VMBootGroup1 = $VMBootGroup1List | where {$_.Name -eq "$CurrentVM"} | Select-Object Name -ExpandProperty Name

$VMBootGroup2 = $VMBootGroup2List | where {$_.Name -eq "$CurrentVM"} | Select-Object Name -ExpandProperty Name

# Using IF stattement to set correct boot group ID

if ($VMBootGroup1 -ccontains $CurrentVM)

{

$VMBootGroupID = $VMBootGroup1ID

}

if ($VMBootGroup2 -ccontains $CurrentVM)

{

$VMBootGroupID = $VMBootGroup2ID

}

# Creating Array and adding info for the current VM

$ZVRArrayLine = new-object PSObject

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $CurrentVM

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName

$ZVRArrayLine | Add-Member -MemberType NoteProperty -Name "BootGroupID" -Value $VMBootGroupID

$ZVRArray += $ZVRArrayLine

# End of for each VM below

}

################################################

# Loading the VPG settings from the CSV, including the ZertoServiceProfile to use

################################################

$ProfileSettings = $ProfileCSVImport | where {$_.ProfileNo -eq "$VPGProfileNo"}

$ServiceProfile = $ProfileSettings.ZertoServiceProfile

$ReplicationPriority = $ProfileSettings.ReplicationPriority

$RecoverySiteName = $ProfileSettings.RecoverySiteName

$ClusterName = $ProfileSettings.ClusterName

$FailoverNetwork = $ProfileSettings.FailoverNetwork

$TestNetwork = $ProfileSettings.TestNetwork

$DatastoreName = $ProfileSettings.DatastoreName

$JournalDatastore = $ProfileSettings.JournalDatastore

$vCenterFolder = $ProfileSettings.vCenterFolder

$BootGroupDelay = $ProfileSettings.BootGroupDelay

################################################

# Creating List of VMs to Protect and profile settings from the Array then selecting unique VPG names

################################################

$VPGsToCreate = $ZVRArray | select VPGName -Unique

# Writing output of VMs to protect

if ($VMsToProtect -eq $null)

{

write-host "No VMs found to protect in vCenter folder:$VMsToProtectvCenterFolderName"

}

else

{

# Writing output of VMs to protect

write-host "Found the below VMs in the vCenter folder to protect:

$VMsToProtect"

}

################################################

# Running the creation process by VPGs to create from the $VPGsToCreate variable, as a VPG can contain multiple VMs

Page 100: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 100 OF 134

################################################

foreach ($VPG in $VPGsToCreate)

{

$VPGName = $VPG.VPGName

$VPGVMs = $ZVRArray | Where {$_.VPGName -Match "$VPGName"}

$VPGVMNames = $VPGVMs.VMName

# Need to get Zerto Identifier for each VM here

write-host "Creating Protection Group:$VPGName for VMs:$VPGVMNames"

################################################

# Getting the Zerto VM Identifiers for all the VMs to be created in this VPG

################################################

# Get SiteIdentifier for getting Local Identifier later in the script

$SiteInfoURL = $BaseURL+"localsite"

$SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier

# Reseting VM identifier list and creating array, needed as this could be executed for multiple VPGs

$VMIdentifierList = $null

$VMIDArray = @()

# Performing for each VM to protect action

foreach ($VMLine in $VPGVMNames)

{

write-host "$VMLine"

# Getting VM IDs

$VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms"

$VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$VMIdentifier = $VMInfoCMD | Where-Object {$_.VmName -eq $VMLine} | select VmIdentifier -ExpandProperty VmIdentifier

$VMBootID = $ZVRArray | Where {$_.VMName -Match $VMLine } | Select-Object BootGroupID -ExpandProperty BootGroupID

# Adding VM ID and boot group to array for the API

$VMIDArrayLine = new-object PSObject

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMID" -Value $VMIdentifier

$VMIDArrayLine | Add-Member -MemberType NoteProperty -Name "VMBootID" -Value $VMBootID

$VMIDArray += $VMIDArrayLine

}

################################################

# Getting Zerto identifiers based on the friendly names in the CSV to use for VPG creation

################################################

# Get SiteIdentifier for getting Identifiers

$TargetSiteInfoURL = $BaseURL+"virtualizationsites"

$TargetSiteInfoCMD = Invoke-RestMethod -Uri $TargetSiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$TargetSiteIdentifier = $TargetSiteInfoCMD | Where-Object {$_.VirtualizationSiteName -eq $RecoverySiteName} | select SiteIdentifier -ExpandProperty SiteIdentifier

# Get NetworkIdentifiers for API

$VISiteInfoURL1 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/networks"

$VISiteInfoCMD1 = Invoke-RestMethod -Uri $VISiteInfoURL1 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FailoverNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $FailoverNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

$TestNetworkIdentifier = $VISiteInfoCMD1 | Where-Object {$_.VirtualizationNetworkName -eq $TestNetwork} | Select NetworkIdentifier -ExpandProperty NetworkIdentifier

# Get ClusterIdentifier for API

$VISiteInfoURL2 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hostclusters"

$VISiteInfoCMD2 = Invoke-RestMethod -Uri $VISiteInfoURL2 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ClusterIdentifier = $VISiteInfoCMD2 | Where-Object {$_.VirtualizationClusterName -eq $ClusterName} | Select ClusterIdentifier -ExpandProperty ClusterIdentifier

# Get ServiceProfileIdenfitifer for API

$VISiteServiceProfileURL = $BaseURL+"serviceprofiles"

$VISiteServiceProfileCMD = Invoke-RestMethod -Uri $VISiteServiceProfileURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$ServiceProfileIdentifier = $VISiteServiceProfileCMD | Where-Object {$_.Description -eq $ServiceProfile} | Select ServiceProfileIdentifier -ExpandProperty ServiceProfileIdentifier

# Get DatastoreIdentifiers for API

$VISiteInfoURL3 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastores"

$VISiteInfoCMD3 = Invoke-RestMethod -Uri $VISiteInfoURL3 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$DatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $DatastoreName} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

$JournalDatastoreIdentifier = $VISiteInfoCMD3 | Where-Object {$_.DatastoreName -eq $JournalDatastore} | Select DatastoreIdentifier -ExpandProperty DatastoreIdentifier

# Get Folders for API

$VISiteInfoURL4 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/folders"

$VISiteInfoCMD4 = Invoke-RestMethod -Uri $VISiteInfoURL4 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

$FolderIdentifier = $VISiteInfoCMD4 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select FolderIdentifier -ExpandProperty FolderIdentifier

# Outputting API results for easier troubleshooting

write-host "ZVR API Output:

$TargetSiteInfoCMD

$VISiteServiceProfileCMD

Page 101: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 101 OF 134

$VISiteInfoCMD1

$VISiteInfoCMD2

$VISiteInfoCMD3

$VISiteInfoCMD4"

# DatastoreClusters for API - not used in this example

# $VISiteInfoURL5 = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/datastoreclusters"

# $VISiteInfoCMD5 = Invoke-RestMethod -Uri $VISiteInfoURL5 -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

# $DataStoreClusterIdentifier = $VISiteInfoCMD5 | Where-Object {$_.FolderName -eq $vCenterFolder} | Select FolderIdentifier -ExpandProperty FolderIdentifier

# Get HostIdentifier for API - not used in this example as using target cluster (which uses simple round robin)

# $VISiteHostURL = $BaseURL+"virtualizationsites/$TargetSiteIdentifier/hosts"

# $VISiteHostCMD = Invoke-RestMethod -Uri $VISiteHostURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType $TypeJSON

# $HostIdentifier = $VISiteHostCMD | Where-Object {$_.VirtualizationHostName -eq "Host name here"} | Select HostIdentifier -ExpandProperty HostIdentifier

################################################

# Building JSON Request for posting VPG settings to API

################################################

$JSONMain =

"{

""Backup"": null,

""Basic"": {

""JournalHistoryInHours"": null,

""Name"": ""$VPGName"",

""Priority"": ""$ReplicationPriority"",

""ProtectedSiteIdentifier"": ""$LocalSiteIdentifier"",

""RecoverySiteIdentifier"": ""$TargetSiteIdentifier"",

""RpoInSeconds"": null,

""ServiceProfileIdentifier"": ""$ServiceProfileIdentifier"",

""TestIntervalInMinutes"": null,

""UseWanCompression"": true,

""ZorgIdentifier"": null

},

""BootGroups"": {

""BootGroups"": [

{

""BootDelayInSeconds"": 0,

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000001"",

""Name"": ""Database""

},

{

""BootDelayInSeconds"": ""$BootGroupDelay"",

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000002"",

""Name"": ""Web""

}

]

},

""Journal"": {

""DatastoreClusterIdentifier"":null,

""DatastoreIdentifier"":""$DatastoreIdentifier"",

""Limitation"":{

""HardLimitInMB"":null,

""HardLimitInPercent"":null,

""WarningThresholdInMB"":null,

""WarningThresholdInPercent"":null

}

},

""Networks"": {

""Failover"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$FailoverNetworkIdentifier""

}

},

""FailoverTest"":{

""Hypervisor"":{

""DefaultNetworkIdentifier"":""$TestNetworkIdentifier""

}

}

},

Page 102: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 102 OF 134

""Recovery"": {

""DefaultDatastoreIdentifier"":""$DatastoreIdentifier"",

""DefaultFolderIdentifier"":""$FolderIdentifier"",

""DefaultHostClusterIdentifier"":""$ClusterIdentifier"",

""DefaultHostIdentifier"":null,

""ResourcePoolIdentifier"":null

},

""Scripting"": {

""PostBackup"": null,

""PostRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

},

""PreRecovery"": {

""Command"": null,

""Parameters"": null,

""TimeoutInSeconds"": 0

}

},

""Vms"": ["

# Resetting VMs if a previous VPG was created in this run of the script

$JSONVMs = $null

# Creating JSON VM array for all the VMs in the VPG

foreach ($VM in $VMIDArray)

{

$VMID = $VM.VMID

$VMBootID = $VM.VMBootID

$JSONVMsLine = "{""VmIdentifier"":""$VMID"",""BootGroupIdentifier"":""$VMBootID""}"

# Running if statement to check if this is the first VM in the array, if not then a comma is added to string

if ($JSONVMs -ne $null)

{

$JSONVMsLine = "," + $JSONVMsLine

}

$JSONVMs = $JSONVMs + $JSONVMsLine

}

# Creating the end of the JSON request

$JSONEnd = "]

}"

# Putting the JSON request together and outputting the request

$JSON = $JSONMain + $JSONVMs + $JSONEnd

write-host "Running JSON request below:

$JSON"

################################################

# Posting the VPG JSON Request to the API

################################################

Try

{

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader

write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier"

}

Catch {

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Confirming VPG settings from API

################################################

$ConfirmVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"

$ConfirmVPGSettingCMD = Invoke-RestMethod -Uri $ConfirmVPGSettingURL -Headers $zertosessionHeader -ContentType $TypeJSON

################################################

# Committing the VPG settings to be created

################################################

$CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit"

write-host "CommitVPGSettingURL:$CommitVPGSettingURL"

Try

Page 103: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 103 OF 134

{

Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100

$VPGCreationStatus = "PASSED"

}

Catch {

$VPGCreationStatus = "FAILED"

Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force

}

################################################

# Performing vSphere folder change operation to indicate protected VM, only if succesfully protected

################################################

if ($VPGCreationStatus -eq "PASSED")

{

foreach ($_ in $VPGVMNames)

{

# Setting VM name

$VMName = $_

# Changing VM to new folder

write-host "Moving VM $VMName to Folder $ProtectedVMvCenterFolderName"

Move-VM -VM $VMName -Destination $ProtectedVMvCenterFolderName

# End of per VM folder change below

}

# End of per VM folder change below

#

# End of per VM folder action if protection succeeded below

}

# End of per VM folder action if protection succeeded above

#

################################################

# Waiting xx minute/s before creating the next VPG

################################################

write-host "Waiting $NextVPGCreationDelay seconds before processing next VPG or finishing script"

sleep $NextVPGCreationDelay

# End of per VPG actions below

}

# End of per VPG actions above

################################################

# Disconnecting from vCenter

################################################

disconnect-viserver $vCenterServer -Force -Confirm:$false

################################################

# Stopping logging

################################################

stop-transcript

Page 104: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 104 OF 134

6.4 Automating VM Protection with vRealize Orchestrator

To integrate automated VM protection with vRealize Orchestrator (vRO) the appropriate script from sections 6.2 and 6.3 must first be built and tested as working. The scripts then need to be placed onto a PowerShell host in vRO. To configure a vRO host execute the “Add a PowerShell host” workflow in vRO:

Further information on other steps required, such as configuring Windows Remote Managed on the PowerShell host can be found on the following blog post: http://www.vmbaggum.nl/2015/04/how-to-add-a-powershell-host-to-vro/ The next step is to ensure the vRO workflows for VM creation place the VMs to protect in the specified vSphere folders in the correct naming convention, as per:

Remember, the VPG name is derived by all the characters before the hyphen in the VM name and multiple VMs are supported per

VPG.

To execute automated VM protection add a “Invoke a PowerShell Script” into your VM creation workflow, referencing the

automation script placed on the PowerShell host, and the integration is complete:

Page 105: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 105 OF 134

6.5 Adding VMs to VPGs

When automating VM protection it might be required to add a VM to an existing VPG. The check to see if a VPG exists to then perform the correct operation is very simple: $VPGName = "DemoVPG1"

$VPGURL = $baseURL+"vpgs"

$VPGCMD = Invoke-RestMethod -Uri $VPGURL -TimeoutSec 100 -Headers $zertosessionHeader -ContentType

"application/JSON"

$VPGIdentifier = $SourceZVMVPGsCMD | Where-Object {$_.Vpgname -eq $VPGName} | Select-Object -ExpandProperty

VpgIdentifier

################################################################################################

# IF VPG does EXIST, adding VMs to VPG

################################################################################################

if ($VPGIdentifier -ne $null)

{

write-host "VPG found - adding VM to VPG"

}

else

{

write-host "VPG not found - creating VPG"

}

Once you have defined the need to add a VM to a VPG rather than create a new VPG, the following script can be used: ################################################

# Configure the variables below using the Production vCenter & ZVM ################################################ # Uncomment the arguments & remove static variables to pass these values to the script # $VPGName = $args[0] # $VMName = $args[1] $VPGName = "DemoVPG1" $VMName = "NewVMtoAdd1" $ZertoServer = "192.168.0.31"

$ZertoPort = "9669" $ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!" ######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################

# Building Zerto API string and invoking API

################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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" $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON #Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertosessionHeader_JSON = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } $zertosessionHeader_XML = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeXML }

################################################ # Getting VPG & VM lists to get identifiers of VPG and VMs to add ################################################ # URL to create VPG settings $CreateVPGURL = $BaseURL+"vpgSettings"

Page 106: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 106 OF 134

# VPG URL and List $vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML # Build List of VMs $vmListApiUrl = $baseURL+"vms"

$vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON # Select IDs from the API array $zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,vmscount,vpgidentifier $VPGIdentifier = $zertoprotectiongrouparray | Where-Object {$_.VpgName -eq $VPGName} | select-object VpgIdentifier -ExpandProperty VpgIdentifier # Building JSON for edit request $JSON = "{ ""VpgIdentifier"":""$VPGidentifier""

}" ################################################ # Posting the VPG JSON Request to the API ################################################ Try { $VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader_JSON write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier"

} Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } ################################################ # Getting the Zerto VM Identifiers for the VM to be created in this VPG ################################################

# Get SiteIdentifier for getting Local Identifier later in the script $SiteInfoURL = $BaseURL+"localsite" $SiteInfoCMD = Invoke-RestMethod -Uri $SiteInfoURL -TimeoutSec 100 -Headers $zertosessionHeader_JSON -ContentType $TypeJSON $LocalSiteIdentifier = $SiteInfoCMD | Select SiteIdentifier -ExpandProperty SiteIdentifier # Getting VM identifier $VMInfoURL = $BaseURL+"virtualizationsites/$LocalSiteIdentifier/vms" $VMInfoCMD = Invoke-RestMethod -Uri $VMInfoURL -TimeoutSec 100 -Headers $zertosessionHeader_JSON -ContentType $TypeJSON $VMIdentifier = $VMInfoCMD | Where-Object {$_.VmName -eq $VMName} | select VmIdentifier -ExpandProperty VmIdentifier

################################################ # Building URLs, JSON and Posting request ################################################ $AddVMURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/vms" $JSONVM = "{""VmIdentifier"":""$vmIdentifier""}" Try {

$AddVMPOST = Invoke-RestMethod -Method POST -Uri $AddVMURL -Body $JSONVM -ContentType $TypeJSON -Headers $zertosessionHeader_JSON -TimeoutSec 100

} Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } ################################################

# Committing the VPG settings to be created ################################################

$CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit" write-host "CommitVPGSettingURL:$CommitVPGSettingURL" Try { Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader_JSON -TimeoutSec 100 $VPGCreationStatus = "PASSED" } Catch {

$VPGCreationStatus = "FAILED"

Write-Host $_.Exception.ToString() $error[0] | Format-List -Force

Page 107: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 107 OF 134

}

7 BULK EDIT OPERATIONS

7.1 Bulk VPG Name Changing

In ZVR, VPG names are required to be unique and naming conventions can change. If you need to bulk change the name of the VPGs

then scripting this procedure can save time and effot. Before importing the new names, you should first export the existing VPG

names to a CSV using:

################################################ # Configure the variables below ################################################ $ExportDataDir = "C:\ZVRBulkVPGRename\" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!"

######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################ # Setting certificate exception to prevent authentication issues to the ZVM ################################################ 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 Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs

$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" Try

{ $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } # Extracting x-zerto-session from the response, and adding it to the actual API

$xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session")

$zertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } ################################################ # Building array of VPGs ################################################

Page 108: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 108 OF 134

$vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON $VPGs = $vpgList | select VpgName,SourceSite,TargetSite,VmsCount,VpgIdentifier $VPGArray = @() ################################################

# Building array line per VPG ################################################ foreach ($VPG in $VPGs) { # Setting values $VpgName = $VPG.VpgName $SourceSite = $VPG.SourceSite $TargetSite = $VPG.TargetSite

$VmsCount = $VPG.VmsCount $VPGidentifier = $VPG.VPGidentifier # Adding info to array $VPGArrayLine = new-object PSObject $VPGArrayLine | Add-Member -MemberType NoteProperty -Name "OldVPGName" -Value $VPGName $VPGArrayLine | Add-Member -MemberType NoteProperty -Name "NewVPGName" -Value "" $VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier $VPGArrayLine | Add-Member -MemberType NoteProperty -Name "SourceSite" -Value $SourceSite

$VPGArrayLine | Add-Member -MemberType NoteProperty -Name "TargetSite" -Value $TargetSite $VPGArrayLine | Add-Member -MemberType NoteProperty -Name "VmsCount" -Value $VmsCount $VPGArray += $VPGArrayLine } ################################################ # Exporting VPG names ################################################ $VPGArray | export-csv $ExportDataDir"VPGNames.csv" -NoTypeInformation

This will then produce the below easy to edit CSV:

Configure the new VPG names, which must be unique, then run the below script to import the CSV and change the VPG names:

################################################ # Configure the variables below ################################################ $CSVImportFile = "C:\ZVRBulkVPGRename\VPGNames.csv" $ZertoServer = "192.168.0.31" $ZertoPort = "9669" $ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!"

######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script

######################################################################################################################## # Importing CSV and building list of VPGs ################################################

Page 109: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 109 OF 134

$VPGsToConfigure = Import-Csv $CSVImportFile ################################################ # Setting certificate exception to prevent authentication issues to the ZVM ################################################ 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 Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs

$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"

Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force }

# Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } # URL to edit VPG settings $CreateVPGSettingsURL = $BaseURL+"vpgSettings" ################################################ # Checking no duplicate new VPG names as they have to be unique

################################################

$NewVPGNameCheck = $VPGsToConfigure.NewVPGName | Group-Object | Where-Object {$_.Count -gt 1} if ($NewVPGNameCheck -ne $null) { write-host "Duplicate New VPG name found, fix it and run the script again" sleep 3 exit

} ################################################

# Performing per VPG rename action ################################################ foreach ($VPG in $VPGsToConfigure) { $OldVPGName = $VPG.OldVPGName $NewVPGName = $VPG.NewVPGName $VPGidentifier = $VPG.VPGidentifier ################################################

# Posting the VPG JSON Request to the API to get a VPG settings ID

################################################ # Building JSON for edit request $JSONVPGSetting = "{

Page 110: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 110 OF 134

""VpgIdentifier"":""$VPGidentifier"" }" # Posting edit request Try {

$VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGSettingsURL -Body $JSONVPGSetting -ContentType $TypeJSON -Headers $zertosessionHeader

write-host "VPGSettingsIdentifier: $VPGSettingsIdentifier" } Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } ################################################

# Changing the VPG name ################################################ $JSON = "{ ""Basic"": { ""Name"": ""$NewVPGName"" } }"

# Put URL & command $EditVPGURL = $BaseURL + "vpgsettings/" + $VPGSettingsIdentifier Try { $EditVPG = Invoke-RestMethod -Method PUT -Uri $EditVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertosessionHeader } Catch { Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force } ################################################ # Committing the VPG setting ################################################ $CommitVPGSettingURL = $BaseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit" write-host "CommitVPGSettingURL:$CommitVPGSettingURL"

Try { Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -ContentType $TypeJSON -Headers $zertosessionHeader -TimeoutSec 100 write-host "Successfully changed VPG:$OldVPGName to VPG:$NewVPGName" } Catch { write-host "Failed changing VPG:$OldVPGName to VPG:$NewVPGName"

}

# Sleeping before processing next VPG sleep 5 # End of per VPG action below } # End of per VPG action above

Page 111: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 111 OF 134

7.2 Bulk Editing VM NIC Settings Including Re-IP & Port Groups

Using the REST API, it is possible to configure new IP and MAC address settings using a CSV for simplicity, speed and to remove human

errors by not having to configure each VM NIC manually. This same technique can also be used for changing Port Groups. To bulk

change the VM NIC settings an export of the current VM NICs is required to build a CSV. This can be done with the below script:

################################################ # Configure the variables below ################################################ $ExportDataDir = "C:\ZVRBulkReIP\" $ZertoServer = "192.168.0.31" $ZertoPort = "9669"

$ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!" ######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################ # Setting certificate exception to prevent authentication issues to the ZVM

################################################

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 Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/"

# Authenticating with Zerto APIs $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" Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON } Catch {

Write-Host $_.Exception.ToString() $error[0] | Format-List -Force

} # Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertoSessionHeader_JSON = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } $zertoSessionHeader_XML = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeXML } ################################################ # Creating Arrays for populating ZVM info from the API ################################################

$VPGArray = @()

$VMArray = @() $VMVolumeArray = @() $VMNICArray = @()

Page 112: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 112 OF 134

################################################ # Creating VPGArray, VMArray, VMVolumeArray, VMNICArray ################################################ # URL to create VPG settings $CreateVPGURL = $baseURL+"vpgSettings"

# Build List of VPGs $vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML # Build List of VMs $vmListApiUrl = $baseURL+"vms" $vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML # Select IDs from the API array $zertoprotectiongrouparray = $vpgList.ArrayOfVpgApi.VpgApi | Select-Object OrganizationName,vpgname,vmscount,vpgidentifier

$vmListarray = $vmList.ArrayOfVmApi.VmApi | select-object * ################################################ # Starting for each VPG action of collecting ZVM VPG data ################################################ foreach ($VPGLine in $zertoprotectiongrouparray) { $VPGidentifier = $VPGLine.vpgidentifier $VPGOrganization = $VPGLine.OrganizationName

$VPGVMCount = $VPGLine.VmsCount $JSON = "{ ""VpgIdentifier"":""$VPGidentifier"" }" ################################################ # Posting the VPG JSON Request to the API ################################################

Try { $VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertoSessionHeader_JSON $ValidVPGSettingsIdentifier = $true } Catch { $ValidVPGSettingsIdentifier = $false }

################################################ # Getting VPG settings from API ################################################ # Skipping if unable to obtain valid VPG setting identifier if ($ValidVPGSettingsIdentifier -eq $true) { $VPGSettingsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier

$VPGSettings = Invoke-RestMethod -Uri $VPGSettingsURL -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting recovery site ID (needed anyway for network settings) $VPGRecoverySiteIdentifier = $VPGSettings.Basic.RecoverySiteIdentifier # Getting site info $VISitesURL = $baseURL+"virtualizationsites" $VISitesCMD = Invoke-RestMethod -Uri $VISitesURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON # Getting network info

$VINetworksURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/networks" $VINetworksCMD = Invoke-RestMethod -Uri $VINetworksURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

# Getting VPG Settings $VPGName = $VPGSettings.Basic.Name # Getting VM IDs in VPG $VPGVMIdentifiers = $VPGSettings.VMs.VmIdentifier ################################################ # Starting for each VM ID action for collecting ZVM VM data ################################################ foreach ($_ in $VPGVMIdentifiers)

{

$VMIdentifier = $_ # Get VMs settings $GetVMSettingsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier $GetVMSettings = Invoke-RestMethod -Method Get -Uri $GetVMSettingsURL -TimeoutSec 100 -Headers $zertoSessionHeader_JSON -ContentType $TypeJSON

Page 113: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 113 OF 134

# Getting the VM name and disk usage $VMNameArray = $vmListarray | where-object {$_.VmIdentifier -eq $VMIdentifier} | Select-Object * $VMName = $VMNameArray.VmName ################################################ # Get VM Nic settings for the current VPG

################################################ $GetVMSettingNICsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics" $GetVMSettingNICs = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICsURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML $VMNICIDs = $GetVMSettingNICs.ArrayOfVpgSettingsVmNicApi.VpgSettingsVmNicApi | select-object NicIdentifier -ExpandProperty NicIdentifier ################################################ # Starting for each VM NIC ID action for collecting ZVM VM NIC data ################################################ foreach ($_ in $VMNICIDs)

{ $VMNICIdentifier = $_ $GetVMSettingNICURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics/"+$VMNICIdentifier $GetVMSettingNIC = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML # Building arrays $VMSettingNICIDArray1 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor $VMSettingNICIDArray2 = $GetVMSettingNIC.VpgSettingsVmNicApi.Failover.Hypervisor.IpConfig $VMSettingNICIDArray3 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor

$VMSettingNICIDArray4 = $GetVMSettingNIC.VpgSettingsVmNicApi.FailoverTest.Hypervisor.IpConfig # Setting failover values $VMNICFailoverDNSSuffix = $VMSettingNICIDArray1.DnsSuffix $VMNICFailoverNetworkIdentifier = $VMSettingNICIDArray1.NetworkIdentifier $VMNICFailoverShouldReplaceMacAddress = $VMSettingNICIDArray1.ShouldReplaceMacAddress $VMNICFailoverGateway = $VMSettingNICIDArray2.Gateway $VMNIsFailoverDHCP = $VMSettingNICIDArray2.IsDhcp $VMNICFailoverPrimaryDns = $VMSettingNICIDArray2.PrimaryDns

$VMNICFailoverSecondaryDns = $VMSettingNICIDArray2.SecondaryDns $VMNICFailoverStaticIp = $VMSettingNICIDArray2.StaticIp $VMNICFailoverSubnetMask = $VMSettingNICIDArray2.SubnetMask # Nulling blank content if ($VMNICFailoverDNSSuffix.nil -eq $true){$VMNICFailoverDNSSuffix = $null} if ($VMNICFailoverGateway.nil -eq $true){$VMNICFailoverGateway = $null} if ($VMNICFailoverPrimaryDns.nil -eq $true){$VMNICFailoverPrimaryDns = $null} if ($VMNICFailoverSecondaryDns.nil -eq $true){$VMNICFailoverSecondaryDns = $null}

if ($VMNICFailoverStaticIp.nil -eq $true){$VMNICFailoverStaticIp = $null} if ($VMNICFailoverSubnetMask.nil -eq $true){$VMNICFailoverSubnetMask = $null} # Setting failover test values $VMNICFailoverTestDNSSuffix = $VMSettingNICIDArray3.DnsSuffix $VMNICFailoverTestNetworkIdentifier = $VMSettingNICIDArray3.NetworkIdentifier $VMNICFailoverTestShouldReplaceMacAddress = $VMSettingNICIDArray3.ShouldReplaceMacAddress $VMNICFailoverTestGateway = $VMSettingNICIDArray4.Gateway

$VMNIsFailoverTestDHCP = $VMSettingNICIDArray4.IsDhcp

$VMNICFailoverTestPrimaryDns = $VMSettingNICIDArray4.PrimaryDns $VMNICFailoverTestSecondaryDns = $VMSettingNICIDArray4.SecondaryDns $VMNICFailoverTestStaticIp = $VMSettingNICIDArray4.StaticIp $VMNICFailoverTestSubnetMask = $VMSettingNICIDArray4.SubnetMask # Nulling blank content if ($VMNICFailoverTestDNSSuffix.nil -eq $true){$VMNICFailoverTestDNSSuffix = $null}

if ($VMNICFailoverTestGateway.nil -eq $true){$VMNICFailoverTestGateway = $null} if ($VMNICFailoverTestPrimaryDns.nil -eq $true){$VMNICFailoverTestPrimaryDns = $null}

if ($VMNICFailoverTestSecondaryDns.nil -eq $true){$VMNICFailoverTestSecondaryDns = $null} if ($VMNICFailoverTestStaticIp.nil -eq $true){$VMNICFailoverTestStaticIp = $null} if ($VMNICFailoverTestSubnetMask.nil -eq $true){$VMNICFailoverTestSubnetMask = $null} # Mapping Network IDs to Names

$VMNICFailoverNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

$VMNICFailoverTestNetworkName = $VINetworksCMD | Where-Object {$_.NetworkIdentifier -eq $VMNICFailoverTestNetworkIdentifier} | Select VirtualizationNetworkName -ExpandProperty VirtualizationNetworkName

################################################ # Adding all VM NIC setting info to $VMNICArray

################################################

$VMNICArrayLine = new-object PSObject $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPGName $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VPGidentifier" -Value $VPGidentifier $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $VMName

Page 114: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 114 OF 134

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMIdentifier" -Value $VMIdentifier $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICIdentifier" -Value $VMNICIdentifier $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverNetworkName" -Value $VMNICFailoverNetworkName $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDNSSuffix" -Value $VMNICFailoverDNSSuffix $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverShouldReplaceMacAddress" -Value $VMNICFailoverShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverGateway" -Value $VMNICFailoverGateway $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverDHCP" -Value $VMNIsFailoverDHCP $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverPrimaryDns" -Value $VMNICFailoverPrimaryDns $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSecondaryDns" -Value $VMNICFailoverSecondaryDns $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverStaticIp" -Value $VMNICFailoverStaticIp $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverSubnetMask" -Value $VMNICFailoverSubnetMask $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestNetworkName" -Value $VMNICFailoverTestNetworkName $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDNSSuffix" -Value $VMNICFailoverTestDNSSuffix

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestShouldReplaceMacAddress" -Value $VMNICFailoverTestShouldReplaceMacAddress

$VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestGateway" -Value $VMNICFailoverTestGateway $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestDHCP" -Value $VMNIsFailoverTestDHCP $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestPrimaryDns" -Value $VMNICFailoverTestPrimaryDns $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSecondaryDns" -Value $VMNICFailoverTestSecondaryDns $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestStaticIp" -Value $VMNICFailoverTestStaticIp $VMNICArrayLine | Add-Member -MemberType NoteProperty -Name "VMNICFailoverTestSubnetMask" -Value $VMNICFailoverTestSubnetMask $VMNICArray += $VMNICArrayLine

# End of per VM NIC actions below } # End of per VM NIC actions above # # End of per VM actions below } # End of per VM actions above ################################################

# Deleting VPG edit settings ID (same as closing the edit screen on a VPG in the ZVM without making any changes) ################################################ Try { Invoke-RestMethod -Method Delete -Uri $VPGSettingsURL -TimeoutSec 100 -Headers $zertoSessionHeader_XML -ContentType $TypeXML } Catch [system.exception] {

} # # End of check for valid VPG settings ID below } # End of check for valid VPG settings ID above # # End of per VPG actions below

}

# End of per VPG actions above # ################################################ # Exporting VM Nic Settings ################################################ $VMNICArray | export-csv $ExportDataDir"ZVRVMNICS.csv" -NoTypeInformation

Page 115: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 115 OF 134

The following CSV will be created after running this script which can easily be edited with the new port group, IP and MAC address settings:

Once the CSV is configured run the below script to import the new settings: ################################################ # Configure the variables below ################################################ $CSVImportFile = "C:\ZVRBulkReIP\ZVRVMNICS.csv" $ZertoServer = "192.168.0.31" $ZertoPort = "9669"

$ZertoUser = "[email protected]" $ZertoPassword = "Zerto1234!" ######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################ # Importing CSV and building list of VPGs ################################################

$CSVImport = Import-Csv $CSVImportFile $VPGsToConfigure = $CSVImport | select -ExpandProperty VPGName -Unique ################################################ # Setting certificate exception to prevent authentication issues to the ZVM ################################################ 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 Zerto API string and invoking API ################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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"

Page 116: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 116 OF 134

$TypeXML = "application/xml" Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON }

Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force } # Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertoSessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } $CreateVPGURL = $baseURL+"vpgSettings"

################################################ # Starting for each VPG action ################################################ foreach ($VPG in $VPGsToConfigure) { $VPGName = $VPG # Getting VPG Identifier $VPGidentifier = $CSVImport | Where-Object {$_.VPGName -eq $VPGName} | select -ExpandProperty VPGidentifier -Unique

# Getting list of VMs to reconfigure $VMsToConfigure = $CSVImport | Where-Object {$_.VPGName -eq $VPGName} | select -ExpandProperty VMName -Unique # Creating edit VPG JSON $JSON = "{ ""VpgIdentifier"":""$VPGidentifier"" }" ################################################

# Posting the VPG JSON Request to the API ################################################ Try { $VPGSettingsIdentifier = Invoke-RestMethod -Method Post -Uri $CreateVPGURL -Body $JSON -ContentType $TypeJSON -Headers $zertoSessionHeader $ValidVPGSettingsIdentifier = $true } Catch {

$ValidVPGSettingsIdentifier = $false } ################################################ # Skipping if unable to obtain valid VPG setting identifier ################################################ if ($ValidVPGSettingsIdentifier -eq $true) {

################################################

# Getting ZVR IDs for the VPG ################################################ $VPGSettingsURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier $VPGSettings = Invoke-RestMethod -Uri $VPGSettingsURL -Headers $zertoSessionHeader -ContentType $TypeJSON # Getting recovery site ID (needed anyway for network settings) $VPGRecoverySiteIdentifier = $VPGSettings.Basic.RecoverySiteIdentifier

# Getting network info $VINetworksURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/networks"

$VINetworksCMD = Invoke-RestMethod -Uri $VINetworksURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON ################################################ # Starting per VM actions ################################################ foreach ($VM in $VMsToConfigure) { $VMName = $VM # Getting VM settings from the CSV

$VMSettings = $CSVImport | Where-Object {$_.VPGName -eq $VPGName -and $_.VMName -eq $VMName} | select

$VMIdentifier = $CSVImport | Where-Object {$_.VPGName -eq $VPGName -and $_.VMName -eq $VMName} | select -ExpandProperty VMIdentifier -Unique $VMNICIdentifiers = $VMSettings.VMNICIdentifier ##################### # Starting per VM NIC actions

Page 117: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 117 OF 134

##################### foreach ($VMNIC in $VMNICIdentifiers) { $VMNICIdentifier = $VMNIC # Getting VM NIC settings

$VMNICSettings = $VMSettings | Where-Object {$_.VMNICIdentifier -eq $VMNICIdentifier} | select * $VMNICFailoverNetworkName = $VMNICSettings.VMNICFailoverNetworkName $VMNICFailoverDNSSuffix = $VMNICSettings.VMNICFailoverDNSSuffix $VMNICFailoverShouldReplaceMacAddress = $VMNICSettings.VMNICFailoverShouldReplaceMacAddress $VMNICFailoverGateway = $VMNICSettings.VMNICFailoverGateway $VMNICFailoverDHCP = $VMNICSettings.VMNICFailoverDHCP $VMNICFailoverPrimaryDns = $VMNICSettings.VMNICFailoverPrimaryDns $VMNICFailoverSecondaryDns = $VMNICSettings.VMNICFailoverSecondaryDns

$VMNICFailoverStaticIp = $VMNICSettings.VMNICFailoverStaticIp $VMNICFailoverSubnetMask = $VMNICSettings.VMNICFailoverSubnetMask $VMNICFailoverTestNetworkName = $VMNICSettings.VMNICFailoverTestNetworkName $VMNICFailoverTestDNSSuffix = $VMNICSettings.VMNICFailoverTestDNSSuffix $VMNICFailoverTestShouldReplaceMacAddress = $VMNICSettings.VMNICFailoverTestShouldReplaceMacAddress $VMNICFailoverTestGateway = $VMNICSettings.VMNICFailoverTestGateway $VMNICFailoverTestDHCP = $VMNICSettings.VMNICFailoverTestDHCP $VMNICFailoverTestPrimaryDns = $VMNICSettings.VMNICFailoverTestPrimaryDns

$VMNICFailoverTestSecondaryDns = $VMNICSettings.VMNICFailoverTestSecondaryDns $VMNICFailoverTestStaticIp = $VMNICSettings.VMNICFailoverTestStaticIp $VMNICFailoverTestSubnetMask = $VMNICSettings.VMNICFailoverTestSubnetMask # Setting answers to lower case for API to process $VMNICFailoverShouldReplaceMacAddress = $VMNICFailoverShouldReplaceMacAddress.ToLower() $VMNICFailoverDHCP = $VMNICFailoverDHCP.ToLower() $VMNICFailoverTestShouldReplaceMacAddress = $VMNICFailoverTestShouldReplaceMacAddress.ToLower() $VMNICFailoverTestDHCP = $VMNICFailoverTestDHCP.ToLower()

# Translating network names to ZVR Network Identifiers

$VMNICFailoverNetworkIdentifier = $VINetworksCMD | where-object {$_.VirtualizationNetworkName -eq $VMNICFailoverNetworkName} | select -ExpandProperty NetworkIdentifier

$VMNICFailoverTestNetworkIdentifier = $VINetworksCMD | where-object {$_.VirtualizationNetworkName -eq $VMNICFailoverTestNetworkName} | select -ExpandProperty NetworkIdentifier

##################### # Building VMNIC JSON ##################### $VMNICJSON = " {

""Failover"":{ ""Hypervisor"":{ ""DnsSuffix"":""$VMNICFailoverDNSSuffix"", ""IpConfig"":{ ""Gateway"":""$VMNICFailoverGateway"", ""IsDhcp"":$VMNICFailoverDHCP, ""PrimaryDns"":""$VMNICFailoverPrimaryDns"",

""SecondaryDns"":""$VMNICFailoverSecondaryDns"",

""StaticIp"":""$VMNICFailoverStaticIp"", ""SubnetMask"":""$VMNICFailoverSubnetMask"" }, ""NetworkIdentifier"":""$VMNICFailoverNetworkIdentifier"", ""ShouldReplaceMacAddress"":$VMNICFailoverShouldReplaceMacAddress }

}, ""FailoverTest"":{

""Hypervisor"":{ ""DnsSuffix"":""$VMNICFailoverTestDNSSuffix"", ""IpConfig"":{ ""Gateway"":""$VMNICFailoverTestGateway"", ""IsDhcp"":$VMNICFailoverTestDHCP, ""PrimaryDns"":""$VMNICFailoverTestPrimaryDns"", ""SecondaryDns"":""$VMNICFailoverTestSecondaryDns"", ""StaticIp"":""$VMNICFailoverTestStaticIp"",

""SubnetMask"":""$VMNICFailoverTestSubnetMask""

}, ""NetworkIdentifier"":""$VMNICFailoverTestNetworkIdentifier"", ""ShouldReplaceMACAddress"":$VMNICFailoverTestShouldReplaceMacAddress }

Page 118: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 118 OF 134

}, ""NicIdentifier"":""$VMNICIdentifier"" }" ##################### # Creating URL and sending PUT command to API

##################### $EditVMNICURL = $baseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/nics/"+$VMNICIdentifier Try { $EditVMNIC = Invoke-RestMethod -Method PUT -Uri $EditVMNICURL -Body $VMNICJSON -Headers $zertoSessionHeader -ContentType $TypeJSON -TimeoutSec 100 } Catch { Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force } # Waiting for API processing sleep 3 # End of for each VMNIC below } # End of for each VMNIC above #

# End of for each VM below } # End of for each VM above ##################### # Committing VPG settings ##################### $CommitVPGSettingURL = $baseURL+"vpgSettings/"+"$VPGSettingsIdentifier"+"/commit" write-host "CommitVPGSettingURL:$CommitVPGSettingURL"

Try { Invoke-RestMethod -Method Post -Uri $CommitVPGSettingURL -Headers $zertoSessionHeader -ContentType $TypeJSON -TimeoutSec 100 $VPGEditOutcome = "PASSED" } Catch { $VPGEditOutcome = "FAILED" Write-Host $_.Exception.ToString()

$error[0] | Format-List -Force } write-host "VPG:$VPGName VPGEditOutcome=$VPGEditOutcome" # Sleeping before processing next VPG write-host "Waiting 5 seconds before processing next VPG" sleep 5 # End of check for valid VPG settings ID below

}

# End of check for valid VPG settings ID above # # End of per VPG actions below } # End of per VPG actions above

Page 119: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 119 OF 134

8 SCHEDULING OFFSITE CLONES

8.1 Use Cases

To extend the retention of replica VM data beyond the journal it is possible to use offsite clones as a copy mechanism for taking

point-in-time copies of each VPG. Using offsite clones has multiple advantages over utilizing offsite backups, these are:

• Clones are taken by the VRAs, not the ZVM

• Increased throughput many times over by writing directly to ESXi datastores

• Scale-out architecture enabling multiple simultaneous jobs

• Protect many large VMs

• Remove the need for VM-level backup solutions

• Recover VMs by simply registering the VM in the inventory and powering on the VM

• Recover VMs without a ZVM

8.2 Design Methodology

To schedule offsite clones this example script requires a combination of PowerCLI, Zerto PowerShell CMDlets and the Zerto REST API

to fully automate scale-out offsite clone operations. Credentials are therefore required for both Zerto PowerShell authentication

using the users.txt file on the ZVM along with vCenter and Zerto REST API server and credentials for the recovery site ZVM.

This script uses a CSV list to obtain the VPGs to clone along with the datastore on which to store the clones. Offsite clone operations

are then run simulatenously using script blocks, 1 VPG at a time on each VRA, across all of the target site VRAs to maximize the

throughput while minimizing the backup time and overheads.

I.E 10 VPGs replicating to 5 different VRAs = max 5 concurrent Offsite Clones & each VRA will clone 2 VPGs total, one after the other.

It is recommended to check balancing of VPGs to ensure the VPGs are evenly spread and the VMs in each VPG replicate to the same

VRA to minimize the total clone time. The next offsite clone operation on each VRA will only commence when the last offsite clone on

the VRA has finished. The script also has the following features:

• Email reports including clone time, size and throughput

• Automatically remove VMs from the target vCenter inventory (configured as variable in script)

• Use VSS checkpoint with the option to fail if no VSS checkpoint found

For storing the offsite clones, it is recommended to use deduplicated storage to minimize the storage overheads of multiple data

copies. The storage device can be a dedicated physical appliance or Windows Server storage presented to the ESXi hosts using NFS,

see the example below:

http://www.lazywinadmin.com/2013/01/configure-windows-server-2012-nfs.html

Page 120: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 120 OF 134

8.3 Scheduled Offsite Clone

Following is the example script to schedule offsite clones. Key variables to configure are vCenterTimeZoneMatch, to enable accurate

reporting of clone completion times, and ResourceReportHourlySample which should be configured to match the Resource Report

sample rate of the recovery site ZVM which should be set as the ZertoServer variable.

################################################ # Configure the variables below ################################################ # VPGs to clone $OffsiteCloneVPGsCSV = "C:\OffsiteCloneVPGs.csv" # Logging directories

$OffsiteCloneLogDataDir = "C:\ZVROffsiteCloning\" $OffsiteCloneVPGLog = "C:\ZVROffsiteCloning\OffsiteCloneVPGLog.csv" $OffsiteCloneVMLog = "C:\ZVROffsiteCloning\OffsiteCloneVMLog.csv" # vCenter login info $vCenterServer = "192.168.0.82" $vCenterUser = "[email protected]" $vCenterPassword = "Zerto1234!"

# PowerShell login info, can use either ZVM

$ZVMIP = "192.168.0.32" $ZVMPSPort = "9080" $ZMVPSUser = "administrator" $ZVMPSPasswd = "password" # API login Info, must use recovery site ZVM for Resource Report API $ZertoServer = "192.168.0.32" $ZertoPort = "9669" $ZertoUser = "[email protected]"

$ZertoPassword = "Zerto1234!" # Remove VM from inventory toggle TRUE/FALSE $RemoveVMsFromInventory = "TRUE" # Configure the email settings $EmailTo = "[email protected]" $EmailFrom = "[email protected]" $SMTPServer = "localhost" $SMTPPort = "25"

$SMTPUser = "[email protected]" $SMTPPassword = "Srt1234!" $SMTPSSLEnabled = "FALSE" # vCenter timezone and PowerShell script host timezone match # If disabled the VM registration time is overwritten by the time the VM was found, less accurate, but removes time zone issues $vCenterTimeZoneMatch = "FALSE" # Configure resource report sampling rate, by default daily, if left as daily then set the below to false

$ResourceReportHourlySample = "TRUE"

######################################################################################################################## # Nothing to configure below this line - Starting the main function of the script ######################################################################################################################## ################################################ # Setting ZVM security exception for REST API ################################################

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 Zerto API string and invoking API

Page 121: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 121 OF 134

################################################ $baseURL = "https://" + $ZertoServer + ":"+$ZertoPort+"/v1/" # Authenticating with Zerto APIs $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" Try {

$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON } Catch [system.exception] { } Finally { }

#Extracting x-zerto-session from the response, and adding it to the actual API $xZertoSession = $xZertoSessionResponse.headers.get_item("x-zerto-session") $zertosessionHeader = @{"x-zerto-session"=$xZertoSession; "Accept"=$TypeJSON } # URL to create VPG settings $CreateVPGURL = $BaseURL+"vpgSettings" # VPG URL and List $vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

# Build List of VMs $vmListApiUrl = $baseURL+"vms" $vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON # Build List of VRAs $vraListApiUrl = $baseURL+"vras" $vraList = Invoke-RestMethod -Uri $vraListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON # Setting resource report values based on $ResourceReportHourlySample if ($ResourceReportHourlySample -eq "TRUE")

{ $NowDateTime = get-date -Format "yyyy-MM-dd HH:mm:ss" $ThenDateTime = (get-date).AddHours(-1).ToString("yyyy-MM-dd HH:mm:ss") } else { $StartDateTime = get-date -Format "yyyy-MM-dd"

$EndDateTime = (get-date).AddDays(1).ToString("yyyy-MM-dd")

} # QueryResourceReport with entries from the last hour

$ResourceReportURL = "https://" + $ZertoServer + ":"+$ZertoPort + "/ZvmService/ResourcesReport/getSamples?fromTimeString=" + $ThenDateTime + "&toTimeString=" + $NowDateTime + "&startIndex=0&count=500"

$ResourceReport = Invoke-RestMethod -Uri $ResourceReportURL -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON # Importing CSV for VPGs $OffsiteCloneVPGs = import-csv $OffsiteCloneVPGsCSV

$OffsiteCloneVPGsByName = $OffsiteCloneVPGs | Select-Object VPGName -ExpandProperty VPGName # Building list of VRAs that have VPGs to clone

$TargetSiteVPGs = $ResourceReport | Sort-Object VPGName -Unique | Select VPGName,TargetVraName ################################################ # Building array of VRAs that have VPGs that require offsite clone ################################################ $TargetVRAArray = @() foreach ($VPG in $TargetSiteVPGs) { if ($OffsiteCloneVPGsByName -ccontains $VPG.VpgName)

{

$TargetVRAArrayLine = new-object PSObject $TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VPGName" -Value $VPG.VpgName $TargetVRAArrayLine | Add-Member -MemberType NoteProperty -Name "VRAName" -Value $VPG.TargetVraName $TargetVRAArray += $TargetVRAArrayLine

Page 122: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 122 OF 134

} } $TargetSiteVRAs = $TargetVRAArray | Select-Object VRAName -Unique ################################################################################################ # Performing for each VRA that has an offsite clone to run action

################################################################################################ foreach ($VRA in $TargetSiteVRAs) { $VRAName = $VRA.VRAName # Getting the VPGs to clone for the current VPG $VRAVPGsToClone = $null $VRAVPGsToClone = $TargetVRAArray | where-object {$_.VRAName -eq "$VRAName"} | Select-Object VPGName -ExpandProperty VPGName -Unique write-host "$VRAName VPGs to clone:

$VRAVPGsToClone" $Now = get-date $JobTime = $Now.ToString("yyy-MM-dd_HH-mm-ss") ################################################ # Script block within per VRA ################################################ $VRAScriptBlock = { param

(

$VRAName, $VRAVPGsToClone, $vmLis t, $OffsiteCloneVPGs, $vCenterServer, $vCenterUser, $vCenterPassword, $ZVMIP, $ZVMPSPort, $ZMVPSUser, $ZVMPSPasswd, $OffsiteCloneVPGLog, $OffsiteCloneVMLog, $Offsi teCloneLogDataDir, $RemoveVMsFromInventory, $vCenterTimeZoneMatch, $EmailTo, $EmailFrom, $SMTPServer, $SMTPPort, $SMTPUser, $SMTPPassword, $SMTPSSLEnabled

) ################################################ # Creating function to get VM registered date time ################################################ function Get-VMEvents { <#

.Synopsis Get events for an entity or for query all events. .Description This function returns events for entities. It's very similar to get-vievent cmdlet.Note that get-VMEvent can handle 1 vm at a time.

You can not send array of vms in this version of the script. .Example Get-VMEvents 0All -types "VmCreatedEvent","VmDeployedEvent","VmClonedEvent" This will receive ALL events of types "VmCreatedEvent","VmDeployedEvent",

"VmClonedEvent".

.Example Get-VMEvents -name 'vm1' -types "VmCreatedEvent" Will ouput creation events for vm : 'vm1'. This was is faster than piping vms from

get-vm result. There is no need to use get-vm to pass names to get-vmevents. Still, it is ok when you will do it, it will make it just a little bit slower😉

.Example Get-VMEvents -name 'vm1' -category 'warning' Will ouput all events for vm : 'vm1'. This was is faster than piping names from get-vm cmdlet. Category will make get-vmevent to search only defined category events.

.Example get-vm 'vm1' | Get-VMEvents -types "VmCreatedEvent","VmMacAssignedEvent"

Page 123: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 123 OF 134

Will display events from vm1 which will be regarding creation events, and events when when/which mac address was assigned .Parameter VM

This parameter is a single string representing vm name. It expects single vm name that exists in virtual center. At this moment in early script version it will handle only a case where there is 1 instance of vm of selected name. In future, it will handle multiple as well. .Parameter types

If none specified it will return all events. If specified will return only events with selected types. For example : "VmCreatedEvent", "VmDeployedEvent", "VmMacAssignedEvent" "VmClonedEvent" , etc... .Parameter category Possible categories are : warning, info, error. Please use this parameter if you want to filter events.

.Parameter All If you will set this parameter, as a result command will query all events from virtual center server regarding virtual machines. .Notes

NAME: VMEvents AUTHOR: Grzegorz Kulikowski LASTEDIT: 11/09/2012 NOT WORKING ? #powercli @ irc.freenode.net

.Link https://psvmware.wordpress.com #> param( [Parameter(ValueFromPipeline=$true)]

[ValidatenotNullOrEmpty()]

$VM, [String[]]$types, [string]$category, [switch]$All ) $si=get-view ServiceInstance

$em= get-view $si.Content.EventManager $EventFilterSpec = New-Object VMware.Vim.EventFilterSpec

$EventFilterSpec.Type = $types if($category){ $EventFilterSpec.Category = $category } if ($VM){ $EventFilterSpec.Entity = New-Object VMware.Vim.EventFilterSpecByEntity switch ($VM) {

{$_ -is [VMware.Vim.VirtualMachine]} {$VMmoref=$vm.moref}

{$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]}{$VMmoref=$vm.Extensiondata.moref} default {$vmmoref=(get-view -ViewType virtualmachine -Filter @{'name'=$VM}).moref } } $EventFilterSpec.Entity.Entity = $vmmoref

Page 124: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 124 OF 134

$em.QueryEvents($EventFilterSpec) } if ($All) { $em.QueryEvents($EventFilterSpec) }

} function get-vmcreationdate { <# .Synopsis Gets where possible vm creation date. .Description

This function will return object with information about creation time, method, month, creator for particular vm. VMname : SomeVM12 CreatedTime : 8/10/2012 11:48:18 AM CreatedMonth : August CreationMethod : Cloned Creator : office\greg

This function will display NoEvent value in properties in case when your VC does no longer have information about those particular events, or your vm events no longer have entries about being created. If your VC database has longer retension date it is more possible that you will find this event. .Example

Get-VMCreationdate -VMnames "my_vm1","My_otherVM" This will return objects that contain creation date information for vms with names myvm1 and myvm2 .Example Get-VM -Location 'Cluster1' |Get-VMCreationdate

This will return objects that contain creation date information for vms that are located in Cluster1 .Example Get-view -viewtype virtualmachine -SearchRoot (get-datacenter 'mydc').id|Get-VMCreationDate

This will return objects that contain creation date information for vms that are located in datacenter container 'mydc'. If you are using this function within existing loop where you have vms from get-view cmdlet, you can pass them via pipe or as VMnames parameter. .Example

$report=get-cluster 'cl-01'|Get-VMCreationdate $report | export-csv c:\myreport.csv

Will store all reported creationtimes object in $report array variable and export report to csv file. You can also filter the report before writing it to csv file using select $report | Where-Object {$_.CreatedMonth -eq "October"} | Select VMName,CreatedMonth So that you will see only vms that were created in October. .Example get-vmcreationdate -VMnames "my_vm1",testvm55

WARNING: my_vm1 could not be found, typo?

VMname : testvm55 CreatedTime : 10/5/2012 2:24:03 PM CreatedMonth : October CreationMethod : NewVM

Page 125: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 125 OF 134

Creator : home\greg In the case when your provided vm does not exists in yor infrastructure, a warning will be displayed. You can still store the whole report in $report variable, but it will not include any information about missing vm creation dates. A warning will be still displayed only for your information that there was probably a typo in the vm name.

.Parameter VMnames This parameter should contain virtual machine objects or strings that represents vm names. It is possible to feed this function wiith VM objects that come from get-vm or from get-view.

.Notes NAME: Get-VMCreationdate AUTHOR: Grzegorz Kulikowski LASTEDIT: 27/11/2012

NOT WORKING ? #powercli @ irc.freenode.net .Link https://psvmware.wordpress.com #>

param( [Parameter(ValueFromPipeline=$true,Mandatory = $true)] [ValidateNotNullOrEmpty()] [Object[]]$VMnames ) process { foreach ($vm in $VMnames){ $ReportedVM = ""|Select VMname,CreatedTime,CreatedMonth,CreationMethod,Creator

if ($CollectedEvent=$vm|Get-VMEvents -types 'VmBeingDeployedEvent','VmRegisteredEvent','VmClonedEvent','VmBeingCreatedEvent' -ErrorAction SilentlyContinue) { if($CollectedEvent.gettype().isArray){$CollectedEvent=$CollectedEvent|?{$_ -is [vmware.vim.VmRegisteredEvent]}} $CollectedEventType=$CollectedEvent.gettype().name $CollectedEventMonth = "{0:MMMM}" -f $CollectedEvent.CreatedTime $CollectedEventCreationDate=$CollectedEvent.CreatedTime $CollectedEventCreator=$CollectedEvent.Username

switch ($CollectedEventType)

{ 'VmClonedEvent' {$CreationMethod = 'Cloned'} 'VmRegisteredEvent' {$CreationMethod = 'RegisteredFromVMX'} 'VmBeingDeployedEvent' {$CreationMethod = 'VmFromTemplate'} 'VmBeingCreatedEvent' {$CreationMethod = 'NewVM'} default {$CreationMethod='Error'}

} $ReportedVM.VMname=$CollectedEvent.vm.Name

$ReportedVM.CreatedTime=$CollectedEventCreationDate $ReportedVM.CreatedMonth=$CollectedEventMonth $ReportedVM.CreationMethod=$CreationMethod $ReportedVM.Creator=$CollectedEventCreator }else { if ($?) { if($vm -is [VMware.Vim.VirtualMachine]){$ReportedVM.VMname=$vm.name} else {$ReportedVM.VMname=$vm.ToString()} $ReportedVM.CreatedTime = 'NoEvent'

$ReportedVM.CreatedMonth = 'NoEvent'

$ReportedVM.CreationMethod = 'NoEvent' $ReportedVM.Creator = 'NoEvent' } else {

Page 126: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 126 OF 134

$ReportedVM = $null Write-Warning "$VM could not be found, typo?" } } $ReportedVM

} } } function Convert-Size { [cmdletbinding()] param( [validateset("Bytes","KB","MB","GB","TB")] [string]$From,

[validateset("Bytes","KB","MB","GB","TB")] [string]$To, [Parameter(Mandatory=$true)] [double]$Value, [int]$Precision = 4 ) switch($From) { "Bytes" {$value = $Value }

"KB" {$value = $Value * 1024 } "MB" {$value = $Value * 1024 * 1024} "GB" {$value = $Value * 1024 * 1024 * 1024} "TB" {$value = $Value * 1024 * 1024 * 1024 * 1024} } switch ($To) { "Bytes" {return $value}

"KB" {$Value = $Value/1KB} "MB" {$Value = $Value/1MB} "GB" {$Value = $Value/1GB} "TB" {$Value = $Value/1TB} } return [Math]::Round($value,$Precision,[MidPointRounding]::AwayFromZero)

} ################################################ # Setting log directory for engine and current month ################################################ $CurrentMonth = get-date -format yyyy.MM $CurrentLogDataDir = $OffsiteCloneLogDataDir + $CurrentMonth

$CurrentTime = get-date -format hh.mm.ss

# Testing path exists to engine logging, if not creating it $ExportDataDirTestPath = test-path $CurrentLogDataDir $CurrentLogDataFile = $CurrentLogDataDir + "\$CurrentTime" + "-$VRAName" + "-OffsiteClone" + ".txt" if ($ExportDataDirTestPath -eq $False) { New-Item -ItemType Directory -Force -Path $CurrentLogDataDir

} start-transcript -path $CurrentLogDataFile -NoClobber

################################################ # Adds the Zerto Powershell CMDlets ################################################ function LoadSnapin{ param($PSSnapinName) if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){ Add-pssnapin -name $PSSnapinName }

}

LoadSnapin -PSSnapinName "Zerto.PS.Commands" ################################################ # Connecting to vCenter - required for successful authentication with Zerto API ################################################

Page 127: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 127 OF 134

Try { connect-viserver -Server $vCenterServer -User $vCenterUser -Password $vCenterPassword } Catch [system.exception]

{ } Finally { } ################################################ # For each VPG to Clone ################################################

write-host "Cloning up the following VPGs on this VRA: $VRAVPGsToClone" foreach ($VPG in $VRAVPGsToClone) { $VPGCloneStartTime = get-date $VPGName = $VPG write-host "Cloning VPG: $VPGName" $VPGCloneDatastore = $OffsiteCloneVPGs | Where-Object {$_.VPGName -eq "$VPGName"} | Select-Object CloneDatstore -ExpandProperty CloneDatastore

$VPGUseLastVSS = $OffsiteCloneVPGs | Where-Object {$_.VPGName -eq "$VPGName"} | Select-Object UseLastVSS -ExpandProperty UseLastVSS $VPGFailIfNoVSS = $OffsiteCloneVPGs | Where-Object {$_.VPGName -eq "$VPGName"} | Select-Object FailIfNoVSS -ExpandProperty FailIfNoVSS $VMNames = $vmList | Where-Object {$_.VpgName -eq "$VPGName"} | select VmName -ExpandProperty VmName $VMCount = $VMNames.Count ################################################ # For each VPG to Clone ################################################ # Getting CP for VPG irrespective of VSS setting

Try {

$cp_list = get-checkpoints -virtualprotectiongroup $VPGName -zvmip $ZVMIP -zvmport $ZVMPSPort -username $ZMVPSUser -password $ZVMPSPasswd -confirm:$false

$last_cp = $cp_list[$cp_list.Count-1] # Changing last checkpoint time into usable value for logging $latesttimeobject = $last_cp | select-object timestamp | select -expandproperty timestamp $VPGTimeSuffix = $latesttimeobject.ToString("yyy-MM-dd_HH-mm-ss") }

Catch [system.exception] { } Finally { } ################################################

# If use last VSS CP is enabled

################################################ if ($VPGUseLastVSS -eq "TRUE") { $lastvss_cpall = $cp_list | Where-Object {$_.Vss -eq $True} $lastvss_cp = $lastvss_cpall[$lastvss_cpall.Count-1] # Changing last checkpoint time into usable value for logging

$latestvsstimeobject = $lastvss_cp | select-object timestamp | select -expandproperty timestamp $VPGVSSTimeSuffix = $latesttimeobject.ToString("yyy-MM-dd_HH-mm-ss")

} ################################################ # Running offsite clone where there is no VSS checkpoint and job is set not to fail if no VSS found ################################################ if (($lastvss_cp -eq $null) -and ($VPGFailIfNoVSS -eq "False")) { $VPGVSSCPUsed = "FALSE" Try

{

clone-vpg -virtualprotectiongroup $VPGName -checkpoint $last_cp -datastore $VPGCloneDatastore -zvmip $ZVMIP -zvmport $ZVMPSPort -username $ZMVPSUser -password $ZVMPSPasswd -confirm:$false

$OffsiteCloneJobSuccess = "TRUE" } Catch [system.exception]

Page 128: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 128 OF 134

{ $OffsiteCloneJobSuccess = "FALSE" } Finally {

} # End of offsite clone for no VSS CP and job set not to fail } ################################################ # If VSS CP is enabled and not null, run offsite clone against the VSS CP ################################################ if ($lastvss_cp -ne $null) {

$VPGVSSCPUsed = "TRUE" # Setting VPG time suffix for VSS CP $VPGTimeSuffix = $VPGVSSTimeSuffix # Running offsite clone where there is no VSS checkpoint and job is set not to fail if no VSS found Try {

clone-vpg -virtualprotectiongroup $VPGName -checkpoint $lastvss_cp -datastore $VPGCloneDatastore -zvmip $ZVMIP -zvmport $ZVMPSPort -username $ZMVPSUser -password $ZVMPSPasswd -confirm:$false

$OffsiteCloneJobSuccess = "TRUE"

} Catch [system.exception] { $OffsiteCloneJobSuccess = "FALSE" } Finally { }

# End of offsite clone for VSS CP } ################################################ # No VSS CP found and VPGFailIfNoVSS set to true ################################################ if (($lastvss_cp -ne $null) -and ($VPGFailIfNoVSS -eq "True")) { $VPGVSSCPUsed = "FALSE"

$OffsiteCloneJobSuccess = "FALSE" write-host "No VSS CP Found and VPGFailIfNoVSS set to TRUE" } ################################################ # Getting VM Names from VPG and CP time ################################################ $VMNames = $vmList | Where-Object {$_.VpgName -eq "$VPGName"} | select VmName -ExpandProperty VmName

$VMCount = $VMNames.Count

write-host "Checking for Clones of VMs: $VMNames" foreach ($_ in $VMNames) { # Setting VM name $OffsiteCloneVMName = $_.VMName + " - " + $VPGTimeSuffix

################################################ # Running VM exist check to validate end of clone job outcome & time

################################################ $vmexistcounter = 0 $vmexistcountermax = 720 $vmexistsleep = 120 do { # $vmexistcounterremain = $vmexistcountermax - $vmexistcounter write-host "Running VMExist Check for $OffsiteCloneVMName in $vmexistsleep seconds, will try another $vmexistcounterremain times"

sleep $vmexistsleep

# Getting VM name Try { $VMNameExists = Get-VM -name $OffsiteCloneVMName

Page 129: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 129 OF 134

} Catch [system.exception] { } Finally

{ } if (!$VMNameExists) { Write-Host "No VM exists named:$OffsiteCloneVMName" $VMExist = "FALSE" } else

{ Write-Host "A VM exists named:$OffsiteCloneVMName" $VMExist = "TRUE" } $vmexistcounter++ } until (($VMExist -eq "TRUE") -or ($vmexistcounter -eq "480")) if ($VMExist -eq "TRUE") { # Calculating VM clone time based on VM creation date

$VMCloneEndTime = get-vm $OffsiteCloneVMName | Get-VMCreationDate | Select-Object CreatedTime -ExpandProperty CreatedTime [datetime]$VMCloneEndTime if ($vCenterTimeZoneMatch -eq "FALSE") { # PS host and vCenter time zones don't match, over writing VMCLoneEndTime otherwise it will show the wrong time taken $VMCloneEndTime = get-date } $VMCloneTimeTakenTimeSpan = new-timespan -Start $VPGCloneStartTime -End $VMCloneEndTime

$VMCloneTotalHours = $VMCloneTimeTakenTimeSpan | Select-Object TotalHours -ExpandProperty TotalHours $VMCloneTotalDays = $VMCloneTimeTakenTimeSpan | Select-Object TotalDays -ExpandProperty TotalDays # If Clone took more than 1 day, adding days to time string, if not then its removed if ($VMCloneTotalDays -ge 1) { $VMCloneTimeTaken = $VMCloneTimeTakenTimeSpan.ToString("dd\:hh\:mm\:ss") } else

{ $VMCloneTimeTaken = $VMCloneTimeTakenTimeSpan.ToString("hh\:mm\:ss") } write-host "VMCloneTimeTaken:$VMCloneTimeTaken" # Getting Clone VM size and calcuating throughput in Mb/sec $VMSizeinGB = (get-vm $OffsiteCloneVMName | Get-HardDisk | measure-Object CapacityGB -Sum).sum $VMSizeinTB = convert-size -From GB -TO TB -Value $VMSizeinGB -Precision 3

$VMThroughputLong = ($VMSizeinTB * 1024 * 1024 * 8) / ($VMCloneTotalHours * 60 * 60)

$VMThroughput = [Math]::Round($VMThroughputLong,2) } # Removing VM from inventory if specified in job if ($RemoveVMsFromInventory -eq "TRUE") { write-host "RemoveVMsFromInventory set to TRUE Executing:

Remove-VM -VM $OffsiteCloneVMName -Confirm:$false" Try

{ Remove-VM -VM $OffsiteCloneVMName -Confirm:$false } Catch [system.exception] { # Failed to remove VM, waiting 30 seconds and trying again sleep 30 Try

{

Remove-VM -VM $OffsiteCloneVMName -Confirm:$false } Catch [system.exception] {

Page 130: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 130 OF 134

} # End of first catch } Finally {

} # End of try to remove VM from inventory } # VM not found in inventory, failing job if ($VMExist -eq "FALSE") { $OffsiteCloneJobSuccess = "FALSE" }

# Resetting array $OffsiteCloneVMLogArray = @() write-host "Adding $OffsiteCloneVMName to OffsiteCloneVMLogArray" $OffsiteCloneVMLogArrayLine = new-object PSObject $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMCloneStart" -Value $VPGCloneStartTime $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMCloneEnd" -Value $VMCloneEndTime $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMCloneTimeTaken" -Value $VMCloneTimeTaken $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VpgName" -Value $VPGName

$OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "CheckpointTimeStamp" -Value $VPGTimeSuffix $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMName" -Value $OffsiteCloneVMName $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMSizeinTB" -Value $VMSizeinTB $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMSizeinGB" -Value $VMSizeinGB $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "ThroughputMbSec" -Value $VMThroughput $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMFoundInInventory" -Value $OffsiteCloneVMName $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastore" -Value $VPGCloneDatastore $OffsiteCloneVMLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMDatastoreFolderName" -Value $OffsiteCloneVMName

$OffsiteCloneVMLogArray += $OffsiteCloneVMLogArrayLine write-host "VM Array: $OffsiteCloneVMLogArray" # Exporting to CSV $OffsiteCloneVMLogCheck = test-path $OffsiteCloneVMLog if ($OffsiteCloneVMLogCheck -eq $False) { $OffsiteCloneVMLogArray | Sort-Object -Property VpgName | export-csv $OffsiteCloneVMLog -NoTypeInformation

} else { $OffsiteCloneVMLogArray | Sort-Object -Property VpgName | export-csv $OffsiteCloneVMLog -Append -NoTypeInformation } # End of for each VM below }

# End of for each VM above

# # Calculating longest VM clone time and using it to calculate last then total VPG clone time $VPGCloneEndTime = $OffsiteCloneVMLogArray | Sort-Object VMCloneEnd -Descending | select-object VMCloneEnd -expandproperty VMCloneEnd -First 1 $VPGCloneTimeTakenTimeSpan = new-timespan -Start $VPGCloneStartTime -End $VPGCloneEndTime $VPGCloneTotalDays = $VPGCloneTimeTakenTimeSpan | Select-Object TotalDays -ExpandProperty TotalDays # If Clone took more than 1 day, adding days to time string, if not then its removed

if ($VPGCloneTotalDays -ge 1) {

$VPGCloneTimeTaken = $VPGCloneTimeTakenTimeSpan.ToString("dd\:hh\:mm\:ss") } else { $VPGCloneTimeTaken = $VPGCloneTimeTakenTimeSpan.ToString("hh\:mm\:ss") } # Getting total VM sizes of VPG $OffsiteCloneSizeinTB = ($OffsiteCloneVMLogArray.VMSizeinTB | measure -sum | select-object sum -expandproperty sum)

$OffsiteCloneSizeinGB = ($OffsiteCloneVMLogArray.VMSizeinGB | measure -sum | select-object sum -expandproperty sum)

$OffsiteCloneAverageThroughputMbSec = ($OffsiteCloneVMLogArray.ThroughputMbSec | measure -average | select-object average -expandproperty average) # Creating array $OffsiteCloneVPGLogArray = @() # Logging VPG Job outcome

Page 131: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 131 OF 134

$OffsiteCloneVPGLogArrayLine = new-object PSObject $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "CloneStart" -Value $VPGTimeSuffix $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "CloneEnd" -Value $VPGCloneEndTime $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "CloneTimeTaken" -Value $VPGCloneTimeTaken $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "VpgName" -Value $VPGName

$OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "JobSuccessful" -Value $OffsiteCloneJobSuccess $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "CheckpointTimeStamp" -Value $VPGTimeSuffix $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "VPGFailIfNoVSS" -Value $VPGFailIfNoVSS $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "VSSCheckpoint" -Value $VPGVSSCPUsed $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "TotalSizeinTB" -Value $OffsiteCloneSizeinTB $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "TotalSizeinGB" -Value $OffsiteCloneSizeinGB $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "AverageThroughputMbSec" -Value $OffsiteCloneAverageThroughputMbSec $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "VMCount" -Value $VMCount

$OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "VRAName" -Value $VRAName $OffsiteCloneVPGLogArrayLine | Add-Member -MemberType NoteProperty -Name "CloneDatastore" -Value $VPGCloneDatastore $OffsiteCloneVPGLogArray += $OffsiteCloneVPGLogArrayLine # Checking to see if file exists $OffsiteCloneVPGLogCheck = test-path $OffsiteCloneVPGLog if ($OffsiteCloneVPGLogCheck -eq $False) { $OffsiteCloneVPGLogArray | Sort-Object -Property VpgName | export-csv $OffsiteCloneVPGLog -NoTypeInformation

} else { $OffsiteCloneVPGLogArray | Sort-Object -Property VpgName | export-csv $OffsiteCloneVPGLog -Append -NoTypeInformation } # Creating per VPG email $VPGHTMLMain = @" <html>

<head> <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> <title></title> </head> <body> <table style="text-align: left; width: 100%;" border="1" cellpadding="2" cellspacing="2">

<tbody> <tr> <td style="vertical-align: top;">CloneStart</td> <td style="vertical-align: top;">CloneEnd</td> <td style="vertical-align: top;">CloneTimeTaken</td> <td style="vertical-align: top;">VpgName</td> <td style="vertical-align: top;">JobSuccessful</td>

<td style="vertical-align: top;">CheckpointTimeStamp</td>

<td style="vertical-align: top;">VSSCheckpointRequired</td> <td style="vertical-align: top;">VSSCheckpoint</td> <td style="vertical-align: top;">TotalSizeinTB</td> <td style="vertical-align: top;">TotalSizeinGB</td> <td style="vertical-align: top;">AverageThroughputMbSec</td> <td style="vertical-align: top;">VMCount</td>

<td style="vertical-align: top;">VRAName</td> <td style="vertical-align: top;">CloneDatastore</td>

</tr> "@ # Creating HTML Row $VPGHTMLRow = " <tr> <td>$VPGTimeSuffix</td> <td>$VPGCloneEndTime</td> <td>$VPGCloneTimeTaken</td>

<td>$VPGName</td>

<td>$OffsiteCloneJobSuccess</td> <td>$VPGTimeSuffix</td> <td>$VPGFailIfNoVSS</td> <td>$VPGVSSCPUsed</td>

Page 132: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 132 OF 134

<td>$OffsiteCloneSizeinTB</td> <td>$OffsiteCloneSizeinGB</td> <td>$OffsiteCloneAverageThroughputMbSec</td> <td>$VMCount</td> <td>$VRAName</td>

<td>$VPGCloneDatastore</td> </tr>" $VPGHTMLTable += $VPGHTMLRow # Compiling End of HTML email $VPGHTMLEnd = @" </tbody> </table> <br>

</body> </html> "@ # Compiling Final HTML $VPGHTML = $VPGHTMLMain + $VPGHTMLTable + $VPGHTMLEnd # Sending per VPG email $EmailSubject = "OffsiteCloneVPG:$VPGName JobSuccess:$OffsiteCloneJobSuccess" # Nothing to configure below

# Building SMTP settings beased on settings $emailsetting = New-Object System.Net.Mail.MailMessage $emailsetting.to.add($EmailTo) $emailsetting.from = $EmailFrom $emailsetting.IsBodyHTML = "TRUE" $emailsetting.subject = $EmailSubject $emailsetting.body = $VPGHTML # Creating SMTP object

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort); # Enabling SSL if set if ($SMTPSSLEnabled -eq "TRUE") { $smtp.EnableSSL = "TRUE" } # Setting credentials $smtp.Credentials = New-Object System.Net.NetworkCredential($SMTPUser, $SMTPPassword);

# Sending the Email Try { $smtp.send($emailsetting) } Catch [system.exception] {

}

Finally { } # Resetting HTML email row table $VPGHTMLTable = $null # End of for each VPG below

} # End of for each VPG above

# ################################################ # Disconnecting from vCenter ################################################ disconnect-viserver $vCenterServer -Force -Confirm:$false ################################################ # Stopping logging ################################################

stop-transcript

# # End of script block below } # End of script block above

Page 133: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 133 OF 134

################################################ # Starting Job to execute script block for each VRA ################################################ # Size significantly reduced to stop line break issues when copying and pasting

Start-Job $VRAScriptBlock -Name "$JobTime $VRAName OffsiteClone" -ArgumentList $VRAName, $VRAVPGsToClone, $vmList, $OffsiteCloneVPGs, $vCenterServer, $vCenterUser, $vCenterPassword, $ZVMIP, $ZVMPSPort, $ZMVPSUser, $ZVMPSPasswd, $OffsiteCloneVPGLog, $OffsiteCloneVMLog, $OffsiteClone Log DataDir, $RemoveVMsFromInventory, $vCenterTimeZoneMatch, $EmailTo, $EmailFrom, $SMTPServer, $SMTPPort, $SMTPUser, $SMTPPassword, $SMTPSSLEnabled

# End of for each VRA below } # End of for each VRA above

Page 134: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/Marketing_Material... · 2018-04-08 · Automating Zerto Virtual Replication with PowerShell

AUTOMATING ZVR WITH POWERSHELL & REST API WHITEPAPER 134 OF 134

9 TROUBLESHOOTING One of the most powerful tools at your disposal when working with PowerShell and APIs is to encapsulate your Invoke-WebRequest commands inside a Try/Catch statement to get more information on the error being returned. This can be very useful for troubleshooting everything from complex VPG creation to initial authentication with the API. Following is an example of a try statement to aid with troubleshooting:

Try { $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURL -Headers $headers -Method POST -Body $sessionBody -ContentType $TypeJSON

} Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force }

A graphical editing tool such as PowerShell ISE is recommended for not only the first run of your powershell scripts, but to aid with real-time troubleshooting and should be used whenever an error is encountered:

By utilizing the transcipting method as described in section 2.5 it is possible to see any exceptions caught during the script runtime. This can be used in combination with the Zerto Virtual Manager logs to correlate the error if it was generated by the REST API. These logs can be found be browsing to the below file on the ZVM: c:\Program Files\Zerto\Zerto Virtual Replication\logs\logfile.csv