automating zerto virtual replication with powershells3.amazonaws.com/zertodownload_docs/4.0u6/white...

135
Automating Zerto Virtual Replication with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

Upload: others

Post on 19-Jul-2020

24 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

Automating Zerto Virtual Replication with PowerShell & REST APIs Whitepaper

VERSION 2.0

AUGUST 2016

Page 2: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

1 ................................................................................................................................................ 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 ............................................................................................................................... 12

3.1 Use Cases ..................................................................................................................... 12

3.1 Listing Unprotected VMs ............................................................................................. 12

3.2 Using UnProtected VM IDs........................................................................................... 12

3.3 Listing Protected VMs & VPGs ..................................................................................... 13

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

3.5 Resource Reports ......................................................................................................... 16

3.6 Resource Report Use Cases .......................................................................................... 18

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

4 ................................................................................................................................... 28

4.1 Use Cases ..................................................................................................................... 28

4.2 Design Methodology .................................................................................................... 28

4.3 Daily Email Report ........................................................................................................ 28

5 ....................................................................................................................... 68

5.1 Use Cases ..................................................................................................................... 68

5.2 Bulk Automated VRA Deployment ............................................................................... 68

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

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

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

6 ................................................................................................................. 90

6.1 Use Cases ..................................................................................................................... 90

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

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

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

6.5 Adding VMs to VPGs .................................................................................................. 106

Page 3: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

7 .............................................................................................................................. 108

7.1 Bulk VPG Name Changing .......................................................................................... 108

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

8 ................................................................................................................... 120

8.1 Use Cases ................................................................................................................... 120

8.2 Design Methodology .................................................................................................. 120

8.3 Scheduled Offsite Clone ............................................................................................. 121

9 ..................................................................................................................................... 135

Page 4: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

1

Page 5: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

2 BASICS & BEST PRACTICES

$ZertoServer = "192.168.0.31"

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

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

$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/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

################################################ # 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

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

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

Page 7: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

function LoadSnapin{

param($PSSnapinName) if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){

Add-pssnapin -name $PSSnapinName } }

# Loading snapins and modules LoadSnapin -PSSnapinName "VMware.VimAutomation.Core"

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

# Setting Cert Policy - required for successful auth with the Zerto API with non trusted certs ################################################ 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/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

Page 9: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

################################################ # 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 ################################################ # Importing PowerCLI snap-in required for successful authentication with Zerto API ################################################ function LoadSnapin{ param($PSSnapinName) if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){ Add-pssnapin -name $PSSnapinName } } # Loading snapins and modules LoadSnapin -PSSnapinName "VMware.VimAutomation.Core" ################################################ # 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

Page 11: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} #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}

Page 12: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

3

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

# 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

# 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 $VMMemoryGB = $VMInfo.MemoryGB

Page 13: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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 14: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

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

# 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 15: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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 16: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 17: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

# 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

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

$ResourceReportAPITable

Page 18: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 19: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 20: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

# 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 = @{"x-zerto-session"=$xZertoSession}

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

# Creating Arrays for populating ZVM info from the API

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

$VPGArray = @()

$VMArray = @()

$VMVolumeArray = @()

$VMNICArray = @()

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

# Creating VPGArray, VMArray, VMVolumeArray, VMNICArray

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

# URL to create VPG settings

$CreateVPGURL = $baseURL+"vpgSettings"

Page 21: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# Build List of VPGs

$vpgListApiUrl = $baseURL+"vpgs"

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

# Build List of VMs

$vmListApiUrl = $baseURL+"vms"

$vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -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

$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 -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 -ContentType $TypeJSON

# Getting network info

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

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

# Getting datastore info

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

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

# Getting datastore cluster info

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

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

# Getting folder info

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

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

# Getting cluster info

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

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

# Getting host info

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

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

# Getting resource pool info

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

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

Page 22: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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

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

Page 23: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$VMDatastoreClusterIdentifier = $GetVMSettings.Recovery.DatastoreClusterIdentifier

Page 24: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 -ContentType $TypeXML

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

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

Page 25: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 -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 -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 -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}

Page 26: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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 27: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

Invoke-RestMethod -Method Delete -Uri $VPGSettingsURL -TimeoutSec 100 -Headers $zertoSessionHeader -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 28: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

4

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

# 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],[email protected]"

$EmailFrom = "[email protected]"

$SMTPServer = "localhost"

$SMTPPort = "25"

Page 29: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$SMTPUser = "[email protected]"

$SMTPPassword = "Srt1234!"

$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 30: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 = @()

$TargetVRAArray = @()

Page 31: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$VMStatusArray += $VMStatusArrayLine

Page 32: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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

$EventStatusArrayLine = new-object PSObject

