• This topic has 5 replies, 4 voices, and was last updated March 7, 2018 by Marc V.

Powershell Cmdlet to Create New VPG

  • I don’t see such a cmdlet referenced in the PowerShell Cmdlets Guide. Is it possible to automate the creation of new VPG’s? If not now, are there plans for a future release?


    Not sure about the Powershell cmdlets but I believe in future things are moving more towards the RESTful API and this can already be achieved through that.

    There is an example script included in: –


    Have not tried it myself but assume it all works OK – please let me know how you get on,



    I am busy getting the examples from the PDF file (referenced by Lee) to work, with mixed results. I found that I had to do quite a bit of tweaking in order to get somewhere. I have example1 working. I am now busy with example2.

    I have attached the error message I get. Because of the tweaking of the code, I have pasted below what my “example2.ps1″ script currently looks like. (ip addresses, passwords, etc have been removed to protect the innocent). The problem seems to happen at row 31/32 of my script.

    Any help would be greatly appreciated.


    <pre class=”EnlighterJSRAW” data-enlighter-language=”null”>#Parameters Section
    $strZVMIP = “<ip address>”
    $strZVMPort = “9669”
    $strZVMUser = “<username>”
    $strZVMPw = “<password>”
    $sourceSiteName = “My Source Site”
    $targetSiteName = “My Target Site”
    $targetDataStoreName = “Target Datastore Name”
    $vpgName = “TestVPG”

    #$unProtectedVMsCSVFile = “name of the file that has the names of the VMs to add to the VPG. The file must not have headers, and the VM names must be separated with commas, without spaces between the names. For example, the first row in the file would look like this: vm1,vm2,vm3}”
    $unProtectedVMsCSVFile = “TestVPGVMs.txt”

    $BASEURL = “https://” + $strZVMIP + “:”+$strZVMPort+”/v1/” #base URL for all APIs

    ##Function Definitions
    #Get a site identifier by invoking Zerto APIs, given a Zerto API session and a site name:
    function getSiteIdentifierByName ($sessionHeader, $siteName){
    $url = $BASEURL + “virtualizationsites”
    $response = Invoke-RestMethod -Uri $url -Headers $zertoSessionHeader -ContentType “application/xml”

    ForEach ($site in $response.ArrayOfVirtualizationSiteApi.VirtualizationSiteApi) {
    if ($site.VirtualizationSiteName -eq $siteName){
    return $site.SiteIdentifier

    #Get a storage identifier by invoking Zerto APIs, given a Zerto Virtual Replication API session and a storage name:
    function getDatastoreIdentifierByName ($sessionHeader, $siteIdentfier, $datastoreName){
    $url = $BASEURL + “virtualizationsites/” + $siteIdentfier + “/datastores”
    $response = Invoke-RestMethod -Uri $url -Headers $zertoSessionHeader -ContentType “application/xml”

    ForEach ($datastore in $response.ArrayOfDatastoreNativeApi.DatastoreNativeApi) {
    if ($datastore.DatastoreName -eq $datastoreName){
    return $datastore.DatastoreIdentifier

    #Get unprotected VM identifiers by invoking Zerto APIs, given a Zerto API session, a site identifier, and a list of VMs to add to the VPG:
    function getUnprotectedVMsIdentifiers($sessionHeader, $siteIdentfier, $VMNames){
    $url = $BASEURL + “virtualizationsites/”+$siteIdentfier + “/vms”
    $unprotectedVMsIdentifiers = @()
    $response = Invoke-RestMethod -Uri $url -Headers $zertoSessionHeader -ContentType “application/xml”

    ForEach ($vm in $response.ArrayOfVmNativeApi.VmNativeApi) {
    if ($VMNames.IndexOf($vm.VmName) -gt -1){
    return $unprotectedVMsIdentifiers

    #Authenticate with Zerto APIs: create a Zerto API session and return it, to be used in other APIs
    #function getZertoXSession (){
    function getZertoXSession ($userName, $password){
    $baseURL = “https://” + $strZVMIP + “:”+$strZVMPort
    $xZertoSessionURI = $baseURL +”/v1/session/add”
    $authInfo = (“{0}:{1}” -f $userName,$password)
    $authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
    $authInfo = [System.Convert]::ToBase64String($authInfo)
    $headers = @{Authorization=(“Basic {0}” -f $authInfo)}
    $body = ‘{“AuthenticationMethod”: “1”}’
    $contentType = “application/json”
    $xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURI -Headers $headers -Method POST -Body $body -ContentType $contentType
    #$xZertoSessionResponse = Invoke-WebRequest -Uri $xZertoSessionURI -Headers $headers -Body $body -Method POST
    return $xZertoSessionResponse.headers.get_item(“x-zerto-session”)

    #Build VM elements to be added to the VPGs API, based on a list of VM identifiers
    function buildVMsElement ($VMs) {
    $response = “<VmsIdentifiers>”

    ForEach ($vm in $VMs) {
    $response+=”<string xmlns=”+'”http://schemas.microsoft.com/2003/10/Serialization/Arrays”‘+”>”+$vm+”</string>”
    $response += “</VmsIdentifiers>”
    return $response

    #Script starts here:
    #Next line to ignore certificate errors
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    $xZertoSession = getZertoXSession $strZVMUser $strZVMPw

    $zertoSessionHeader = @{“x-zerto-session”=$xZertoSession}

    $sourceSiteIdentifier = getSiteIdentifierByName $zertoSessionHeader $sourceSiteName

    $targetSiteIdentifier = getSiteIdentifierByName $zertoSessionHeader $targetSiteName

    $dataStoreIdentifier = getDatastoreIdentifierByName $zertoSessionHeader $targetSiteIdentifier $targetDataStoreName

    $unprotectedVMNames = Get-Content $unProtectedVMsCSVFile | %{$_.Split(“,”)}

    $vmsIdentifiers = getUnprotectedVMsIdentifiers $zertoSessionHeader $sourceSiteIdentifier $unprotectedVMNames

    $vmsIdentifiersElement = buildVMsElement $vmsIdentifiers

    #Create the URL and body of the VPGs request:
    $createVPGUrl = $BASEURL+”vpgs”
    $vpgsRequestBody = “<VpgCreateDataApi xmlns=”+'”http://schemas.zerto.com/zvm/api”‘+”>”+”<DatastoreIdentifier>”+$dataStoreIdentifier +”</DatastoreIdentifier><SourceSiteIdentifier>”+$sourceSiteIdentifier+”</SourceSiteIdentifier><TargetSiteIdentifier>”+$targetSiteIdentifier+”</TargetSiteIdentifier>”+$vmsIdentifiersElement+”<VpgName>”+$vpgName+”</VpgName></VpgCreateDataApi>”

    #Invoke the Zerto API:
    Invoke-RestMethod -Uri $createVPGUrl -Headers $zertoSessionHeader -Body $vpgsRequestBody -ContentType “application/xml” -method POST
    ##End of script

    Mark –

    I created a ZertoModule that wraps the REST API that that helps simplify your code.

    For example, we create VPG’s like this:

    Set-Item ENV:ZertoServer "il1zerto.test.com"
    Set-Item ENV:ZertoPort "9669"
    Set-ZertoAuthToken -ZertoUser test\Account

    Add-ZertoVPG -Priority Low `
    -VPGName 'Application1' `
    -RecoverySiteName 'Zerto-IL1' `
    -ClusterName 'Cluster01' `
    -FailoverNetwork 'Network01' `
    -TestNetwork 'Network01' `
    -DatastoreName 'DataStore01' `
    -JournalDatastoreName 'DataStore01' `
    -vCenterFolder 'ZertoRecoveryFolder' `
    -VmNamess @('Server1','Server2')



    Thanks for your reply. I will have to try that out for my next Zerto implementation.



    I realise it has been more than a year, but I am working on a sizable Zerto implementation and wanted to try out your Powershell solution to create VPGs. I installed the module, but got stuck with this:

    Set-ZertoAuthToken -ZertoUser test\Account

    When running the above command, a dialog box prompts me for the account’s password. After I enter the password (either correctly or incorrectly), the following error shows up:

    Missing Zerto Authentication Token
    At C:\Program Files\WindowsPowerShell\Modules\ZertoModule\1.0.8\ZertoModule.psm1:2582 char:13
    + throw "Missing Zerto Authentication Token"
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (Missing Zerto Authentication Token:String) [], RuntimeException
    + FullyQualifiedErrorId : Missing Zerto Authentication Token

    Any ideas what this could be? I am using Zerto 6.0 P2.


You must be logged in to create new topics. Click here to login