Page 33: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 34: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 35: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 36: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 37: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 38: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$EventStatusArrayLine = new-object PSObject

Page 39: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 40: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

# Importing PowerCLI snap-in required

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

function LoadSnapin{

param($PSSnapinName)

if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){

Add-pssnapin -name $PSSnapinName

}

}

# Loading snapins and modules

LoadSnapin -PSSnapinName "VMware.VimAutomation.Core"

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

# 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

Page 41: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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(

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 = @{"x-zerto-session"=$SourceZVMSession}

if ($SourceZVMAuthentication -eq "PASS")

{

# Get SiteIdentifier for later in the script

$SourceSiteInfoURL = $SourceZVMBaseURL+"localsite"

$SourceSiteInfoCMD = Invoke-RestMethod -Uri $SourceSiteInfoURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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

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

Page 42: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

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

Page 43: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$VPGStatusDescription = $VMStatusArray | Where-Object {$_.Number -eq $StatusNumber} | select -ExpandProperty Description

# Gettong VPG Journal size

$VPGResourceReport = $ResourceReport | Where-Object {$_.VpgName -eq $VPGName}

# Calculating total Journal usage

$VPGJournalUsage = $VPGResourceReport.RecoveryJournalUsedStorageInGB

$VPGTotalJournalUsage = 0

foreach ($_ in $VPGJournalUsage)

{

$VPGTotalJournalUsage += $_

}

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

Page 44: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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"

$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 += $_

Page 45: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

}

$TotalTargetVraMemoryInGB = $TotalTargetVraMemoryInMB / 1024

$TotalTargetVraMemoryInGB = [math]::Round($TotalTargetVraMemoryInGB,2)

# Calculating total ActiveGuestMemoryInMB

$TargetVraActiveGuestMemoryInMB = $TargetVraData.ActiveGuestMemoryInMB

$TotalTargetVraActiveGuestMemoryInMB = 0

foreach ($_ in $TargetVraActiveGuestMemoryInMB)

{

$TotalTargetVraActiveGuestMemoryInMB += $_

}

$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 -ContentType $TypeJSON

# For each unprotected VM

foreach ($VM in $SourceZVMUnprotectedVMsCMD)

{

Page 46: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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

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

Page 47: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

}

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

$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 -ContentType $TypeXML

# Build List of VMs

$vmListApiUrl = $SourceZVMBaseURL+"vms"

$vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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

$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 -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 -ContentType $TypeJSON

# Getting network info

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

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

# Getting datastore info

Page 48: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

# Getting datastore cluster info

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

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

# Getting folder info

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

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

# Getting cluster info

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

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

# Getting host info

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

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

# Getting resource pool info

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

$VIResourcePoolsCMD = Invoke-RestMethod -Uri $VIResourcePoolsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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

Page 49: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

Page 50: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$GetVMSettings = Invoke-RestMethod -Method Get -Uri $GetVMSettingsURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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

$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

Page 51: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 = $SourceZVMBaseURL+"vpgSettings/"+$VPGSettingsIdentifier+"/vms/"+$VMIdentifier+"/volumes"

$GetVMSettingVolumes = Invoke-RestMethod -Method Get -Uri $GetVMSettingVolumesURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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 -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 -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 = $_

Page 52: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$GetVMSettingNIC = Invoke-RestMethod -Method Get -Uri $GetVMSettingNICURL -TimeoutSec 100 -Headers $SourceZVMSessionHeader -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 "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

Page 53: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

Page 54: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

Page 55: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

<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

Page 56: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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>

<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

Page 57: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$VRARecoveryVolumesInTB = $_.VRARecoveryVolumesInTB

$VRARecoveryJournalsInTB = $_.VRARecoveryJournalsInTB

$VMNumberOfvCPU = $_.VMNumberOfvCPU

$VMCpuUsedInGhz = $_.VMCpuUsedInGhz

$VMMemoryInGB = $_.VMMemoryInGB

$VMActiveMemoryInGB = $_.VMActiveMemoryInGB

# Building HTML table row

$TargetVRAArrayHTMLTableRow = "

<tr>

<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

Page 58: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$NumCPU = $_.NumCPU

$MemoryGB = $_.MemoryGB

$NICS = $_.NICS

$HardDisks = $_.HardDisks

$UsedSpaceGB = $_.UsedSpaceGB

# Building HTML table row

$UnprotectedVMArrayHTMLTableRow = "

<tr>

<td class=""tg-yw4l"">$SourcePOD</td>

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

Page 59: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

<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

$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

Page 60: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$VPGVMCount = $_.VPGVMCount

$VPGPriortiy = $_.VPGPriortiy

$VPGProtectedSiteName = $_.VPGProtectedSiteName

$VPGProtectedSiteIdentifier = $_.VPGProtectedSiteIdentifier

$VPGRecoverySiteName = $_.VPGRecoverySiteName

$VPGRecoverySiteIdentifier = $_.VPGRecoverySiteIdentifier

$VPGRpoInSeconds = $_.VPGRpoInSeconds

$VPGServiceProfileIdentifier = $_.VPGServiceProfileIdentifier

$VPGTestIntervalInMinutes = $_.VPGTestIntervalInMinutes

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

Page 61: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

<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 = @"

</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

Page 62: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$VMJournalDatastoreIdentifier = $_.VMJournalDatastoreIdentifier

$VMJournalHardLimitInMB = $_.VMJournalHardLimitInMB

$VMJournalHardLimitInPercent = $_.VMJournalHardLimitInPercent

$VMDatastoreClusterName = $_.VMDatastoreClusterName

$VMDatastoreClusterIdentifier = $_.VMDatastoreClusterIdentifier

$VMDatastoreName = $_.VMDatastoreName

$VMDatastoreIdentifier = $_.VMDatastoreIdentifier

$VMFolderName = $_.VMFolderName

$VMFolderIdentifier = $_.VMFolderIdentifier

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

Page 63: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

<th class="tg-foxd">VolumeDatastoreClusterName</th>

<th class="tg-foxd">VolumeDatastoreName</th>

</tr>

"@

# Building HTML table

$VMVolumeArrayHTMLTable = $null

foreach ($_ in $Array)

{

# Setting values

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

Page 64: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

Page 65: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

<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

}

# 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>

Page 66: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

<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

Page 67: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$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 68: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

5

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

# 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 69: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

# 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 70: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 71: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 72: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

# URL to create VPG settings

Page 73: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 74: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 75: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

""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 76: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

}

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 77: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 78: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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}

# URL to create VPG settings

$CreateVPGURL = $BaseURL+"vpgSettings"

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

Page 79: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 80: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

},

""Scripting"": {

Page 81: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

""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 82: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 83: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 84: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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 ################################################

# Importing VMware PowerCLI snap-in if required, uncomment line 76 ################################################ function LoadSnapin{

param($PSSnapinName) if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){ Add-pssnapin -name $PSSnapinName

} } # Loading snapins and modules

Page 85: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# LoadSnapin -PSSnapinName "VMware.VimAutomation.Core" ################################################ # Connecting to vCenter - if required uncomment line 80

################################################ # 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} # 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

Page 86: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

Page 87: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} }, ""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 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

Page 88: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

if ($BootGroupName -eq "Group1") { $BootGroupIdentifier = "00000000-0000-0000-0000-000000000001"

} else {

$BootGroupIdentifier = "00000000-0000-0000-0000-000000000002" } #####################

# Building JSON start ##################### $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) {

Page 89: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 = "], }" # 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 90: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

6

Page 91: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# Configure the variables below using the Production vCenter & ZVM

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

$LogDataDir = "C:\ZVRAutomatedVMProtection\"

$ProfileCSV = "C:\Users\JoshuaJamie\OneDrive\Zerto\Scripts\#2016Scripts\AutomatedVMProtection-Folders\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

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

# Importing PowerCLI snap-in required for successful authentication with Zerto API

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

function LoadSnapin{

param($PSSnapinName)

if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){

Add-pssnapin -name $PSSnapinName

Page 92: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

}

}

# Loading snapins and modules

LoadSnapin -PSSnapinName "VMware.VimAutomation.Core"

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

# 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}

# 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

Page 93: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

$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

Page 94: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

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

Page 95: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

},

{

""BootDelayInSeconds"": ""$BootGroupDelay"",

""BootGroupIdentifier"": ""00000000-0000-0000-0000-000000000002"",

""Name"": ""Web""

}

]

},

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

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

}

Page 96: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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

{

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

}

Page 97: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# End of per VPG actions above

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

# Disconnecting from vCenter

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

disconnect-viserver $vCenterServer -Force -Confirm:$false

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

# Stopping logging

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

stop-transcript

Page 98: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016
Page 99: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# Configure the variables below using the Production vCenter & ZVM

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

$LogDataDir = "C:\ZVRAutomatedVMProtection\"

$ProfileCSV = "C:\Users\JoshuaJamie\OneDrive\Zerto\Scripts\#2016Scripts\AutomatedVMProtection-Folders\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

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

# Importing PowerCLI snap-in required for successful authentication with Zerto API

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

function LoadSnapin{

param($PSSnapinName)

if (!(Get-PSSnapin | where {$_.Name -eq $PSSnapinName})){

Add-pssnapin -name $PSSnapinName

}

}

# Loading snapins and modules

LoadSnapin -PSSnapinName "VMware.VimAutomation.Core"

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

# 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")

Page 100: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$zertosessionHeader = @{"x-zerto-session"=$xZertoSession}

# 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"}

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

{

Page 101: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$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

Page 102: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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"":{

Page 103: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

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

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

}

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

Page 104: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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

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

stop-transcript

Page 106: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

}

################################################ # 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 = @{"x-zerto-session"=$xZertoSession}

################################################ # Getting VPG & VM lists to get identifiers of VPG and VMs to add ################################################

# URL to create VPG settings $CreateVPGURL = $BaseURL+"vpgSettings" # VPG URL and List

Page 107: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeXML # Build List of VMs

$vmListApiUrl = $baseURL+"vms" $vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -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 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 -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 -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 -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 -TimeoutSec 100

$VPGCreationStatus = "PASSED" } Catch {

$VPGCreationStatus = "FAILED" Write-Host $_.Exception.ToString() $error[0] | Format-List -Force

}

Page 108: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

7

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

# 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} ################################################ # Building array of VPGs

################################################ $vpgListApiUrl = $baseURL+"vpgs" $vpgList = Invoke-RestMethod -Uri $vpgListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -ContentType $TypeJSON

$VPGs = $vpgList | select VpgName,SourceSite,TargetSite,VmsCount,VpgIdentifier

Page 109: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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

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

# 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

################################################ $VPGsToConfigure = Import-Csv $CSVImportFile ################################################

# Setting certificate exception to prevent authentication issues to the ZVM

Page 110: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

################################################ 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} # 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 = "{

""VpgIdentifier"":""$VPGidentifier"" }" # Posting edit request

Page 111: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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 112: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# 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 = @{"x-zerto-session"=$xZertoSession} ################################################ # Creating Arrays for populating ZVM info from the API

################################################ $VPGArray = @() $VMArray = @()

$VMVolumeArray = @() $VMNICArray = @()

Page 113: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

################################################ # 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 -ContentType $TypeXML # Build List of VMs

$vmListApiUrl = $baseURL+"vms" $vmList = Invoke-RestMethod -Uri $vmListApiUrl -TimeoutSec 100 -Headers $zertoSessionHeader -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 $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 -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 -ContentType $TypeJSON # Getting network info

$VINetworksURL = $baseURL+"virtualizationsites/$VPGRecoverySiteIdentifier/networks" $VINetworksCMD = Invoke-RestMethod -Uri $VINetworksURL -TimeoutSec 100 -Headers $zertoSessionHeader -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 -ContentType $TypeJSON

Page 114: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

# 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 -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 -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 115: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 -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 116: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

################################################ # 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 117: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

$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 118: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

##################### 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 119: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

}, ""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 120: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

8

Page 121: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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

# Configure the variables below ################################################ # VPGs to clone

$OffsiteCloneVPGsCSV = "C:\Users\JoshuaJamie\OneDrive\Zerto\#Scripts\#2016Scripts\OffsiteCloneScheduler\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 122: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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} # 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 123: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} $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, $vmList, $OffsiteCloneVPGs, $vCenterServer, $vCenterUser, $vCenterPassword, $ZVMIP, $ZVMPSPort, $ZMVPSUser, $ZVMPSPasswd, $OffsiteCloneVPGLog, $OffsiteCloneVMLog, $OffsiteCloneLogDataDir, $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"

Will display events from vm1 which will be regarding creation events,

Page 124: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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 $em.QueryEvents($EventFilterSpec)

Page 125: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} 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 Creator : home\greg

Page 126: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

In case when you privided vm that 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 { $ReportedVM = $null

Page 127: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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" LoadSnapin -PSSnapinName "VMware.VimAutomation.Core"

################################################ # Connecting to vCenter - required for successful authentication with Zerto API ################################################

Page 128: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

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 129: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

{ $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 130: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} 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 131: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

} # 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 132: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

$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 133: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

<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 134: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

################################################ # 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, $OffsiteCloneLogDataDir, $RemoveVMsFromInventory, $vCenterTimeZoneMatch, $EmailTo, $EmailFrom, $SMTPServer, $SMTPPort, $SMTPUser, $SMTPPassword, $SMTPSSLEnabled

# End of for each VRA below

} # End of for each VRA above

Page 135: Automating Zerto Virtual Replication with PowerShells3.amazonaws.com/zertodownload_docs/4.0U6/White Paper - Autom… · with PowerShell & REST APIs Whitepaper VERSION 2.0 AUGUST 2016

9

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

} Catch { Write-Host $_.Exception.ToString() $error[0] | Format-List -Force }