ZertoApiWrapper.psm1

#------------------------------------------------------------#
#---------------------Private Functions----------------------#
#------------------------------------------------------------#

function Get-Map {
    [CmdletBinding()]
    [OutputType([Hashtable])]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [PSCustomObject]$inputObject,
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$key,
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$value
    )

    $returnMap = @{ }
    foreach ($item in $inputObject) {
        $returnMap[$item.$key] = $item.$value
    }
    $returnMap
}


function Get-ZertoApiFilter {
    [cmdletbinding()]
    [Outputtype([String])]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Hashtable that contains filter keys and values"
        )]
        [ValidateNotNullOrEmpty()]
        [hashtable]$filterTable
    )
    # Define the start of the return string
    [string]$returnString = "?"
    $commonParameters = @(
        "Debug"
        "ErrorAction"
        "ErrorVariable"
        "InformationAction"
        "InformationVariable"
        "OutVariable"
        "OutBuffer"
        "PipelineVariable"
        "Verbose"
        "WarningAction"
        "WarningVariable"
        "WhatIf"
        "Confirm"
    )
    #Foreach item in the table, process each item
    foreach ( $key in $filterTable.Keys ) {
        # If the key is not a common parameter, process it.
        if ($key -notin $commonParameters) {
            #If this is not the first item added to the string, add the ampersand and filter
            if ($returnString.Length -gt 1) {
                $returnString = "{0}&{1}={2}" -f $returnString, $key, $filterTable[$key]
            } else {
                #If it is the first item, just add the first item
                $returnString = "{0}{1}={2}" -f $returnString, $key, $filterTable[$key]
            }
        }
    }
    # Return the built query String
    return $returnString
}


#------------------------------------------------------------#
#----------------------Public Functions----------------------#
#------------------------------------------------------------#

<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Add-ZertoPeerSite {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [parameter(
            Mandatory,
            HelpMessage = "Target Hostname or IP address to pair the localsite to."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$targetHost,
        [Parameter(
            HelpMessage = "Target communication port. Default is 9081"
        )]
        [ValidateRange(1024, 65535)]
        [int]$targetPort = 9081,
        [Parameter(
            HelpMessage = "The generated token from the destination site. Note: This is only supported when both sites support pairing authentication. This was implemented to support ZVR 7.5 and later."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$token
    )

    begin {
    }

    process {
        $baseUri = "peersites"
        if ($PSBoundParameters.Keys.Contains("token")) {
            $body = @{ "HostName" = $targetHost; "Port" = $targetPort; "Token" = $token }
        } else {
            $body = @{ "HostName" = $targetHost; "Port" = $targetPort }
        }
        if ($PSCmdlet.ShouldProcess("Pairing with Site $targetHost")) {
            Invoke-ZertoRestRequest -uri $baseUri -body $($body | ConvertTo-Json) -method "POST"
        }
    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Add-ZertoVpgVm {
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "VpgName")]
    param (
        [Parameter(
            Mandatory,
            HelpMessage = "Vpg Settings Identifier",
            ValueFromPipeline,
            ValueFromPipelineByPropertyName,
            ValueFromRemainingArguments,
            ParameterSetName = "VpgSettingsIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("sid", "settingsIdentifier", "vpgSettingsId")]
        [String]$vpgSettingsIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Target VPG Name to Add the VM",
            ParameterSetName = "VpgName"
        )]
        [ValidateNotNullOrEmpty()]
        [String]$VpgName,
        [Parameter(
            Mandatory,
            HelpMessage = "Name of VM(s) to add to the VPG"
        )]
        [ValidateNotNullOrEmpty()]
        [String[]]$Vm
    )

    begin {

    }

    process {
        if ($PSCmdlet.ParameterSetName -eq "VpgName") {
            $VpgIdentifier = Get-ZertoVpg -name $VpgName | Select-Object -ExpandProperty VpgIdentifier
            if (-not $VpgIdentifier) {
                Write-Error "Unable to find Vpg with name $VpgName. Please check your parameters and try again." -ErrorAction Stop
            } else {
                $vpgSettingsIdentifier = New-ZertoVpgSettingsIdentifier -vpgIdentifier $VpgIdentifier
            }
        }
        $baseUrl = "vpgsettings/{0}/vms" -f $vpgSettingsIdentifier
        $baseSettings = Get-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsIdentifier
        if ($PSCmdlet.ParameterSetName -eq "VpgSettingsIdentifier") {
            $VpgName = $baseSettings.Basic.Name
        }
        $unprotectedVms = Get-ZertoUnprotectedVm
        $protectedVms = Get-ZertoProtectedVm
        $vmMap = Get-Map -inputObject $unprotectedVms -key VmName -value VmIdentifier
        $vmMap = $vmMap + (Get-Map -inputObject $protectedVms -key VmName -value VmIdentifier)
        # Create array of VM identifiers
        $vmIdentifiers = foreach ($machine in ($Vm | Select-Object -Unique)) {
            if ($vmMap[$machine] -notin $baseSettings.Vms.vmIdentifier ) {
                # If the VM is unprotected, get the identifier
                $vmIdentifier = $unprotectedVms | Where-Object { $_.vmName -like $machine } | Select-Object -ExpandProperty vmIdentifier
                # If the VM is not unprotected, check the protected VMs
                if ( -not $vmIdentifier) {
                    # Get all identifiers to test if the VM is eligible to be a member of an additional VPG
                    $results = $protectedVms | Where-Object { $_.VmName -like $machine } | Select-Object -ExpandProperty vmIdentifier
                    $recoverySiteIdentifiers = $protectedVms | Where-Object { $_.VmName -like $machine } | Select-Object -ExpandProperty RecoverySite | Select-Object -ExpandProperty identifier
                    # If VM is currently a member of 3 VPGs, skip it. If it cannot be found, skip it. Otherwise, set the identifier
                    if ($baseSettings.basic.RecoverySiteIdentifier -in $recoverySiteIdentifiers) {
                        Write-Warning "$machine is already replicating to target site. It cannot be added to an additional VPG replicating to that site. Please check your configurations and try again. Skipping $machine"
                        continue
                    } elseif ($results.count -eq 3) {
                        Write-Warning "$machine is already a part of 3 VPGs and cannot be part of an additional VPG. Skipping $machine"
                        continue
                    } elseif ($results.count -eq 0) {
                        Write-Warning "$machine not found. Skipping $machine"
                        continue
                    } else {
                        $vmIdentifier = $results | Select-Object -First 1
                    }
                }
                # Create a custom object to store the information to easily convert to JSON. Return to vmIdentifiers array.
                $vmIdentifier
            } else {
                Write-Warning "$machine is already a member of this VPG Settings object. It will not be added again. Skipping $machine"
                continue
            }
        }
        if ($vmIdentifiers.Count -gt 0 -and $PSCmdlet.ShouldProcess($VmIdentifiers, "Adding VM(s): $Vm to Vpg $VpgName")) {
            foreach ($id in $VmIdentifiers) {
                # Build the Body
                $Body = @{VmIdentifier = $id }
                # Submit the request. Out to Null to prevent line returns while running.
                $null = Invoke-ZertoRestRequest -uri $baseUrl -method POST -body ($Body | ConvertTo-Json -Depth 10)
            }

            $vpgSettingsIdentifier
        } else {
            Write-Warning "No VMs found to add. Please check your parameters and try again."
            if ($PSCmdlet.ParameterSetName -eq "VpgName") {
                Remove-ZertoVpgSettingsIdentifier -vpgSettingsIdentifier $vpgSettingsIdentifier
            }
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Checkpoint-ZertoVpg {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Name of the VPG to tag.",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            Mandatory,
            HelpMessage = "Text to tag the checkpoint with."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$checkpointName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $vpgIdentifier = $(get-zertovpg -name $name).vpgIdentifier
            if ($vpgIdentifier) {
                $uri = "{0}/{1}/Checkpoints" -f $baseUri, $vpgIdentifier
                $body = @{"checkpointName" = $checkpointName }
                Invoke-ZertoRestRequest -uri $uri -body $($body | ConvertTo-Json) -method "POST"
            } else {
                Write-Output "Cannot find VPG named $name. Please check the name and try again."
            }
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Connect-ZertoAnalytics {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "PSCredential Object containing username and password authorized for the Zerto Analytics site",
            Position = 0
        )]
        [System.Management.Automation.PSCredential]$credential
    )

    $uri = "auth/token"
    Set-Variable -Name zaHeaders -Scope Script -Value @{"Accept" = "application/json" }
    Set-Variable -Name zaLastActionTime -Scope Script -Value $(Get-date).Ticks
    $body = @{"username" = $credential.UserName; "password" = $credential.GetNetworkCredential().password }
    $result = Invoke-ZARestRequest -Uri $uri -body $($body | ConvertTo-Json) -Method POST
    $Script:zaHeaders["Authorization"] = "Bearer $($result.Token)"
    $Script:zaHeaders
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Connect-ZertoServer {
    [cmdletbinding()]
    [OutputType([hashtable])]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "IP address or FQDN of your Zerto Management Server",
            Position = 0
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("server", "zvm")]
        [string]$zertoServer,
        [Parameter(
            Mandatory,
            HelpMessage = "Valid credentials to connect to the Zerto Management Server",
            Position = 1
        )]
        [System.Management.Automation.PSCredential]$credential,
        [Parameter(
            HelpMessage = "Zerto Virtual Manager management port. Default value is 9669."
        )]
        [ValidateNotNullOrEmpty()]
        [ValidateRange(1024, 65535)]
        [Alias("port")]
        [string]$zertoPort = "9669",
        [Parameter(
            HelpMessage = "Use this switch to indicate that you would like the module to take care of auto re-authorization and reconnection to the ZVM should the token expire. This option will cache your PSCredential object to be reused"
        )]
        [switch]$AutoReconnect,
        [Parameter(
            HelpMessage = "Use this switch to return the headers to a specified variable or to the default output."
        )]
        [switch]$returnHeaders

    )

    begin {
        $body = '{"AuthenticationMethod": "1"}'
        $uri = "session/add"
        # Set Script Scope Variables for Use in all functions in the module; Server and Port Information
        Set-Variable -Name zvmServer -Scope Script -Value $zertoServer
        Set-Variable -Name zvmPort -Scope Script -Value $zertoPort
        # Set zvmLastAction Variable to keep track when the API token expires
        Set-Variable -Name zvmLastAction -Scope Script -Value $(Get-Date).Ticks
        # Set / Clear the zvmHeaders to clear any existing token
        Set-Variable -Name zvmHeaders -Scope Script -Value @{
            "Accept"             = "application/json"
            "zerto-triggered-by" = "PowershellWes"
        }
        Set-Variable -Name Reconnect -Scope Script -Value $AutoReconnect.IsPresent
        if ($Script:Reconnect) {
            Set-Variable -Name CachedCredential -Scope Script -Value $credential
        }
    }

    process {
        # Send authorization request to the function and send back the results including headers
        $results = Invoke-ZertoRestRequest -uri $uri -credential $credential -returnHeaders -body $body -method POST -ErrorAction Stop
    }

    end {
        # Build Headers Hashtable with Authorization Token
        $Script:zvmHeaders['x-zerto-session'] = $results.Headers['x-zerto-session'][0].ToString()
        
        # Have the option to return the headers to a variable
        if ($returnHeaders) {
            return $Script:zvmHeaders
        }
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Copy-ZertoVpg {
    [CmdletBinding(SupportsShouldProcess)]
    param (
        # VPG Name to Clone
        [Parameter(Mandatory,
            HelpMessage = "Name of the VPG to clone")]
        [ValidateNotNullOrEmpty()]
        [String]$SourceVpgName,
        # New VPG Name
        [Parameter(Mandatory,
            HelpMessage = "Name to assign the newly created VPG")]
        [ValidateNotNullOrEmpty()]
        [String]$NewVpgName, # Name of VMs to add to the VPG
        [Parameter(Mandatory,
            HelpMessage = "Name(s) of the Virtual Machine(s) to add to the VPG")]
        [ValidateNotNullOrEmpty()]
        [String[]]$VMs
    )

    begin {

    }

    process {
        $VpgIdToCopy = @{ VpgIdentifier = (Get-ZertoVpg -vpgName $SourceVpgName).vpgIdentifier }
        if ( $null -eq $VpgIdToCopy.VpgIdentifier ) {
            Throw "Unable to find a VPG with the name: $SourceVpgName. Please check the name and try again."
        }
        $BaseUri = "vpgSettings/copyVpgSettings"
        $VmsMap = Get-Map -InputObject (Get-ZertoUnprotectedVm) -Key 'VmName' -Value 'VmIdentifier'
        $VmsMap += Get-Map -InputObject (Get-ZertoProtectedVm) -Key 'VmName' -Value 'VmIdentifier'
        $VMsToAdd = foreach ($VM in $VMs) {
            if ($VmsMap.Keys -contains $VM) {
                [PSCustomObject]@{
                    VmIdentifier = $VmsMap[$VM]
                }
            } else {
                Write-Warning -Message "Unable to find VM with Name $VM. Skipping."
            }
        }
        if ($PSCmdlet.ShouldProcess("$VMsToAdd", "Copying $SourceVpgName to $NewVpgName with Settings")) {
            $NewVpgId = Invoke-ZertoRestRequest -Uri $BaseUri -Body ($VpgIdToCopy | ConvertTo-Json) -Method "POST"
            $Uri = "{0}/{1}/vms" -f "vpgSettings", $NewVpgId
            foreach ($VM in $VMsToAdd) {
                $null = Invoke-ZertoRestRequest -Uri $Uri -Body ($VM | ConvertTo-Json) -Method "POST" -ErrorAction Stop
            }
            $Uri = "vpgSettings/{0}" -f $NewVpgId
            $CurrentSettings = Invoke-ZertoRestRequest -Uri $Uri
            $CurrentSettings.Basic.Name = $NewVpgName
            $Null = Invoke-ZertoRestRequest -Uri $Uri -Method "Put" -Body $($CurrentSettings | ConvertTo-Json -Depth 20)
            Save-ZertoVpgSetting -vpgSettingsIdentifier $NewVpgId
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Disconnect-ZertoServer {
    [cmdletbinding()]
    param()
    $uri = "session"

    # Delete API Authorization
    $null = Invoke-ZertoRestRequest -uri $uri -method DELETE

    # Remove all variables used
    Remove-Variable -Name zvmServer -Scope Script
    Remove-Variable -Name zvmPort -Scope Script
    Remove-Variable -Name zvmLastAction -Scope Script
    Remove-Variable -Name zvmHeaders -Scope Script
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Edit-ZertoVra {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Identifier of the VRA to be updated."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vraId")]
        [string]$vraIdentifier,
        [Parameter(
            HelpMessage = "Bandwidth group to assign to the VRA. If unspecified will not modify current assignment"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$groupName,
        [Parameter(
            ParameterSetName = "StaticIp",
            HelpMessage = "Static IP address to assign to the VRA."
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$vraIpAddress,
        [Parameter(
            ParameterSetName = "StaticIp",
            HelpMessage = "Default gateway to assign to the VRA"
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$defaultGateway,
        [Parameter(
            ParameterSetName = "StaticIp",
            HelpMessage = "Subnetmask to be assigned to the VRA"
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$subnetMask,
        [Parameter(
            HelpMessage = "Updated ESXi host root password."
        )]
        [ValidateNotNullOrEmpty()]
        [securestring]$HostRootPassword

    )

    begin {
        $baseUri = "vras/{0}" -f $vraIdentifier
        # Get the current VRA information for use if an updated parameter is not supplied
        $vra = Get-ZertoVra -vraIdentifier $vraIdentifier
        if ( -not $vra ) {
            Throw "VRA with Identifier: $vraIdentifier could not be found. Please check the ID and try again."
        }
    }

    process {
        # Create ordered hashtables to be converted later to JSON.
        $vraUpdate = [ordered]@{ }
        $vraNetwork = [ordered]@{ }
        # If a new group name is specified, update.
        if ( $PSBoundParameters.ContainsKey('GroupName')) {
            $vraUpdate['GroupName'] = $groupName
        } else {
            $vraUpdate['GroupName'] = $vra.VraGroup
        }
        # If ParameterSetName StaticIp is used, update the parameters submitted
        if ( $PSCmdlet.ParameterSetName -eq 'StaticIp' -or $vra.VraNetworkDataApi.VraIPConfigurationTypeApi -eq "Static" ) {
            if ( $PSBoundParameters.ContainsKey('defaultGateway') ) {
                $vraNetwork['DefaultGateway'] = $defaultGateway
            } else {
                $vraNetwork['DefaultGateway'] = $vra.VraNetworkDataApi.DefaultGateway
            }
            if ( $PSBoundParameters.ContainsKey('subnetMask') ) {
                $vraNetwork['SubnetMask'] = $subnetMask
            } else {
                $vraNetwork['SubnetMask'] = $vra.VraNetworkDataApi.SubnetMask
            }
            if ( $PSBoundParameters.ContainsKey('vraIpAddress') ) {
                $vraNetwork['VraIpAddress'] = $vraIpAddress
            } else {
                $vraNetwork['VraIpAddress'] = $vra.VraNetworkDataApi.VraIpAddress
            }
            $vraNetwork['VraIPConfigurationTypeApi'] = "Static"
            # Add network information to update object.
            $vraUpdate['VraNetworkDataApi'] = $vraNetwork
        } else {
            $vraNetwork['VraIPConfigurationTypeApi'] = "Dhcp"
            $vraUpdate['VraNetworkDataApi'] = $vraNetwork
        }
        if ($PSBoundParameters.ContainsKey('HostRootPassword')) {
            $HostRootCredential = [pscredential]::New('root', $HostRootPassword)
            $vraUpdate['UsePublicKeyInsteadOfCredentials'] = $false
            $vraUpdate['HostRootPassword'] = $HostRootCredential.GetNetworkCredential().Password
        }

        # -WhatIf processing and submit!
        if ($PSCmdlet.ShouldProcess( $vra.vraName )) {
            Invoke-ZertoRestRequest -uri $baseUri -body $($vraUpdate | ConvertTo-Json) -method "PUT"
        }
    }

    end {
        # Nothing to Do
    }
}
#TODO: Refactor


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Export-ZertoVmNicSetting {
    [CmdletBinding()]
    param (
        # Vpg(s) to export. If no VPG was named, all data will be exported.
        [Parameter(
            Helpmessage = "VPG(s) to export"
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $VpgName,
        # Output file information
        [Parameter(
            Helpmessage = "File to export the data to. This MUST be a CSV. If a CSV filename is not specified, the file will be forced into a CSV",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]
        $OutputFile
    )

    begin {
    }

    process {
        if (($OutputFile.Split('.')[-1]) -ne 'csv') {
            $OutputFile += '.csv'
        }
        if ( "VpgName" -in $PSBoundParameters.Keys ) {
            $vpgs = Get-ZertoVpg | Where-Object { $_.VpgName -in $VpgName }
            foreach ($group in $VpgName) {
                if ($group -notin $vpgs.VpgName) {
                    Write-Error "$group VPG not found. Skipping." -ErrorAction Continue
                }
            }
        } else {
            $vpgs = Get-ZertoVpg
        }
        $nicSettings = foreach ($group in $vpgs) {
            $protectedVms = Get-ZertoProtectedVm -vpgName ($group.vpgname)
            $vmMap = Get-Map -InputObject $protectedVms -key "vmIdentifier" -value "vmName"
            $settingsId = New-ZertoVpgSettingsIdentifier -vpgIdentifier $group.vpgIdentifier
            $vmSettings = Get-ZertoVpgSetting -vpgSettingsIdentifier $settingsId -vms
            $networks = Get-ZertoVirtualizationSite -siteIdentifier $group.RecoverySite.identifier -networks
            $null = Remove-ZertoVpgSettingsIdentifier -vpgSettingsIdentifier $settingsId
            $networkMap = Get-Map -InputObject $networks -key "NetworkIdentifier" -value "VirtualizationNetworkName"
            foreach ($vm in $vmSettings) {
                if ($vm.nics.count -gt 0) {
                    foreach ($nic in $vm.nics) {
                        $nicInfo = [PSCustomObject]@{
                            VPGName              = $group.VPGName
                            VMName               = $vmMap[$vm.vmIdentifier]
                            NicIdentifier        = $nic.NicIdentifier
                            LiveNetwork          = $networkMap[$nic.failover.Hypervisor.NetworkIdentifier]
                            LiveShouldReplaceMac = $nic.failover.Hypervisor.ShouldReplaceMacAddress
                            LiveIsDHCP           = $nic.failover.Hypervisor.IpConfig.IsDhcp
                            LiveIpAddress        = $nic.failover.Hypervisor.IpConfig.StaticIp
                            LiveIpSubnetMask     = $nic.failover.Hypervisor.IpConfig.SubnetMask
                            LiveIpDefaultGateway = $nic.failover.Hypervisor.IpConfig.Gateway
                            LivePrimaryDns       = $nic.failover.Hypervisor.IpConfig.PrimaryDns
                            LiveSecondayDns      = $nic.failover.Hypervisor.IpConfig.SecondaryDns
                            LiveDnsSuffix        = $nic.failover.Hypervisor.DnsSuffix
                            TestNetwork          = $networkMap[$nic.failoverTest.Hypervisor.NetworkIdentifier]
                            TestShouldReplaceMac = $nic.failoverTest.Hypervisor.ShouldReplaceMacAddress
                            TestIsDHCP           = $nic.failoverTest.Hypervisor.IpConfig.IsDhcp
                            TestIpAddress        = $nic.failoverTest.Hypervisor.IpConfig.StaticIp
                            TestIpSubnetMask     = $nic.failoverTest.Hypervisor.IpConfig.SubnetMask
                            TestIpDefaultGateway = $nic.failoverTest.Hypervisor.IpConfig.Gateway
                            TestPrimaryDns       = $nic.failoverTest.Hypervisor.IpConfig.PrimaryDns
                            TestSecondayDns      = $nic.failoverTest.Hypervisor.IpConfig.SecondaryDns
                            TestDnsSuffix        = $nic.failoverTest.Hypervisor.DnsSuffix
                        }
                        $nicInfo
                    }
                }
            }
        }
        $nicSettings | Export-Csv -Path $OutputFile -NoTypeInformation
    }

    end {
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Export-ZertoVpg {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Location where to dump the resulting JSON files containing the VPG Settings",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("outputFolder")]
        [string]$outputPath,
        [parameter(
            HelpMessage = "Name(s) of the VPG(s) to be exported",
            ParameterSetName = "namedVpgs",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [parameter(
            HelpMessage = "Export all VPGs at this site",
            ParameterSetName = "allVpgs",
            valuefrompipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory
        )]
        [switch]$allVpgs
    )

    begin {
        if ($allVpgs) {
            $vpgName = $(Get-ZertoVpg).vpgName
        }
    }

    process {
        foreach ($name in $vpgName) {
            $vpgSettingsIdentifier = New-ZertoVpgSettingsIdentifier -vpgIdentifier $(Get-ZertoVpg -name $name).vpgIdentifier
            $vpgSettings = Get-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsIdentifier
            $filePath = "{0}\{1}.json" -f $outputPath, $name
            $vpgSettings | Convertto-Json -depth 10 | Out-File -FilePath $filePath
            $null = Remove-ZertoVpgSettingsIdentifier -vpgSettingsIdentifier $vpgSettingsIdentifier
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAAlert {
    [cmdletbinding( DefaultParameterSetName = "zOrg")]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the alert list. If the ZORG identifier is omitted, a list of all the alerts is retrieved.",
            ParameterSetName = "zOrg"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The maximum number of alerts to return.",
            ParameterSetName = "zOrg"
        )]
        [ValidateRange(1, 1000000)]
        [int]$limitTo,
        [Parameter(
            HelpMessage = "The alert Idnetifier",
            ParameterSetName = "alertId",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$alertIdentifier
    )
    $uri = "monitoring/alerts"
    switch ($PSCmdlet.ParameterSetName) {
        zOrg {
            if ( $PSBoundParameters.Keys.Count -gt 0 ) {
                $filterString = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $uri, $filterString
            }
        }

        alertId {
            $uri = "{0}/{1}" -f $uri, $alertIdentifier
        }
    }
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZADatastore {
    [CmdletBinding(DefaultParameterSetName = "AllInfo")]
    param (
        [Parameter(
            HelpMessage = "The site identifier. The site identifier is mandatory. Omit the datastore and datastore cluster identifiers to view site level storage information.",
            Mandatory,
            ParameterSetName = "AllInfo"
        )]
        [Parameter(
            Mandatory,
            ParameterSetName = "cluster"
        )]
        [Parameter(
            Mandatory,
            ParameterSetName = "datastore"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            HelpMessage = "The datastore cluster identifier. Gets a list of datastores in the cluster.",
            ParameterSetName = "cluster",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$clusterIdentifier,
        [Parameter(
            HelpMessage = "The datastore identifer. Gets the datastore info.",
            ParameterSetName = "datastore",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreIdentifier

    )
    $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
    $uri = "monitoring/datastores{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAEvent {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the user's events. If the ZORG identifier is omitted, events is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The event category (events/alertsHistory). Default displays the list of all."
        )]
        [ValidateSet("events", "alertsHistory")]
        [string]$category,
        [Parameter(
            HelpMessage = "The maximum number of events to return."
        )]
        [ValidateRange(1, 1000000)]
        [int]$limitTo,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard ('1970-01-01T00:00:00Z'). Default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard ('1970-01-01T00:00:00Z'). Default is the present time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "monitoring/events"

    if ( $PSBoundParameters.Keys.Count -gt 0 ) {
        $filterString = Get-ZertoApiFilter -filterTable $PSBoundParameters
        $uri = "{0}{1}" -f $uri, $filterString
    }

    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalAverageHistory {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/journal-history-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalAverageSize {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/journal-size-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalBreach {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/journal-breach{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalHistoryStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/stats-journal-history{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSiteAverageHistory {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the recovery site. A site identification is required for at least one site.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/site-journal-history-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSiteAverageSize {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the recovery site. A site identification is required for at least one site.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/site-journal-size-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSiteHistoryStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the recovery site.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/site-journal-history-stats{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSiteHistorySummary {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the recovery site.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/site-journal-history-summary{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSiteSizeStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/site-journal-size-stats{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalStatusProportion {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/journal-statuses-proportions{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalStorageStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/stats-journal-storage{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAJournalSummary {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -filtertable $PSBoundParameters
    $uri = "reports/journal-summary{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZALicense {
    [cmdletbinding()]
    param()
    $uri = "licenses"
    Invoke-ZARestRequest -uri $uri
}

<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAMonitoring {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the user's statistics for a single account. If the ZORG identifier is omitted, statistics related to all sites, for a single account, is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier
    )
    $uri = "monitoring/"
    if ( -not [String]::IsNullorEmpty($zOrgIdentifier) ){
        $filterTable = @{"zOrgIdentifier" = $zOrgIdentifier}
        $filterString = Get-ZertoApiFilter -filterTable $filterTable
        $uri = "{0}{1}" -f $uri, $filterString
    }
    Invoke-ZARestRequest -uri $uri
}

<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkSiteAverageIOPS {
    [CmdletBinding(DefaultParameterSetName = "ProtectedSite")]
    param (
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "ProtectedSite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "RecoverySite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteIdentifier,
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "RecoverySite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "ProtectedSite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the executive summary."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval

    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/sites-network-iops-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkSiteAveragePerformance {
    [CmdletBinding(DefaultParameterSetName = "ProtectedSite")]
    param (
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "ProtectedSite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "RecoverySite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteIdentifier,
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "RecoverySite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "ProtectedSite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the executive summary."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per hour, for up to 15 days’ time frame or per day, for between 15 to 30 days' time frame. Submit value in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/sites-network-performance-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkSiteStat {
    [CmdletBinding(DefaultParameterSetName = "ProtectedSite")]
    param (
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "ProtectedSite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "RecoverySite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteIdentifier,
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "RecoverySite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "ProtectedSite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the executive summary."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/sites-network-stats{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkSiteSummary {
    [CmdletBinding(DefaultParameterSetName = "ProtectedSite")]
    param (
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "ProtectedSite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Protected site identifier. A site identification is required for at least one of the sites.",
            ParameterSetName = "RecoverySite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteIdentifier,
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "RecoverySite",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Recovery site identifier. If the recovery site identifier is omitted, the API will show all outgoing traffic from the protected site to its replicating sites.",
            ParameterSetName = "ProtectedSite"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is ommitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the executive summary."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/sites-network-summary{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkVpgAverageIOPS {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The VPG identifier.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per minute - for up to 6 hours, per hour - for 6 hours to 15 days, or per day - for 15 days up to 30 days. If an interval is not specified, the default is 60 seconds. Submit value in Seconds."
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/vpg-network-iops-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkVpgAveragePerformance {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The VPG identifier.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be per minute - for up to 6 hours, per hour - for 6 hours to 15 days, or per day - for 15 days up to 30 days. If an interval is not specified, the default is 60 seconds. Submit value in Seconds."
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/vpg-network-performance-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkVpgStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The VPG identifier.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/vpg-network-stats{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZANetworkVpgSummary {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The VPG identifier.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default end date is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoAPIFilter -filtertable $PSBoundParameters
    $uri = "reports/vpg-network-summary{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerJournalSizeReport {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Type of target recovery site."
        )]
        [ValidateSet('azure', 'vcenter', 'vcd', 'scvmm', 'aws')]
        [string]$recoveryType,
        [Parameter(
            Mandatory,
            HelpMessage = "Identifiers of the VMs you want to recover at the target recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmIdentifier,
        [Parameter(
            HelpMessage = "The desired journal history in hours. The default is 24 hours. Limited to a 1 hour up to 720 hours, or the equivalent of 30 days"
        )]
        [ValidateRange(1, 720)]
        [Int]$desiredJournalHistory = 24,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "planner/reports/stats/journal-size"
    $body = @{
        siteIdentifier        = $siteIdentifier
        recoveryType          = $recoveryType
        desiredJournalHistory = $desiredJournalHistory
        vms                   = New-Object System.Collections.Generic.List[psobject]
    }
    if ( -not [String]::IsNullOrEmpty($startDate) ) {
        $body['startDate'] = $startDate
    }
    if ( -not [String]::IsNullOrEmpty($endDate) ) {
        $body['endDate'] = $endDate
    }
    foreach ($vmId in $vmIdentifier) {
        $body['vms'].Add(@{'identifier' = $vmId; 'desiredJournalHistory' = $desiredJournalHistory })
    }
    $reportId = Invoke-ZARestRequest -uri $uri -method POST -body ($body | ConvertTo-Json)
    $uri = '{0}?reportId={1}' -f $uri, $reportId.reportId
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerNetworkPerformanceReport {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Type of target recovery site."
        )]
        [ValidateSet('azure', 'vcenter', 'vcd', 'scvmm', 'aws')]
        [string]$recoveryType,
        [Parameter(
            Mandatory,
            HelpMessage = "Identifiers of the VMs you want to recover at the target recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmIdentifier,
        [Parameter(
            HelpMessage = "The desired sample interval in seconds. The default is 3600 seconds (1 Hour). Limited to a 60 second to 86,400 second (24 Hour) interval"
        )]
        [ValidateRange(60, 86400)]
        [Int]$interval = 3600,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "planner/reports/network-performance"
    $body = @{
        siteIdentifier = $siteIdentifier
        recoveryType   = $recoveryType
        interval       = $interval
        vmIdentifiers  = New-Object System.Collections.Generic.List[psobject]
    }
    if ( -not [String]::IsNullOrEmpty($startDate) ) {
        $body['startDate'] = $startDate
    }
    if ( -not [String]::IsNullOrEmpty($endDate) ) {
        $body['endDate'] = $endDate
    }
    foreach ($vmId in $vmIdentifier) {
        $body['vmIdentifiers'].Add($vmId)
    }
    $reportId = Invoke-ZARestRequest -uri $uri -method POST -body ($body | ConvertTo-Json)
    $uri = '{0}?reportId={1}' -f $uri, $reportId.reportId
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerSite {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$siteIdentifier
    )
    $uri = "planner/sites"
    if ( -not [String]::IsNullorEmpty($siteIdentifier) ) {
        $entry = foreach ($id in $siteIdentifier) {
            "{0}/{1}" -f $uri, $id
        }
    } else {
        $entry = $uri
    }
    foreach ($uri in $entry) {
        Invoke-ZARestRequest -uri $uri
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerStatsReport {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Type of target recovery site."
        )]
        [ValidateSet('azure', 'vcenter', 'vcd', 'scvmm', 'aws')]
        [string]$recoveryType,
        [Parameter(
            Mandatory,
            HelpMessage = "Identifiers of the VMs you want to recover at the target recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmIdentifier,
        [Parameter(
            HelpMessage = "The desired journal history in hours. The default is 24 hours. Limited to a 1 hour up to 720 hours, or the equivalent of 30 days"
        )]
        [ValidateRange(1, 720)]
        [Int]$desiredJournalHistory = 24,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "planner/reports/stats"
    $body = @{
        siteIdentifier        = $siteIdentifier
        recoveryType          = $recoveryType
        desiredJournalHistory = $desiredJournalHistory
        vms                   = New-Object System.Collections.Generic.List[psobject]
    }
    if ( -not [String]::IsNullOrEmpty($startDate) ) {
        $body['startDate'] = $startDate
    }
    if ( -not [String]::IsNullOrEmpty($endDate) ) {
        $body['endDate'] = $endDate
    }
    foreach ($vmId in $vmIdentifier) {
        $body['vms'].Add(@{'identifier' = $vmId; 'desiredJournalHistory' = $desiredJournalHistory })
    }
    $reportId = Invoke-ZARestRequest -uri $uri -method POST -body ($body | ConvertTo-Json)
    $uri = '{0}?reportId={1}' -f $uri, $reportId.reportId
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerWanReport {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Type of target recovery site."
        )]
        [ValidateSet('azure', 'vcenter', 'vcd', 'scvmm', 'aws')]
        [string]$recoveryType,
        [Parameter(
            Mandatory,
            HelpMessage = "Identifiers of the VMs you want to recover at the target recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmIdentifier,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "planner/reports/stats/wan"
    $body = @{
        siteIdentifier = $siteIdentifier
        recoveryType   = $recoveryType
        vmIdentifiers  = New-Object System.Collections.Generic.List[psobject]
    }
    if ( -not [String]::IsNullOrEmpty($startDate) ) {
        $body['startDate'] = $startDate
    }
    if ( -not [String]::IsNullOrEmpty($endDate) ) {
        $body['endDate'] = $endDate
    }
    foreach ($vmId in $vmIdentifier) {
        $body['vmIdentifiers'].Add($vmId)
    }
    $reportId = Invoke-ZARestRequest -uri $uri -method POST -body ($body | ConvertTo-Json)
    $uri = '{0}?reportId={1}' -f $uri, $reportId.reportId
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAPlannerZcasReport {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "The site identifier(s) for which to return detailed information."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            Mandatory,
            HelpMessage = "Type of target recovery site."
        )]
        [ValidateSet('azure', 'vcenter', 'vcd', 'scvmm', 'aws')]
        [string]$recoveryType,
        [Parameter(
            Mandatory,
            HelpMessage = "Identifiers of the VMs you want to recover at the target recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmIdentifier,
        [Parameter(
            HelpMessage = "The earliest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is one year ago."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The latest timestamp of an event to return, in RFC 3339 standard. ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $uri = "planner/reports/stats/zcas"
    $body = @{
        siteIdentifier = $siteIdentifier
        recoveryType   = $recoveryType
        vmIdentifiers  = New-Object System.Collections.Generic.List[psobject]
    }
    if ( -not [String]::IsNullOrEmpty($startDate) ) {
        $body['startDate'] = $startDate
    }
    if ( -not [String]::IsNullOrEmpty($endDate) ) {
        $body['endDate'] = $endDate
    }
    foreach ($vmId in $vmIdentifier) {
        $body['vmIdentifiers'].Add($vmId)
    }
    #$body | ConvertTo-Json
    $reportId = Invoke-ZARestRequest -uri $uri -method POST -body ($body | ConvertTo-Json)
    #Start-Sleep 10
    $uri = '{0}?reportId={1}' -f $uri, $reportId.reportId
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAProtectedVm {
    [cmdletbinding(DefaultParameterSetName = "AllVMs")]
    param(
        [Parameter(
            ParameterSetName = "AllVMs",
            HelpMessage = "Use this switch when you want a list of all protected VMs. Please be warned this list can be quite large."
        )]
        [switch]$AllVms,
        [Parameter(
            ParameterSetName = "IndividualVMs",
            Mandatory,
            HelpMessage = "A list of VM identifiers to query"
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$VMIdentifier,
        [Parameter(
            ParameterSetName = "IndividualVMs",
            HelpMessage = "Specify this switch when you would like protected vms' volume information returned"
        )]
        [switch]$Volumes
    )

    Begin {

    }

    Process {
        $BaseUri = "monitoring/protected-vms"
        switch ($PSCmdlet.ParameterSetName) {
            "AllVMs" {
                Invoke-ZARestRequest -uri $BaseUri
            }

            "IndividualVMs" {
                foreach ($identifier in $VMIdentifier) {
                    if ($Volumes.IsPresent) {
                        $Uri = "{0}/{1}/volumes" -f $BaseUri, $identifier
                    } else {
                        $uri = $Uri = "{0}/{1}" -f $BaseUri, $identifier
                    }
                    Invoke-ZARestRequest -uri $Uri
                }
            }
        }
    }

    End {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAProtectedVmReport {
    [cmdletbinding()]
    param(
        [Parameter(
            ParameterSetName = "GenerateReport",
            Mandatory,
            HelpMessage = "A list of VM identifiers to include in the report."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$VMIdentifier
    )

    Begin {

    }

    Process {
        $BaseUri = "monitoring/protected-vms"
        $Body = @{
            vmsIdentifiers = $VMIdentifier
        }
        $reportId = Invoke-ZARestRequest -uri $BaseUri -method POST -body ($Body | ConvertTo-Json)
        Start-Sleep 1
        $Uri = "{0}?reportId={1}" -f $BaseUri, $reportId.reportId
        Invoke-ZARestRequest -uri $Uri
    }

    End {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOAccountAverage {
    [CmdletBinding()]
    param (
        [Parameter(
            Helpmessage = "The ZORG identifier by which to filter the user's average RPO for a single account. If the ZORG identifier is omitted, statistics related to all sites, for a single account, is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/account-rpo-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOAverage {
    [CmdletBinding()]
    param (
        [Parameter(
            Helpmessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            HelpMessage = "The interval selected within the duration of the report. The interval can be 1-minute data granularity for up to 6 hours’ time frame, 1-hour data granularity for 6 hours to 15 days’ time frame or 1-day data granularity for 15 days up to 30 days’ time frame. Value should be submitted in Seconds"
        )]
        [ValidateRange(60, 2678400)]
        [Int32]$interval
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/rpo-average{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOBreach {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/rpo-breach{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOStat {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/stats-rpo{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOStatusProportion {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/rpo-statuses-proportions{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZARPOSummary {
    [CmdletBinding()]
    param (
        [Parameter(
            HelpMessage = "The identifier of the VPG.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier,
        [Parameter(
            HelpMessage = "The starting date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). If only the end date is added, the start date by default will be the end date minus 7 days."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "The end date of the report, in RFC 3339 standard ('1970-01-01T00:00:00Z'). The default is the current time."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "reports/rpo-summary{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZASite {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter site list. If the ZORG identifier is omitted, a list of all sites is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier
    )
    $uri = "monitoring/sites"
    if ( -not [String]::IsNullorEmpty($zOrgIdentifier) ) {
        $filterTable = @{"zOrgIdentifier" = $zOrgIdentifier }
        $filterString = Get-ZertoApiFilter -filterTable $filterTable
        $uri = "{0}{1}" -f $uri, $filterString
    }
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZASitePair {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the site list. If the ZORG identifier is omitted, a list of all sites is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "Start date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the start date is omitted, the default start date is 7 days before the end date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            HelpMessage = "End date in RFC 3339 standard ('1970-01-01T00:00:00Z'). If the end date is omitted, the default endDate is the current date."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate
    )
    $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
    $uri = "reports/sites-list{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZASiteTopology {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter sites topology list. If the ZORG identifier is omitted, information related to all sites topology is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier
    )
    $uri = "monitoring/sites"
    if ( -not [String]::IsNullorEmpty($zOrgIdentifier) ) {
        $filterTable = @{"zOrgIdentifier" = $zOrgIdentifier }
        $filterString = Get-ZertoApiFilter -filterTable $filterTable
        $uri = "{0}{1}&format=topology" -f $uri, $filterString
    } else {
        $uri = "{0}?format=topology" -f $uri
    }
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZATask {
    [cmdletbinding( DefaultParameterSetName = "zOrg")]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the task list. If the ZORG identifier is omitted, a list of all the tasks is retrieved.",
            ParameterSetName = "zOrg"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The maximum number of tasks to return.",
            ParameterSetName = "zOrg"
        )]
        [ValidateRange(1, 1000000)]
        [int]$limitTo,
        [Parameter(
            HelpMessage = "The task Idnetifier",
            ParameterSetName = "taskId",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$taskIdentifier
    )
    $uri = "monitoring/tasks"
    switch ($PSCmdlet.ParameterSetName) {
        zOrg {
            if ( $PSBoundParameters.Keys.Count -gt 0 ) {
                $filterString = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $uri, $filterString
            }
        }

        taskId {
            $uri = "{0}/{1}" -f $uri, $taskIdentifier
        }
    }
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAVolume {
    [CmdletBinding(DefaultParameterSetName = "VpgIdentifier")]
    param (
        [Parameter(
            HelpMessage = "The site identifier. The site identifier is mandatory if vpgIdentifier is not entered.",
            Mandatory,
            ParameterSetName = "SiteAndClusterIdentifier"
        )]
        [Parameter(
            HelpMessage = "The site identifier. The site identifier is mandatory if vpgIdentifier is not entered.",
            Mandatory,
            ParameterSetName = "SiteAndDatastoreIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteIdentifier,
        [Parameter(
            HelpMessage = "The cluster identifier. If a cluster identifier is not entered, you must enter a datastore identifier.",
            Mandatory,
            ParameterSetName = "SiteAndClusterIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$clusterIdentifier,
        [Parameter(
            HelpMessage = "The datastore identifer. If a datastore identifier is not entered, you must enter a cluster identifier.",
            Mandatory,
            ParameterSetName = "SiteAndDatastoreIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreIdentifier,
        [Parameter(
            HelpMessage = "The vpg identifer.",
            Mandatory,
            ParameterSetName = "VpgIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier

    )

    $filter = Get-ZertoApiFilter -FilterTable $PSBoundParameters
    $uri = "monitoring/volumes{0}" -f $filter
    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAVpg {
    [cmdletbinding(DefaultParameterSetName = 'zOrg')]
    param(
        [Parameter(
            HelpMessage = "The ZORG identifier by which to filter the VPG list. If the ZORG identifier is omitted, a list of all VPGs is retrieved.",
            ParameterSetName = 'zOrg'
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zOrgIdentifier,
        [Parameter(
            HelpMessage = "The VPG Identifier",
            ParameterSetName = "vpg",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgIdentifier
    )
    $uri = "monitoring/vpgs"

    switch ($PSCmdlet.ParameterSetName) {
        zOrg {
            if ( -not [String]::IsNullorEmpty($zOrgIdentifier) ) {
                $filterTable = @{"zOrgIdentifier" = $zOrgIdentifier }
                $filterString = Get-ZertoApiFilter -filterTable $filterTable
                $uri = "{0}{1}" -f $uri, $filterString
            }
        }

        vpg {
            $uri = "{0}/$vpgIdentifier" -f $uri
        }
    }

    Invoke-ZARestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZAzOrg {
    [cmdletbinding()]
    param()
    $uri = "monitoring/zorgs"
    Invoke-ZARestRequest -uri $uri
}

<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoAlert {
    [cmdletbinding( defaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "alertId",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true ,
            HelpMessage = "AlertId or array of AlertIds to be queried"
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$alertId,
        [Parameter(
            ParameterSetName = "entities",
            Mandatory,
            HelpMessage = "Switch to return the entities information from the API"
        )]
        [switch]$entities,
        [Parameter(
            ParameterSetName = "helpIdentifiers",
            Mandatory,
            HelpMessage = "Switch to get the Help Identifiers information from the API"
        )]
        [switch]$helpIdentifiers,
        [Parameter(
            ParameterSetName = "levels",
            Mandatory,
            HelpMessage = "Switch to return Alert Levels information from the API"
        )]
        [switch]$levels,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns Alerts after the Start Date. Provide the string in the format of 'yyyy-MM-ddTHH:mm:ss.fff'"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns Alerts before the End Date. Provide the string in the format of 'yyyy-MM-ddTHH:mm:ss.fff'"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified vpgIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId")]
        [string]$vpgIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified siteIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string]$siteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified zorgIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("zorgId")]
        [string]$zorgIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified level"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$level,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified helpIdentifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("helpId")]
        [string]$helpIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Returns alerts for the specified entity"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$entity,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = 'Returns alerts that are dismissed when set to $true an undismissed alerts when set to $false'
        )]
        [bool]$isDismissed
    )

    begin {
        $baseUri = "alerts"
        $returnObject = @()
    }

    process {
        # Select the operation based on the ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {
            # If called without any parameters, return all alerts
            "main" {
                $uri = "{0}" -f $baseUri
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # If called with the alertId ParameterSetName, build an object that contains all alerts for alertIds specified
            "alertId" {
                $returnObject = foreach ( $id in $alertId ) {
                    $uri = "{0}/{1}" -f $baseUri, $alertId
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            # If called with the filter ParameterSetName, get a filter string and get results from API.
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # If any other ParameterSetName is called, build URI based on ParameterSetName and submit
            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoDatastore {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Alias("datastoreId")]
        [Parameter(
            ParameterSetName = "datastoreIdentifier",
            HelpMessage = "datastoreIdentifier or array of datastoreIdentifiers to be queried"
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$datastoreIdentifier
    )

    begin {
        $baseUri = "datastores"
        $returnObject = @()
    }

    process {
        # If command is called without parameters, return all datastores
        if ( $PSCmdlet.ParameterSetName -eq "main" ) {
            $uri = "{0}" -f $baseUri
            $returnObject = Invoke-ZertoRestRequest -uri $uri
        } else {
            # Return information for datastoreIdentifiers requested
            $returnObject = foreach ( $id in $datastoreIdentifier ) {
                $uri = "{0}/{1}" -f $baseUri, $id
                Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoEvent {
    [cmdletbinding( defaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The starting date for the list of events, supplied as a date with the format of the Zerto Virtual Manager where the API runs, for example, yyyy-MM-dd. You can also specify a local time with the following format: yyyy-MM-ddTHH:mm:ss.fffZ. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The end date for the list, supplied as a date with the format of the Zerto Virtual Manager where the API runs, for example, yyyy-MM-dd. You can also specify a local time with the following format: yyyy-MM-ddTHH:mm:ss.fffZ. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the VPG for which you want to return events."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgName")]
        [string]$vpg,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the VPG for which you want to return events."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId")]
        [string]$vpgIdentifier,
        [Parameter( ParameterSetName = "filter",
            HelpMessage = "The type of event. For the description of events, refer to the Zerto Virtual Replication documentation about alerts and events. Please see Zerto API Documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$eventType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the site for which you want to return events."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$siteName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The internal site identifier for which you want to return events."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string]$siteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the ZORG, Zerto organization, defined in the Zerto Cloud Manager for which you want to return results."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("zorgId")]
        [string]$zorgIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The type of entity for which you wish to return results. Possible Values are: 'VPG', 'VRA', 'Unknown', or 'Site'"
        )]
        [ValidateSet("VPG", "VRA", "Unknown", "Site")]
        [string]$entityType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the user for which the event occurred. If the event occurred as a result of a task started by the Zerto Virtual Manager, for example, when moving a VPG before the commit stage, the user is System."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$userName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The type of event to return. This filter behaves in the same way as the eventCategory filter. Possible Values are: Possible Values are: 'All', 'Events', 'Alerts'"
        )]
        [ValidateSet('All', 'Events', 'Alerts')]
        [string]$category,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = " This filter behaves in the same way as the category filter. If both category and eventCategory filters are specified, only the category filter value is used and the eventCategory filter value is ignored. The type of event to return. Possible Values are: 'All', 'Events', 'Alerts'"
        )]
        [ValidateSet("All", "Events", "Alerts")]
        [string]$eventCategory,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The internal alert identifier for the Event"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("alertId")]
        [string]$alertIdentifier,
        [Parameter(
            ParameterSetName = "eventId",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "The identifier or identifiers of the event for which information is returned."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$eventId,
        [Parameter(
            ParameterSetName = "categories",
            Mandatory,
            HelpMessage = "Returns possible Event Categories."
        )]
        [switch]$categories,
        [Parameter(
            ParameterSetName = "entities",
            Mandatory,
            HelpMessage = "Returns possible entity types."
        )]
        [switch]$entities,
        [Parameter(
            ParameterSetName = "types",
            Mandatory,
            HelpMessage = "Returns possible event types.")]
        [switch]$types
    )

    begin {
        $baseUri = "events"
        $returnObject = @()
    }

    process {
        # Process based on the ParameterSetName Used
        switch ( $PSCmdlet.ParameterSetName ) {
            # If no params are supplied, return all Events
            "main" {
                $uri = "{0}" -f $baseUri
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # If one or more eventIds are supplied, run a foreach loop to get them all
            "eventId" {
                $returnObject = foreach ( $id in $eventId ) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            # If a filter is applied, create the filter and return the events that fall in that filter
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                if ($PSBoundParameters.Keys -contains 'vpg') {
                    $vpgIdentifier = (Get-ZertoVpg -name $vpg).vpgIdentifier
                    $filter = $filter.replace("vpg=$vpg", "vpg=$vpgIdentifier")
                }
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # If a different ParameterSet is called, use the ParameterSet name to determine the URI and call it.
            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoLicense {
    [cmdletbinding()]
    param()
    $uri = "license"
    Invoke-ZertoRestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoLocalSite {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Switch to return possible paiting statuses."
        )]
        [switch]$pairingstatuses
    )
    $uri = "localsite"
    if ($pairingstatuses) {
        $uri = "/{0}/pairingstatuses" -f $uri
    }
    Invoke-ZertoRestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoPeerSite {
    [cmdletbinding( defaultParameterSetName = "main" )]
    param (
        [Parameter(
            ParameterSetName = "pairingStatuses",
            HelpMessage = "Switch to return possible paiting statuses.",
            Mandatory
        )]
        [switch]$pairingStatuses,
        [Parameter(
            ParameterSetName = "siteIdentifier",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "The identifier(s) of the peer site(s) for which information is to be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string[]]$siteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of a peer site for which information is to be returned. The name is case-sensitive."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$peerName,
        [Parameter (
            ParameterSetName = "filter",
            HelpMessage = "The pairing status for which information is to be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$paringStatus,
        [Parameter (
            ParameterSetName = "filter",
            HelpMessage = "The site location, as specified in the site information, for which information is to be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$location,
        [Parameter (
            ParameterSetName = "filter",
            HelpMessage = "The IP address of a Zerto Virtual Manager, paired with this site, for which information is to be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$hostName,
        [Parameter (
            ParameterSetName = "filter",
            HelpMessage = "The port used to access peer sites for which information is to be returned. The default port is 9081."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$port
    )

    begin {
        $baseUri = "peersites"
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "main" {
                $uri = "{0}" -f $baseUri
                $results = Invoke-ZertoRestRequest -uri $uri
                return $results
            }

            "siteIdentifier" {
                foreach ( $id in $siteIdentifier ) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    $results = Invoke-ZertoRestRequest -uri $uri
                    return $results
                }
            }

            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $results = Invoke-ZertoRestRequest -uri $uri
                return $results
            }

            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
                $results = Invoke-ZertoRestRequest -uri $uri
                return $results
            }
        }
    }

    end {
        #Nothing to do!
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoProtectedVm {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param (
        [Parameter(
            ParameterSetName = "vmIdentifier",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "vmIdentifier(s) for which to return information"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vmId")]
        [string[]]$vmIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the VPG which protects the virtual machine."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the virtual machine."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vmName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The status of the VPG. Please see Zerto API documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$status,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The substatus of the VPG, for example the VPG is in a bitmap sync. For the description of substatuses, refer to the Zerto Virtual Manager Administration Guide. Please see Zerto API documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$substatus,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The ZORG for this VPG."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$organizationName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The priority specified for the VPG. Possible values are: 'Low', 'Medium', or 'High'"
        )]
        [ValidateSet("Low", "Medium", "High")]
        [string]$priority,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The protected site type. Please see Zerto API documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The recovery site type. Please see Zerto API documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the protected site where the VPG virtual machines are protected."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("protectedSiteId")]
        [string]$protectedSiteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the recovery site where the VPG virtual machines are recovered."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("recoverySiteId")]
        [string]$recoverySiteIdentifier
    )

    begin {
        $baseUri = "vms"
        $returnObject = @()
    }

    process {
        # Select the operation based on the ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {
            # Return all protected VMs if no parameters are requested
            "main" {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }

            # Return information based on the vmIdentifer(s) provided.
            "vmIdentifier" {
                $returnObject = foreach ( $id in $vmIdentifier ) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            # If a search is requested, build the query string and return values.
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoRecoveryReport {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Operations performed between the specified start Time and end Time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startTime,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Operations performed between the specified start Time and end Time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endTime,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The page number the user wants to retrieve. Minimum value is 1."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$pageNumber,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The number of reports to display in a single page. The maximum number of reports per page is 1000."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$pageSize,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the VPG. You can specify more than one VPG, separated by commas."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The type of recovery operations. Possible values are: 'Failover', 'Failover Test', or 'Move'"
        )]
        [ValidateSet("Failover", "Failover Test", "Move")]
        [string]$recoveryType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Whether the recovery operation has completed."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$state
    )

    begin {
        $baseUri = "reports/recovery"
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            default {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoResourcesReport {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Operations performed between the specified start Time and end Time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startTime,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Operations performed between the specified start Time and end Time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endTime,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The page number to retrieve. Minimum value is 1"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$pageNumber,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The number of reports to display in a single page. The maximum number of reports per page is 1000."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$pageSize,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the organization set up in the Zerto Cloud Manager."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zorgName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the virtual machine."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vmName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the VPG."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the protected site."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the cluster containing the host where the virtual machine in the recovery site resides."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedClusterName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The address or DNS name of the host where the virtual machine in the recovery site resides."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedHostName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the vDC organization in the protected site."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedOrgVdc,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the vCD organization in the protected site."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedVdcOrg,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the cluster containing the host where the virtual machine in the recovery site resides."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryClusterName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The address or DNS name of the host where the virtual machine in the recovery site resides."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryHostName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the vDC organization in the recovery site."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryOrgVdc,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the recovery vCD organization."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryVdcOrg
    )

    begin {
        $baseUri = "reports/resources"
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            default {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoServiceProfile {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param (
        [Parameter(
            ParameterSetName = "siteIdentifier",
            HelpMessage = "The identifier of the site for which service profiles should be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string]$siteIdentifier,
        [Parameter(
            ParameterSetName = "serviceProfileId",
            HelpMessage = "The service profile ID for which information should be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("serviceProfileIdentifier")]
        [string[]]$serviceProfileId
    )

    begin {
        $baseUri = "serviceprofiles"
        $returnObject = [System.Collections.ArrayList]@()
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "siteIdentifier" {
                $uri = "{0}?site={1}" -f $baseUri, $siteIdentifier
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            "serviceProfileId" {
                $returnObject = foreach ( $id in $serviceProfileId ) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            default {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoTask {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param (
        [Parameter(
            ParameterSetName = "taskIdentifier",
            HelpMessage = "The identifier(s) for which task information is to be returned."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("taskId")]
        [string[]]$taskIdentifier,
        [Parameter(
            ParameterSetName = "types",
            HelpMessage = "Returns all task types."
        )]
        [switch]$types,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Tasks started before this time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startedBeforeDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Tasks started after this time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startedAfterDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Tasks completed after this time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$completedAfterDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Tasks completed before this time (inclusive) are displayed. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$completedBeforeDate,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The type of task. For the description of the tasks, refer to the Zerto Virtual Replication documentation about monitoring tasks. Please see Zerto API Documentation for possible types and values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$type,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The status of the task. Possible values are: 'InProgress', 'Paused', 'Failed', 'Completed', or 'Cancelling'"
        )]
        [ValidateSet("InProgress", "Paused", "Failed", "Completed", "Cancelling")]
        [string]$status
    )

    begin {
        $baseUri = "tasks"
        $returnObject = @()
    }

    process {
        # Process based on ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {

            # If function is called without parameters, return all events.
            "main" {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }

            # If function is called with Filter ParameterSetName, build filter and return results
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # If taskIdentifier(s) is supplied, return information for each id supplied.
            "taskIdentifier" {
                $returnObject = foreach ( $id in $taskIdentifier ) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            # If a different ParameterSetName is supplied, use that to build the URI and submit.
            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoUnprotectedVm {
    [cmdletbinding()]
    param()
    $uri = "virtualizationsites/{0}/vms" -f (Get-ZertoLocalSite).siteIdentifier
    Invoke-ZertoRestRequest -uri $uri
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoVirtualizationSite {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "siteIdentifier",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "datastoreClusters",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "datastores",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "hostClusters",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "hosts",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "networks",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "resourcePools",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "vms",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "devices",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "folders",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [Parameter(
            ParameterSetName = "repositories",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string]$siteIdentifier,
        [Parameter(
            ParameterSetName = "datastoreClusters",
            Mandatory,
            HelpMessage = "When selected, will return all datastore clusters at the specified site."
        )]
        [switch]$datastoreClusters,
        [Parameter(
            ParameterSetName = "datastores",
            Mandatory,
            HelpMessage = "When selected, will return all datastores at the specified site."
        )]
        [switch]$datastores,
        [Parameter(
            ParameterSetName = "devices",
            Mandatory,
            HelpMessage = "When selected, will return all devices at the specified site."
        )]
        [switch]$devices,
        [Parameter(
            ParameterSetName = "devices",
            Mandatory = $false,
            HelpMessage = "The identifier of the host for which to return all devices."
        )]
        [Parameter(
            ParameterSetName = "hosts",
            Mandatory = $false,
            HelpMessage = "The identifier of the host at the selected site to return information for only one host."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("hostId")]
        [string]$hostIdentifier,
        [Parameter(
            ParameterSetName = "folders",
            Mandatory,
            HelpMessage = "Return all folders at the selected site."
        )]
        [switch]$folders,
        [Parameter(
            ParameterSetName = "hostClusters",
            Mandatory,
            HelpMessage = "Return all host clusters at the selected site."
        )]
        [switch]$hostClusters,
        [Parameter(
            ParameterSetName = "hosts",
            Mandatory,
            HelpMessage = "Return all hosts at the selected site. If a host identifier is provided, return only that host."
        )]
        [switch]$hosts,
        [Parameter(
            ParameterSetName = "networks",
            Mandatory,
            HelpMessage = "Return all networks at the selected site."
        )]
        [switch]$networks,
        [Parameter(
            ParameterSetName = "resourcePools",
            Mandatory,
            HelpMessage = "Return all resource pools at the selected site."
        )]
        [switch]$resourcePools,
        [Parameter(
            ParameterSetName = "vms",
            Mandatory,
            HelpMessage = "Return all VMs at the selected site."
        )]
        [switch]$vms,
        [Parameter(
            ParameterSetName = "repositories",
            Mandatory,
            HelpMessage = "The identifier of the Zerto Virtual Manager site."
        )]
        [switch]$repositories
    )

    begin {

    }

    process {
        # Return information based on ParameterSetName invoked.
        $baseUri = "virtualizationsites"
        switch ( $PSCmdlet.ParameterSetName ) {
            # If no ParameterSetName is specified, return all data
            "main" {
                $uri = $baseUri
            }

            # If devices is specified along with a hostId, build return just that host information, otherwise return all devices at the site
            "devices" {
                if ( $PSBoundParameters.ContainsKey( "hostIdentifier" ) ) {
                    $uri = "{0}/{1}/devices?hostIdentifier={2}" -f $baseUri, $siteIdentifier, $hostIdentifier
                } else {
                    $uri = "{0}/{1}/devices" -f $baseUri, $siteIdentifier
                }
            }

            # If hosts is specified along with a hostID, build and return just that host information, otherwise return all hosts at the site
            "hosts" {
                if ( $PSBoundParameters.ContainsKey( "hostIdentifier" ) ) {
                    $uri = "{0}/{1}/hosts/{2}" -f $baseUri, $siteIdentifier, $hostIdentifier
                } else {
                    $uri = "{0}/{1}/hosts" -f $baseUri, $siteIdentifier
                }
            }

            # If siteIdentifier is specified, return information for that site.
            "siteIdentifier" {
                $uri = "{0}/{1}" -f $baseUri, $siteIdentifier
            }

            # If a different ParameterSetName is selected, use that information to build the URI and return that information
            default {
                $uri = "{0}/{1}/{2}" -f $baseUri, $siteIdentifier, $PSCmdlet.ParameterSetName.ToLower()
            }
        }
        Invoke-ZertoRestRequest -uri $uri
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoVolume {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The type of volume. Please see Zerto API Documentation for possible values."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$volumeType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the VPG."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId")]
        [string]$vpgIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the datastore."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("datastoreId", "dsId")]
        [string]$datastoreIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the protected virtual machine."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("protectedVmId")]
        [string]$protectedVmIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the owning virtual machine."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("owningVmId")]
        [string]$owningVmIdentifier
    )

    begin {
        $baseUri = "volumes"
        $returnObject = @()
    }

    process {
        # Process based on ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {

            # If a filter is defined, build the query string and return selected information
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # Default action is to return all Volumes.
            default {
                $returnObject = Invoke-ZertoRestRequest -uri $baseUri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoVpg {
    [cmdletbinding( DefaultParameterSetName = "main" )]
    param(
        [Parameter(
            ParameterSetName = "protectionGroupIdentifier",
            Mandatory,
            HelpMessage = "The identifier(s) of the Virtual Protection Group to return"
        )]
        [Parameter(
            ParameterSetName = "checkpoints",
            Mandatory,
            HelpMessage = "The identifier(s) of the Virtual Protection Group to return"
        )]
        [Parameter(
            ParameterSetName = "stats",
            Mandatory,
            HelpMessage = "The identifier(s) of the Virtual Protection Group to return"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId", "protectionGroupId", "pgId")]
        [string[]]$protectionGroupIdentifier,
        [Parameter(
            ParameterSetName = "checkpoints",
            Mandatory,
            HelpMessage = "Return checkpoints for the selected Virtual Protection Group."
        )]
        [switch]$checkpoints,
        [Parameter(
            ParameterSetName = "checkpoints",
            HelpMessage = "Return checkpoints after the specified start date. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$startDate,
        [Parameter(
            ParameterSetName = "checkpoints",
            HelpMessage = "Return checkpoints before the specified start date. Valid formats include: 'yyyy-MM-ddTHH:mm:ss.fffZ', 'yyyy-MM-ddTHH:mm:ssZ', 'yyyy-MM-ddTHH:mmZ', 'yyyy-MM-ddTHHZ', 'yyyy-MM-dd', 'yyyy-MM', 'yyyy'. Adding Z to the end of the time sets the time to UTC."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$endDate,
        [Parameter(
            ParameterSetName = "stats", Mandatory,
            HelpMessage = "Return earliest and latest checkpoints for the selected Virtual Protection Group"
        )]
        [switch]$checkpointsStats,
        [Parameter(
            ParameterSetName = "entityTypes",
            Mandatory,
            HelpMessage = "Return Valid VPG entityTypes"
        )]
        [switch]$entityTypes,
        [Parameter(
            ParameterSetName = "failoverCommitPolicies",
            Mandatory,
            HelpMessage = "Valid Failover Commit Policies"
        )]
        [switch]$failoverCommitPolicies,
        [Parameter(
            ParameterSetName = "failoverShutdownPolicies",
            Mandatory,
            HelpMessage = "Valid Failover Shutdown Policies"
        )]
        [switch]$failoverShutdownPolicies,
        [Parameter(
            ParameterSetName = "priorities",
            Mandatory,
            HelpMessage = "Valid VPG priorities"
        )]
        [switch]$priorities,
        [Parameter(
            ParameterSetName = "retentionPolicies",
            Mandatory,
            HelpMessage = "Valid retention policies"
        )]
        [switch]$retentionPolicies,
        [Parameter(
            ParameterSetName = "statuses",
            Mandatory,
            HelpMessage = "Valid VPG statuses"
        )]
        [switch]$statuses,
        [Parameter(
            ParameterSetName = "subStatuses",
            Mandatory,
            HelpMessage = "Valid VPG sub statuses"
        )]
        [switch]$subStatuses,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The name of the VPG."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgName")]
        [string]$name,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The status of the VPG. Please use 'Get-ZertoVpg -statuses' for valid values"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$status,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The substatus of the VPG. Please use 'Get-ZertoVpg -substatuses' for valid values"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$subStatus,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The protected site environment. This filter behaves in the same way as the sourceType filter. Please see Zerto API Documentation for vaild values and discriptions."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The recovery site environment. This filter behaves in the same way as the sourceType filter. Please see Zerto API Documentation for vaild values and discriptions."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteType,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the protected site where the VPG virtual machines are protected."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$protectedSiteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the protected site where the VPG virtual machines are recovered."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySiteIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The ZORG for this VPG."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$organizationName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The internal identifier for the ZORG."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$zorgIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The VPG priority. Possible values are: 'Low', 'Medium', 'High'"
        )]
        [ValidateSet("Low", "Medium", "High")]
        [string]$priority,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "The identifier of the service profile to use for the VPG when a Zerto Cloud Manager is used."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$serviceProfileIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "If backup is enabled."
        )]
        [switch]$backupEnabled
    )
    begin {
        $baseUri = "vpgs"
    }

    Process {
        # Process based on ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {

            # When called with no parameters, return all values
            "main" {
                $uri = $baseUri
            }

            # When called with protectionGroupIdentifier, query for each id provided
            "protectionGroupIdentifier" {
                $uri = foreach ( $vpgId in $protectionGroupIdentifier ) {
                    "{0}/{1}" -f $baseUri, $vpgId
                }
            }

            # When checkpoints is called, determine if a filter is needed and query with or without the filter.
            "checkpoints" {
                $filter = $false
                if ( $PSBoundParameters.ContainsKey("startDate") -or $PSBoundParameters.ContainsKey("endDate") ) {
                    $filter = $true
                    $filterTable = @{ }
                    foreach ( $param in $PSBoundParameters.GetEnumerator() ) {
                        if ( $param.key -eq "startDate" -or $param.key -eq "endDate") {
                            $filterTable[$param.key] = $param.value
                        }
                    }
                    $filter = Get-ZertoApiFilter -filterTable $filterTable
                }
                $uri = foreach ( $id in $protectionGroupIdentifier ) {
                    if ( $filter ) {
                        "{0}/{1}/checkpoints{2}" -f $baseUri, $id, $filter
                    } else {
                        "{0}/{1}/checkpoints" -f $baseUri, $id
                    }
                }
            }

            # When stats are requested
            "stats" {
                $uri = foreach ( $id in $protectionGroupIdentifier ) {
                    "{0}/{1}/checkpoints/stats" -f $baseUri, $id
                }
            }

            # When filtering for VPGs build query string and return events
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
            }

            # Default is to build URI based on ParameterSetName and return results.
            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
            }
        }
        foreach ($entry in $uri) {
            Invoke-ZertoRestRequest -uri $entry
        }
    }

    End {
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoVpgSetting {
    [cmdletbinding(
        DefaultParameterSetName = "main",
        SupportsShouldProcess = $false
    )]
    param(
        [Parameter(
            ParameterSetName = "vpgSettingsIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "backup",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved. Please note, this parameter is ONLY available in Zerto version 7.5 and earlier. Attempting to run this switch against a Zerto Virtual Manager version 8.0 or higher result in an error."
        )]
        [Parameter(
            ParameterSetName = "dayOfWeek",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "retentionPeriod",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "schedulerPeriod",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "basic",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "bootGroup",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "journal",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "networks",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "priority",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "recovery",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "scripting",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "vms",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "vmIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "nics",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "nicIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "volumes",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "volumeIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [Parameter(
            ParameterSetName = "ltr",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            Mandatory,
            HelpMessage = "The identifier of the VPG settings object for which information is retrieved."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgSettingsId", "settingsId")]
        [string[]]$vpgSettingsIdentifier,
        [Parameter(
            ParameterSetName = "backup",
            Mandatory,
            HelpMessage = "Return backup information for VPG identifier specified. Please note, this parameter is ONLY available in Zerto version 7.5 and earlier. Attempting to run this switch against a Zerto Virtual Manager version 8.0 or higher result in an error."
        )]
        [switch]$backup,
        [Parameter(
            ParameterSetName = "dayOfWeek",
            Mandatory,
            HelpMessage = "Get the day of week a backup is scheduled. Please note, this parameter is ONLY available in Zerto version 7.5 and earlier. Attempting to run this switch against a Zerto Virtual Manager version 8.0 or higher result in an error."
        )]
        [switch]$dayOfWeek,
        [Parameter(
            ParameterSetName = "retentionPeriod",
            Mandatory,
            HelpMessage = "Get the retention period for a backup. Please note, this parameter is ONLY available in Zerto version 7.5 and earlier. Attempting to run this switch against a Zerto Virtual Manager version 8.0 or higher result in an error."
        )]
        [switch]$retentionPeriod,
        [Parameter(
            ParameterSetName = "schedulerPeriod",
            Mandatory,
            HelpMessage = "Get the backup schedule. Please note, this parameter is ONLY available in Zerto version 7.5 and earlier. Attempting to run this switch against a Zerto Virtual Manager version 8.0 or higher result in an error."
        )]
        [switch]$schedulerPeriod,
        [Parameter(
            ParameterSetName = "basic",
            Mandatory,
            HelpMessage = "Get VPG Basic Settings"
        )]
        [switch]$basic,
        [Parameter(
            ParameterSetName = "bootGroup",
            Mandatory,
            HelpMessage = "Get VPG Boot Settings"
        )]
        [switch]$bootgroup,
        [Parameter(
            ParameterSetName = "journal",
            Mandatory,
            HelpMessage = "Get VPG Journal Settings"
        )]
        [switch]$journal,
        [Parameter(
            ParameterSetName = "networks",
            Mandatory,
            HelpMessage = "Get VPG Network Settings"
        )]
        [switch]$networks,
        [Parameter(
            ParameterSetName = "priority",
            Mandatory,
            HelpMessage = "Get VPG Priority Settings"
        )]
        [switch]$priority,
        [Parameter(
            ParameterSetName = "recovery",
            Mandatory,
            HelpMessage = "Get VPG Recovery Settings"
        )]
        [Alias("rcovery")]
        [switch]$recovery,
        [Parameter(
            ParameterSetName = "scripting",
            Mandatory,
            HelpMessage = "Get VPG Recovery Settings"
        )]
        [switch]$scripting,
        [Parameter(
            ParameterSetName = "vms",
            Mandatory,
            HelpMessage = "Get all settings for all VMs in a VPG."
        )]
        [switch]$vms,
        [Parameter(
            ParameterSetName = "vmIdentifier",
            Mandatory,
            HelpMessage = "Get all settings for selected VM"
        )]
        [Parameter(
            ParameterSetName = "nics",
            Mandatory,
            HelpMessage = "VM Identifier"
        )]
        [Parameter(
            ParameterSetName = "volumes",
            Mandatory,
            HelpMessage = "VM Identifier"
        )]
        [Parameter(
            ParameterSetName = "nicIdentifier",
            Mandatory,
            HelpMessage = "VM Identifier"
        )]
        [Parameter(
            ParameterSetName = "volumeIdentifier",
            Mandatory,
            HelpMessage = "VM Identifier"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vmId")]
        [string]$vmIdentifier,
        [Parameter(
            ParameterSetName = "nics",
            Mandatory,
            HelpMessage = "Return NIC information for all NICs of the specified VM"
        )]
        [switch]$nics,
        [Parameter(
            ParameterSetName = "nicIdentifier",
            Mandatory,
            HelpMessage = "Return NIC information for specified NIC of the specified VM"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("nicId")]
        [string]$nicIdentifier,
        [Parameter(
            ParameterSetName = "volumes",
            Mandatory,
            HelpMessage = "Return Volume information for all volumes of the specified VM"
        )]
        [switch]$volumes,
        [Parameter(
            ParameterSetName = "volumeIdentifier",
            Mandatory,
            HelpMessage = "Return volume information for the specified volume of the specified VM"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("volumeId")]
        [string]$volumeIdentifier,
        [Parameter(
            ParameterSetName = "ltr",
            Mandatory,
            HelpMessage = "Return LTR information for the specified VPG. Please note, this parameter is ONLY available in Zerto version 8.0 and later. Attempting to run this switch against a Zerto Virtual Manager version 7.5 or lower will result in an error."
        )]
        [switch]$ltr

    )

    begin {
        $baseUri = "vpgSettings"
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "main" {
                Invoke-ZertoRestRequest -uri $baseUri
                break
            }

            "vpgSettingsIdentifier" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "dayOfWeek" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/backup/{2}" -f $baseUri, $id, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "retentionPeriod" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/backup/{2}" -f $baseUri, $id, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "schedulerPeriod" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/backup/{2}" -f $baseUri, $id, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "nics" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/vms/{2}/{3}" -f $baseUri, $id, $vmIdentifier, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "volumes" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/vms/{2}/{3}" -f $baseUri, $id, $vmIdentifier, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "vmIdentifier" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/vms/{2}" -f $baseUri, $id, $vmIdentifier
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "nicIdentifier" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/vms/{2}/nics/{3}" -f $baseUri, $id, $vmIdentifier, $nicIdentifier
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            "volumeIdentifier" {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/vms/{2}/volumes/{3}" -f $baseUri, $id, $vmIdentifier, $volumeIdentifier
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }

            default {
                foreach ($id in $vpgSettingsIdentifier) {
                    $uri = "{0}/{1}/{2}" -f $baseUri, $id, $PSCmdlet.ParameterSetName.ToLower()
                    Invoke-ZertoRestRequest -uri $uri
                }
                break
            }
        }
    }

    end {
        #Nothing to do!
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoVra {
    [cmdletbinding(
        DefaultParameterSetName = "main"
    )]
    param(
        [Parameter(
            ParameterSetName = "ipConfigurationTypes",
            HelpMessage = "Returns Valid VRA IP configuration types"
        )]
        [switch]$ipconfigurationtypes,
        [Parameter(
            ParameterSetName = "statuses",
            HelpMessage = "Returns Valid VRA statuses"
        )]
        [switch]$statuses,
        [Parameter(
            ParameterSetName = "vraIdentifier",
            HelpMessage = "Returns information for provided VRA identifier(s)"
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vraId")]
        [string[]]$vraIdentifier,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "VRA Name to return information for."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vraName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs in a specific status"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$status,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs of a specific version"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vraVersion,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs paired to a specific host version"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$hostVersion,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for a VRA with the specified IP address"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$ipAddress,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs belonging to a specific group"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vraGroup,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs on a specific datastore"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs on a specific datastore cluster"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreClusterName,
        [Parameter(
            ParameterSetName = "filter",
            HelpMessage = "Search for VRAs on a specific network"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$networkName
    )

    begin {
        $baseUri = "vras"
        $returnObject = @()
    }

    process {

        # Process based on ParameterSetName
        switch ( $PSCmdlet.ParameterSetName ) {

            # When called without params, return all VRAs
            "main" {
                $uri = $baseUri
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # When vra ids are provided, return for each id provided
            "vraIdentifier" {
                $returnObject = foreach ( $vraId in $vraIdentifier ) {
                    $uri = "{0}/{1}" -f $baseUri, $vraId
                    Invoke-ZertoRestRequest -uri $uri
                }
            }

            # When filter is requested, search based on provided data.
            "filter" {
                $filter = Get-ZertoApiFilter -filterTable $PSBoundParameters
                $uri = "{0}{1}" -f $baseUri, $filter
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }

            # When a different ParameterSetName is requested, query against that name
            default {
                $uri = "{0}/{1}" -f $baseUri, $PSCmdlet.ParameterSetName.ToLower()
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoZorg {
    [cmdletbinding( DefaultParameterSetName = "default" )]
    param(
        [Parameter(
            ParameterSetName = "zorgIdentifier",
            HelpMessage = "Identifier(s) of the ZORG."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("zorgId")]
        [string[]]$zorgIdentifier
    )

    begin {
        $baseUri = "zorgs"
        $returnObject = @()
    }

    process {
        if ( $PSCmdlet.ParameterSetName -eq "default" ) {
            $returnObject = Invoke-ZertoRestRequest -uri $baseUri
        } elseif ( $PSCmdlet.ParameterSetName -eq "zorgIdentifier" ) {
            $returnObject = foreach ( $id in $zorgIdentifier ) {
                $uri = "{0}/{1}" -f $baseUri, $id
                Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Get-ZertoZsspSession {
    [cmdletbinding( DefaultParameterSetName = "default" )]
    param(
        [Parameter(
            ParameterSetName = "zsspSessionIdentifier",
            HelpMessage = "ZSSP Session Id(s) to get information."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("zsspSessionId")]
        [string[]]$zsspSessionIdentifier
    )

    begin {
        $baseUri = "zsspSessionIdentifier"
        $returnObject = @()
    }

    process {
        if ( $PSCmdlet.ParameterSetName -eq "default" ) {
            $returnObject = Invoke-ZertoRestRequest -uri $baseUri
        } elseif ( $PSCmdlet.ParameterSetName -eq "zsspSessionIdentifier" ) {
            $returnObject = foreach ( $id in $zsspSessionIdentifier ) {
                $uri = "{0}/{1}" -f $baseUri, $id
                $returnObject = Invoke-ZertoRestRequest -uri $uri
            }
        }
    }

    end {
        return $returnObject
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Import-ZertoVmNicSetting {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        # File to process for import
        [Parameter(Helpmessage = "CSV file containing the required VM NIC settings", Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]
        $InputFile
    )

    begin {
    }

    process {
        if (-not (Test-Path $InputFile)) {
            Write-Error "Unable to find $InputFile. Please check the name and path and try again." -ErrorAction Stop
        } elseif ((Get-Item $InputFile).Extension -notmatch '.csv') {
            Write-Error "$InputFile does not have a 'csv' extension. Please check the name and path and try again." -ErrorAction Stop
        }
        $ExpectedHeaders = "VPGName", "VMName", "NicIdentifier", "LiveNetwork", "LiveShouldReplaceMac", "LiveIsDHCP", "LiveIpAddress", "LiveIpSubnetMask", "LiveIpDefaultGateway", "LivePrimaryDns", "LiveSecondayDns", "LiveDnsSuffix", "TestNetwork", "TestShouldReplaceMac", "TestIsDHCP", "TestIpAddress", "TestIpSubnetMask", "TestIpDefaultGateway", "TestPrimaryDns", "TestSecondayDns", "TestDnsSuffix"
        $HeaderLine = ((Get-Content -Path $InputFile -First 1).Replace('"', '')).Split(',')
        foreach ($header in $ExpectedHeaders) {
            if ($header -notin $HeaderLine) {
                Write-Error "$InputFile is malformed. Please ensure all headers are present." -ErrorAction Stop
            }
        }
        $ImportData = Import-Csv -Path $InputFile
        $VpgsToUpdate = $ImportData.VPGName | Select-Object -Unique
        foreach ($Vpg in $VpgsToUpdate) {
            $VpgInfo = Get-ZertoVpg -vpgName $Vpg
            $VpgIdentifier = $VpgInfo.VpgIdentifier
            $RecoveryNetworks = Get-ZertoVirtualizationSite -siteIdentifier $VpgInfo.RecoverySite.Identifier -networks
            $NetworkMap = Get-Map -InputObject $RecoveryNetworks -key "VirtualizationNetworkName" -value "NetworkIdentifier"
            $VpgVms = Get-ZertoProtectedVm -vpgName $Vpg
            $VmMap = Get-Map -InputObject $VpgVms -key "vmName" -value "vmIdentifier"
            $VpgSettingsId = New-ZertoVpgSettingsIdentifier -vpgIdentifier $VpgIdentifier
            $VmsToUpdate = $ImportData | Where-Object { $_.VPGName -eq $Vpg }
            foreach ($vm in $VmsToUpdate) {
                if ([string]::IsNullOrWhiteSpace($vm.VpgName) -or
                    [string]::IsNullOrWhiteSpace($Vm.VMName) -or
                    [string]::IsNullOrWhiteSpace($Vm.NicIdentifier) -or
                    [string]::IsNullOrWhiteSpace($Vm.LiveNetwork) -or
                    [string]::IsNullOrWhiteSpace($Vm.LiveShouldReplaceMac) -or
                    [string]::IsNullOrWhiteSpace($Vm.TestNetwork) -or
                    [string]::IsNullOrWhiteSpace($Vm.TestShouldReplaceMac)) {
                    Write-Error "$($Vm.VMName) does not contain all the required data. Please check the CSV entry for this item and try again. You are required to provide the VPGName, VMName, NicIdentifier, LiveNetwork, and ShouldReplaceMacAddress for each Nic." -ErrorAction Continue
                } else {
                    $uri = "vpgSettings/{0}/vms/{1}" -f $vpgSettingsId, $vmMap[$vm.VMName]
                    $VmNicSettings = Get-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsId -vmIdentifier $vmMap[$vm.VMName]
                    foreach ($nic in $VmNicSettings.nics) {
                        if ($nic.NicIdentifier -eq $vm.NicIdentifier) {
                            $NicUri = "{0}/nics/{1}" -f $uri, $nic.NicIdentifier
                            Invoke-ZertoRestRequest -uri $NicUri -Method "DELETE" > $null
                            $nicSettings = Invoke-ZertoRestRequest -uri $NicUri -Method "GET"
                            $nicSettings.failover.Hypervisor.NetworkIdentifier = $NetworkMap[$vm.LiveNetwork]
                            $nicSettings.failover.Hypervisor.ShouldReplaceMacAddress = $vm.LiveShouldReplaceMac
                            if ($vm.LiveIsDHCP -imatch "true") {
                                $IpConfig = [PSCustomObject]@{
                                    IsDhcp       = $vm.LiveIsDHCP
                                    PrimaryDns   = $vm.LivePrimaryDns
                                    SecondaryDns = $vm.LiveSecondayDns
                                }
                                $nicSettings.failover.Hypervisor.IpConfig = $IpConfig
                                $nicSettings.failover.Hypervisor.DnsSuffix = $vm.LiveDnsSuffix
                            } elseif (($vm.LiveIsDHCP -imatch "false" -or
                                    [string]::IsNullOrWhiteSpace($vm.LiveIsDHCP)) -and
                                -not [string]::IsNullOrWhiteSpace($vm.LiveIpAddress)) {
                                $IpConfig = [PSCustomObject]@{
                                    IsDhcp       = $vm.LiveIsDHCP
                                    StaticIp     = $vm.LiveIpAddress
                                    SubnetMask   = $vm.LiveIpSubnetMask
                                    Gateway      = $vm.LiveIpDefaultGateway
                                    PrimaryDns   = $vm.LivePrimaryDns
                                    SecondaryDns = $vm.LiveSecondayDns
                                }
                                $nicSettings.failover.Hypervisor.IpConfig = $IpConfig
                                $nicSettings.failover.Hypervisor.DnsSuffix = $vm.LiveDnsSuffix
                            }
                            $nicSettings.failoverTest.Hypervisor.NetworkIdentifier = $NetworkMap[$vm.TestNetwork]
                            $nicSettings.failoverTest.Hypervisor.ShouldReplaceMacAddress = $vm.TestShouldReplaceMac
                            if ($vm.TestIsDHCP -imatch "true" ) {
                                $IpConfig = [PsCustomObject]@{
                                    IsDhcp       = $vm.TestIsDHCP
                                    PrimaryDns   = $vm.TestPrimaryDns
                                    SecondaryDns = $vm.TestSecondayDns
                                }
                                $nicSettings.failoverTest.Hypervisor.IpConfig = $IpConfig
                                $nicSettings.failoverTest.Hypervisor.DnsSuffix = $vm.TestDnsSuffix
                            } elseif (($vm.TestIsDHCP -imatch "false" -or
                                    [string]::IsNullOrWhiteSpace($vm.TestIsDHCP)) -and
                                -not [string]::IsNullOrWhiteSpace($vm.TestIpAddress)) {
                                $IpConfig = [PsCustomObject]@{
                                    IsDhcp       = $vm.TestIsDHCP
                                    StaticIp     = $vm.TestIpAddress
                                    SubnetMask   = $vm.TestIpSubnetMask
                                    Gateway      = $vm.TestIpDefaultGateway
                                    PrimaryDns   = $vm.TestPrimaryDns
                                    SecondaryDns = $vm.TestSecondayDns
                                }
                                $nicSettings.failoverTest.Hypervisor.IpConfig = $IpConfig
                                $nicSettings.failoverTest.Hypervisor.DnsSuffix = $vm.TestDnsSuffix
                            }
                            Write-Verbose "Putting Updated Config for VM: $($vm.name), NIC: $($nic.nicidentifier) in VPG: $Vpg"
                            if ($PSCmdlet.ShouldProcess($vm.NicIdentifier, "Updating Nic")) {
                                Invoke-ZertoRestRequest -uri $NicUri -Method "PUT" -Body ($nicSettings | ConvertTo-Json -Depth 10) > $null
                            }
                        }
                    }
                }
            }
            Write-Verbose "Saving updated configuration for VPG: $Vpg"
            if ($PSCmdlet.ShouldProcess($Vpg, "Saving Changes")) {
                Save-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsId
            }
            Write-Verbose "Waiting 5 Seconds for Next VPG Update"
            Start-Sleep 5
        }
    }


    end {
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Import-ZertoVpg {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "VPG settings JSON file(s) to import.",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("FullName")]
        [string[]]$settingsFile
    )

    begin {
        $baseUri = "vpgSettings"
    }

    process {
        foreach ($file in $settingsFile) {
            $importedSettings = Get-Content -Path $file -Raw | ConvertFrom-Json
            $vpgSettingsIdentifier = New-ZertoVpgSettingsIdentifier -newVpg
            $importedSettings.VpgIdentifier = $null
            $importedSettings.VpgSettingsIdentifier = $vpgSettingsIdentifier
            $uri = "{0}/{1}" -f $baseUri, $vpgSettingsIdentifier
            Invoke-ZertoRestRequest -uri $uri -method "PUT" -body $($importedSettings | convertto-json -Depth 10)
            $vpgSettingsIdentifier | Save-ZertoVpgSetting
            if ($settingsFile.Count -gt 1) {
                Start-Sleep 5
            }
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Install-ZertoVra {
    [cmdletbinding( SupportsShouldProcess )]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Host name where the VRA is to be installed."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$hostName,
        [Parameter(
            Mandatory,
            HelpMessage = "Datastore name where the VRA is to be installed."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreName,
        [Parameter(
            Mandatory,
            HelpMessage = "Network name the VRA is to be assigned."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$networkName,
        [Parameter(
            HelpMessage = "Initial amount of memory to assign to the VRA in GB. Default is 3, Minimum is 1, Maximum is 16"
        )]
        [ValidateRange(1, 16)]
        [int]$memoryInGB = 3,
        [Parameter(
            HelpMessage = "Initial number of CPUs to assign to the VRA. Default is 1, Minimum is 1, Maximum is 4"
        )]
        [ValidateRange(1, 4)]
        [int]$NumOfCpus = 1,
        [Parameter(
            HelpMessage = "Bandwidth group to assign to the VRA. If unspecified will assign to the 'default_group'"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$groupName,
        [Parameter(
            ParameterSetName = "Dhcp",
            Mandatory,
            HelpMessage = "Assign a DHCP address to the VRA."
        )]
        [Parameter(
            ParameterSetName = "DhcpWithRoot",
            Mandatory,
            HelpMessage = "Assign a DHCP address to the VRA."
        )]
        [switch]$Dhcp,
        [Parameter(
            ParameterSetName = "StaticIp",
            Mandatory,
            HelpMessage = "Static IP address to assign to the VRA."
        )]
        [Parameter(
            ParameterSetName = "StaticIpWithRoot",
            Mandatory,
            HelpMessage = "Static IP address to assign to the VRA."
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$vraIpAddress,
        [Parameter(
            ParameterSetName = "StaticIp",
            Mandatory,
            HelpMessage = "Default gateway to assign to the VRA"
        )]
        [Parameter(
            ParameterSetName = "StaticIpWithRoot",
            Mandatory,
            HelpMessage = "Default gateway to assign to the VRA"
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$defaultGateway,
        [Parameter(
            ParameterSetName = "StaticIp",
            Mandatory,
            HelpMessage = "Subnetmask to be assigned to the VRA"
        )]
        [Parameter(
            ParameterSetName = "StaticIpWithRoot",
            Mandatory,
            HelpMessage = "Subnetmask to be assigned to the VRA"
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string]$subnetMask,
        [Parameter(
            ParameterSetName = "StaticIpWithRoot",
            Mandatory,
            HelpMessage = "Use this switch to install the VRA using the root password install method."
        )]
        [Parameter(
            ParameterSetName = "DhcpWithRoot",
            Mandatory,
            HelpMessage = "Use this switch to install the VRA using the root password install method."
        )]
        [switch]$UseRootCredential,
        [Parameter(
            ParameterSetName = "StaticIpWithRoot",
            Mandatory,
            HelpMessage = "The password for the root user of the ESXi host where the VRA is to be installed."
        )]
        [Parameter(
            ParameterSetName = "DhcpWithRoot",
            Mandatory,
            HelpMessage = "The password for the root user of the ESXi host where the VRA is to be installed."
        )]
        [ValidateNotNullOrEmpty()]
        [securestring]$HostRootPassword
    )

    begin {

    }
    Process {
        # Build the VRA Name.
        $vraName = "Z-VRA-{0}" -f $hostName
        # If the VRA does not exist, proceed with the installation. If it does exist, bypass and
        if ( -not (Get-ZertoVra -vraName $vraName) ) {
            # Get identifiers for each item provided by name.
            $siteIdentifier = (Get-ZertoLocalSite).SiteIdentifier
            $hostIdentifier = Get-ZertoVirtualizationSite -siteIdentifier $siteIdentifier -hosts | Where-Object { $_.VirtualizationHostName -eq $hostName } | Select-Object hostIdentifier -ExpandProperty hostIdentifier
            $networkIdentifier = Get-ZertoVirtualizationSite -siteIdentifier $siteIdentifier -networks | Where-Object { $_.VirtualizationNetworkName -eq $networkName } | Select-Object NetworkIdentifier -ExpandProperty NetworkIdentifier
            $datastoreIdentifier = Get-ZertoVirtualizationSite -siteIdentifier $siteIdentifier -datastores | Where-Object { $_.DatastoreName -eq $datastoreName } | Select-Object DatastoreIdentifier -ExpandProperty DatastoreIdentifier
            if ($datastoreIdentifier.count -gt 1) {
                $hostDevices = Get-ZertoVirtualizationSite -siteIdentifier $siteIdentifier -devices -hostIdentifier $hostIdentifier
                $datastoreIdentifier = foreach ($identifier in $datastoreIdentifier) {
                    if ($identifier -in $hostDevices.DatastoreIdentifier) {
                        $identifier
                    }
                }
                if ($datastoreIdentifier.count -gt 1) {
                    Write-Error "Datastore $datastoreName has more than one identifier associated with it on the specified host. Please review and try again."
                    Break
                }
            }

            # Build the JSON object through an Ordered Hashtable.
            $vraBasic = [ordered]@{ }
            $vraBasic['DatastoreIdentifier'] = $datastoreIdentifier.toString()
            if ($PSBoundParameters.ContainsKey('groupName')) {
                $vraBasic['GroupName'] = $groupName
            }
            $vraBasic['HostIdentifier'] = $hostIdentifier.toString()
            $vraBasic['MemoryInGB'] = $memoryInGB
            $vraBasic['NumOfCpus'] = $NumOfCpus
            $vraBasic['NetworkIdentifier'] = $networkIdentifier.toString()
            $vraBasic['UsePublicKeyInsteadOfCredentials'] = $true
            $vraBasicNetwork = [ordered]@{ }
            if ( $PSCmdlet.ParameterSetName -eq "StaticIp" -or $PSCmdlet.ParameterSetName -eq "StaticIpWithRoot") {
                $vraBasicNetwork['DefaultGateway'] = $defaultGateway.toString()
                $vraBasicNetwork['SubnetMask'] = $subnetMask.toString()
                $vraBasicNetwork['VraIPAddress'] = $vraIpAddress.toString()
                $vraBasicNetwork['VraIPConfigurationTypeApi'] = "Static"
            } else {
                $vraBasicNetwork['VraIPConfigurationTypeApi'] = "Dhcp"
            }
            $vraBasic['VraNetworkDataApi'] = $vraBasicNetwork
            if ($PSCmdlet.ParameterSetName -eq "StaticIpWithRoot" -or $PSCmdlet.ParameterSetName -eq "DhcpWithRoot") {
                $HostRootCredential = [pscredential]::new('root', $HostRootPassword)
                $vraBasic['UsePublicKeyInsteadOfCredentials'] = $false
                $vraBasic['HostRootPassword'] = $HostRootCredential.GetNetworkCredential().Password
            }

            # Leverage WhatIf functionality to see what might happen, if WhatIf is not specified, attempt to install.
            if ($PSCmdlet.ShouldProcess($hostName)) {
                Invoke-ZertoRestRequest -uri "vras" -method POST -body $($vraBasic | ConvertTo-Json)
            }
        } else {
            Write-Error "Host $hostName already has a VRA installed. Aborting Install Call"
        }
    }

    End {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZARestRequest {
    [cmdletbinding()]
    param(
        # Parameter help description
        [Parameter(
            Mandatory,
            Helpmessage = "URI endpoint to be utilized. When submitting the URI, only the endpoint needs to be submitted. Please review the help documentation for examples."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$uri,
        [Parameter(
            Helpmessage = "API method to be used. GET, PUT, POST, or DELETE. Refer to documentation for the API endpoint to ensure the correct method is being used. If unspecified, defaults to GET"
        )]
        [ValidateSet("GET", "PUT", "POST", "DELETE")]
        [string]$method = "GET",
        [Parameter(
            Helpmessage = "Body to be submitted to the REST API endpoint. This needs to be submitted in JSON format"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$body

    )
    # While the API can use XML or JSON, this module is built on JSON functionality. Currently forcing all
    # content types and language to JSON.
    [string]$contentType = "application/json"

    # Check to see if the required variables are present and currently valid
    if ( -not ((Test-Path variable:script:zaLastActionTime) -and (Test-Path variable:script:zaHeaders)) ) {
        Throw "Zerto Analytics Connection does not Exist. Please run Connect-ZertoAnalytics first to establish a connection"
    } elseif ( (Test-Path variable:script:zaHeaders) -and $([datetime]$script:zaLastActionTime).addMinutes(60) -lt $(Get-Date) ) {
        Throw "Authorization Token has Expired. Please re-authorize to the Zerto Analytics Portal"
    } else {
        # Update the last action time and submit the request based on PS Version.
        Set-Variable -Name zaLastActionTime -Scope Script -Value $(Get-Date).Ticks
        $submittedUri = "https://analytics.api.zerto.com/v2/{0}" -f $uri
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            Invoke-RestMethod -Uri $submittedUri -Method $method -Body $body -Headers $Script:zaHeaders -ContentType $contentType -TimeoutSec 100
        } else {
            # With PS 5, you cannot ship a $null body, check for $body variable and select correct Invoke request.
            if ([String]::IsNullOrEmpty($body)) {
                Invoke-RestMethod -Uri $submittedUri -Method $method -Headers $Script:zaHeaders -ContentType $contentType -TimeoutSec 100
            } else {
                Invoke-RestMethod -Uri $submittedUri -Method $method -Headers $Script:zaHeaders -ContentType $contentType -TimeoutSec 100 -Body $body
            }
        }
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoEvacuateVra {
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "VraIdentifier")]
    param (
        # HostName Option
        [Parameter(
            Mandatory,
            HelpMessage = "Name of the Host to Evacuate",
            ParameterSetName = "HostName"
        )]
        [ValidateNotNullOrEmpty()]
        [String]$HostName,
        # VRA Option
        [Parameter(
            Mandatory,
            HelpMessage = "Name of the VRA to Evacuate",
            ParameterSetName = "VraName"
        )]
        [ValidateNotNullOrEmpty()]
        [String]$VraName,
        # VRAIdentifier Option
        [Parameter(
            Mandatory,
            HelpMessage = "Identifier of the VRA to be evacuated",
            ParameterSetName = "VraIdentifier",
            ValueFromPipelineByPropertyName,
            ValueFromPipeline
        )]
        [Alias("VraId", "Identifier")]
        [ValidateNotNullOrEmpty()]
        [String]$VraIdentifier
    )

    begin {

    }

    process {
        switch ($PSCmdlet.ParameterSetName) {
            "HostName" {
                $VraName = "Z-VRA-" + $HostName
                Invoke-ZertoEvacuateVra -VraName $VraName
            }

            "VraName" {
                $VraIdentifier = (Get-ZertoVra -vraName $VraName).VraIdentifier
                Invoke-ZertoEvacuateVra -VraIdentifier $VraIdentifier
            }

            "VraIdentifier" {
                $Uri = "vras/{0}/changerecoveryvra/execute" -f $VraIdentifier
                if ($PSCmdlet.ShouldProcess($VraIdentifier, "Evacuating VRA with Identifier:")) {
                    Invoke-ZertoRestRequest -Uri $Uri -Method "POST"
                }
            }
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoFailover {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        #TODO - Refactor?
        [Parameter(
            Mandatory,
            HelpMessage = "Name of the VPG to Failover"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            HelpMessage = "Checkpoint Identifier to use as the Point-In-Time to rollback to."
        )]
        [Alias("checkpointId")]
        [ValidateNotNullOrEmpty()]
        [string]$checkpointIdentifier,
        [Parameter(
            HelpMessage = "'Rollback': After the seconds specified in the commitValue setting have elapsed, the failover is rolled back.
            'Commit': After the seconds specified in the commitValue setting have elapsed, the failover continues, committing the virtual machines in the recovery site.
            'None': The virtual machines in the VPG being failed over remain in the Before Commit state until either they are committed with Commit a failover, or rolled back with Roll back a failover.
            Default is the Site Settings setting."

        )]
        [ValidateSet("Rollback", "Commit", "None")]
        [string]$commitPolicy = "Rollback",
        [Parameter(
            HelpMessage = "0: The protected virtual machines are not touched before starting the failover. -- DEFAULT
        1: If the protected virtual machines have VMware Tools or Microsoft Integration Services available, the virtual machines are gracefully shut down, otherwise the failover operation fails. This is similar to performing a Move operation to a specified checkpoint. This assumes that you do not have access to the protected virtual machines.
        2: The protected virtual machines are forcibly shut down before starting the failover. If the protected virtual machines have VMware Tools or Microsoft Integration Services available, the procedure waits five minutes for the virtual machines to be gracefully shut down before forcibly powering them off. This is similar to performing a Move operation to a specified checkpoint. This assumes that you do not have access to the protected virtual machines"

        )]
        [ValidateSet(0, 1, 2)]
        [int]$shutdownPolicy = 0,
        [Parameter(
            HelpMessage = "The amount of time in seconds the failover waits in a Before Commit state to enable checking that the failover is as required before performing the commitPolicy setting. Default is 60 Minutes (3600 Seconds)"
        )]
        # Min 5 Minutes, Max 24 Hours, Default 1 Hour.
        [ValidateRange(300, 86400)]
        [int]$timeToWaitBeforeShutdownInSec = 3600,
        [Parameter(
            HelpMessage = "True: Enable reverse protection. The virtual machines are recovered on the recovery site and then protected using the default reverse protection settings.
            False: Do not enable reverse protection. The VPG definition is kept with the status Needs Configuration and the reverse settings in the VPG definition are not set."

        )]
        [bool]$reverseProtection,
        [Parameter(
            HelpMessage = "Name(s) of VMs in the VPG to failover"
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmName
    )

    begin {
        $vpgId = $(Get-ZertoVpg -name $vpgName).vpgIdentifier
        if ( -not $vpgId) {
            Write-Error "VPG: $vpgName Not Found. Please check the name and try again!" -ErrorAction Stop
        }
        $baseUri = "vpgs/{0}/failover" -f $vpgId
        $body = @{ }
        # Setup Required Defaults
        $body['commitpolicy'] = $commitPolicy
        $body['TimeToWaitBeforeShutdownInSec'] = $timeToWaitBeforeShutdownInSec

        Switch ($PSBoundParameters.Keys) {
            "checkpointIdentifier" {
                $body['checkpointIdentifier'] = $checkpointIdentifier
            }

            "shutdownPolicy" {
                $body['shutdownPolicy'] = $shutdownPolicy
            }

            "reverseProtection" {
                $body['reverseProtection'] = $reverseProtection
            }

            "vmName" {
                $vpgVmInformation = Get-ZertoProtectedVm -vpgName $vpgName
                [System.Collections.ArrayList]$vmIdentifiers = @()
                foreach ( $name in $vmName ) {
                    $selectedVm = $vpgVmInformation | Where-Object { $_.VmName.toLower() -eq $name.toLower() }
                    if ($null -eq $selectedVm) {
                        Write-Error "VM: $name NOT found in VPG $vpgName. Check the name and try again." -ErrorAction Stop
                    } elseif ($vmIdentifiers.Contains($selectedVm.vmIdentifier.toString())) {
                        Write-Error "VM: $($selectedVm.VmName) specified more than once. Please check parameters and try again." -ErrorAction Stop
                    } else {
                        $vmIdentifiers.Add($selectedVm.vmIdentifier.toString()) | Out-Null
                    }
                }
                $body['VmIdentifiers'] = $vmIdentifiers
            }
        }
    }

    process {
        if ($PSCmdlet.ShouldProcess("$vpgName with identifier $vpgId and these options $($body | convertto-json)")) {
            Invoke-ZertoRestRequest -uri $baseUri -body $($body | ConvertTo-Json) -method "POST"
        }
    }

    end {
        # Nothing to do!
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoFailoverCommit {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            HelpMessage = "Name(s) of the VPG(s) to commit.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            HelpMessage = "Use this switch to reverse protect the VPG(s) to the source site."
        )]
        [switch]$reverseProtection
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        if ( $reverseProtection.IsPresent ) {
            $body = @{"IsReverseProtection" = $true }
        } else {
            $body = @{"IsReverseProtection" = $false }
        }
        foreach ($name in $vpgName) {
            $vpgId = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $vpgId ) {
                Write-Error "VPG: $name could not be found. Please check the name and try again. Skipping."
            } else {
                $uri = "{0}/{1}/FailoverCommit" -f $baseUri, $vpgId
                if ($PSCmdlet.ShouldProcess($body, $uri)) {
                    Invoke-ZertoRestRequest -uri $uri -body $($body | convertto-json) -method "POST"
                }
            }
        }
    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoFailoverRollback {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to roll back from failing over",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $vpgId = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $vpgId ) {
                Write-Error "VPG: $name not found. Please check the name and try again. Skipping"
            } else {
                $uri = "{0}/{1}/FailoverRollback" -f $baseUri, $vpgId
                Invoke-ZertoRestRequest -uri $uri -method "POST"
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoForceSync {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to force sync",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $id = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $id ) {
                Write-Error "VPG: $name not found. Please check the name and try again. Skipping"
            } else {
                $uri = "{0}/{1}/forcesync" -f $baseUri, $id
                Invoke-ZertoRestRequest -uri $uri -method "POST"
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoMove {
    [CmdletBinding( DefaultParameterSetName = "id", SupportsShouldProcess = $true )]
    param(
        [Parameter(
            ParameterSetName = 'name',
            HelpMessage = "Name(s) of the VPG(s) you want to move.",
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'commitName',
            HelpMessage = "Name(s) of the VPG(s) you want to move.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            ParameterSetName = 'id',
            HelpMessage = "ID(s) of the VPG(s) you want to move.",
            Mandatory,
            ValueFromPipelineByPropertyName
        )]
        [Parameter(
            ParameterSetName = 'commitId',
            HelpMessage = "ID(s) of the VPG(s) you want to move.",
            Mandatory,
            ValueFromPipelineByPropertyName
        )]
        [ValidateNotNullOrEmpty()]
        [guid[]]$vpgIdentifier,
        [Parameter(
            ParameterSetName = 'commitName',
            HelpMessage = "'Rollback': After the seconds specified in the commitValue setting have elapsed, the failover is rolled back.
            'Commit': After the seconds specified in the commitValue setting have elapsed, the failover continues, committing the virtual machines in the recovery site.
            'None': The virtual machines in the VPG being failed over remain in the Before Commit state until either they are committed with Commit a failover, or rolled back with Roll back a failover.
            Default is the Site Settings setting."
,
            Mandatory
        )]
        [Parameter(
            ParameterSetName = 'commitId',
            HelpMessage = "'Rollback': After the seconds specified in the commitValue setting have elapsed, the failover is rolled back.
            'Commit': After the seconds specified in the commitValue setting have elapsed, the failover continues, committing the virtual machines in the recovery site.
            'None': The virtual machines in the VPG being failed over remain in the Before Commit state until either they are committed with Commit a failover, or rolled back with Roll back a failover.
            Default is the Site Settings setting."
,
            Mandatory
        )]
        [ValidateSet("Rollback", "Commit", "None")]
        [string]$commitPolicy,
        [Parameter(
            ParameterSetName = 'commitName',
            HelpMessage = "The amount of time, in seconds, the Move is in a 'Before Commit' state, before performing the commitPolicy setting. If omitted, the site settings default will be applied."
        )]
        [Parameter(
            ParameterSetName = 'commitId',
            HelpMessage = "The amount of time, in seconds, the Move is in a 'Before Commit' state, before performing the commitPolicy setting. If omitted, the site settings default will be applied."
        )]
        # Min 5 Minutes, Max 24 Hours, Default Site Settigns.
        [ValidateRange(300, 86400)]
        [Int]$commitPolicyTimeout,
        [Parameter(
            HelpMessage = "If this switch is specified, Zerto will attempt to gracefully shut down the Virtual Machines. If the machines do not poweroff within 5 minutes, they will be forcibly powering them off."
        )]
        [switch]$forceShutdown,
        [Parameter(
            HelpMessage = "Do not enable reverse protection. The VPG definition is kept with the status Needs Configuration and the reverse settings in the VPG definition are not set."
        )]
        [switch]$disableReverseProtection,
        [Parameter(
            HelpMessage = "Prevent the protected virtual machines from being deleted in the protected site. Using this setting disables reverse protection."
        )]
        [switch]$keepSourceVms,
        [Parameter(
            HelpMessage = "Continue the Move operation in case of failure of script executing prior the operation. If this switch is not set a failure of the script executing prior to the operation will cause the operation to fail."
        )]
        [switch]$ContinueOnPreScriptFailure
    )

    begin {
        $baseUri = "vpgs"
        $body = @{
            forceShutdown              = $forceShutdown.IsPresent
            ContinueOnPreScriptFailure = $ContinueOnPreScriptFailure.IsPresent
            keepSourceVms              = $keepSourceVms.IsPresent
            reverseProtection          = -not $disableReverseProtection.IsPresent
        }

        if ( $keepSourceVms.IsPresent -and -not $disableReverseProtection.IsPresent ) {
            Write-Verbose 'Disabling reverse protection as keepSourceVms requires it'
            $body['reverseProtection'] = $false
        }

        if ($PSBoundParameters.ContainsKey('commitPolicy')) {
            $body['commitPolicy'] = $commitPolicy
            if ($PSBoundParameters.ContainsKey('commitPolicyTimeout')) {
                $body['commitPolicyTimeout'] = $commitPolicyTimeout
            }
        }
    }

    process {

        switch ($PSCmdlet.ParameterSetName) {
            { $_ -in 'name', 'commitName' } {
                $vpgIds = foreach ($name in $vpgName) {
                    $vpgId = $(Get-ZertoVpg -name $name).vpgIdentifier
                    if ( -not $vpgId ) {
                        Write-Error "VPG: '$name' not found. Please check the name and try again. Skipping"
                    } else {
                        Write-Verbose "VPG: $name, ID: $vpgId"
                        $vpgId
                    }
                }
            }

            { $_ -in 'id', 'commitId' } {
                $vpgIds = $vpgIdentifier
            }
        }

        foreach ($thisId in $vpgIds) {
            $uri = "{0}/{1}/move" -f $baseUri, $thisId
            if ($PSCmdlet.ShouldProcess("Moving VPG: $thisId with settings: $($body | ConvertTo-Json)")) {
                Invoke-ZertoRestRequest -uri $uri -method "POST" -body $($body | ConvertTo-Json)
            }
        }
    }

    end {
        # Nothing to do.
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoMoveCommit {
    [cmdletbinding(SupportsShouldProcess = $true, DefaultParameterSetName = "Main")]
    param(
        [Parameter(
            HelpMessage = "Name(s) of the VPG(s) to commit.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            HelpMessage = "Use this switch to reverse protect the VPG(s) to the source site. If neither 'ReverseProtction' nor 'KeepSourceVms' switch is specified, the commit process will use selection made during move initiation.",
            ParameterSetName = 'ReverseProtect',
            Mandatory

        )]
        [switch]$reverseProtection,
        [Parameter(
            HelpMessage = "Use this switch to keep the source VMs at the source site. If neither 'ReverseProtction' nor 'KeepSourceVms' switch is specified, the commit process will use selection made during move initiation.",
            ParameterSetName = 'KeepSource',
            Mandatory
        )]
        [switch]$keepSourceVms
    )

    begin {
        $baseUri = "vpgs"
        $body = @{ }
        Switch ($PSCmdlet.ParameterSetName){
            'KeepSource' {
                $body["KeepSourceVms"] = $true
                $body["ReverseProtection"] = $false
            }

            'ReverseProtect' {
                $body["ReverseProtection"] = $true
                $body["KeepSourceVms"] = $false
            }
        }
    }

    process {
        foreach ($name in $vpgName) {
            $vpgId = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $vpgId ) {
                Write-Error "VPG: $name not found. Please check the name and try again. Skipping."
            } else {
                $uri = "{0}/{1}/MoveCommit" -f $baseUri, $vpgId
                if ($PSCmdlet.ShouldProcess("Commiting VPG: $name with settings $($body | convertto-json)")) {
                    Invoke-ZertoRestRequest -uri $uri -body $($body | convertto-json) -method "POST"
                }
            }
        }
    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoMoveRollback {
    [cmdletbinding(SupportsShouldProcess = $true)]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to roll back from failing over",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $id = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $id ) {
                Write-Error "VPG: $name not found. Please check the name and try again."
            } else {
                $uri = "{0}/{1}/moveRollBack" -f $baseUri, $id
                if ($PSCmdlet.ShouldProcess("Rolling back VPG: $name")) {
                    Invoke-ZertoRestRequest -uri $uri -method "POST"
                }
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Invoke-ZertoRestRequest {
    [cmdletbinding()]
    param(
        # Parameter help description
        [Parameter(
            Helpmessage = "API method to be used. GET, PUT, POST, or DELETE. Refer to documentation for the API endpoint to ensure the correct method is being used. If unspecified, defaults to GET"
        )]
        [ValidateSet("GET", "PUT", "POST", "DELETE")]
        [string]$method = "GET",
        [Parameter(
            Mandatory,
            Helpmessage = "URI endpoint to be utilized. When submitting the URI, only the endpoint needs to be submitted. Please review the help documentation for examples."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$uri,
        [Parameter(
            Helpmessage = "Body to be submitted to the REST API endpoint. This needs to be submitted in JSON format"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$body,
        [Parameter(
            Helpmessage = "PSCredential object. This is ONLY used when authenticating with the ZVM. No other endpoints require this and generally is not used."
        )]
        [PSCredential]$credential,
        [Parameter(
            Helpmessage = "Use this switch if you would like the request headers returned along with the body. Useful for troubleshooting to get HTTP error codes."
        )]
        [switch]$returnHeaders
    )
    # API version. Currently this is locked at v1 in all versions of Zerto. Should this change, will look
    # at making this as parameter to be selected during function call.
    $apiVersion = "v1"
    # While the API can use XML or JSON, this module is built on JSON functionality. Currently forcing all
    # content types and language to JSON.
    $contentType = "application/json"
    $callerErrorActionPreference = $ErrorActionPreference
    # If the ZVM server and Port not defined, Stop Call
    if ( -not ((Test-Path variable:script:zvmServer) -and (Test-Path variable:script:zvmPort)) ) {
        Throw "Zerto Connection does not Exist. Please run Connect-ZertoServer first to establish a connection"
    }

    # If the Headers exist and the Last action was more than 30 minutes ago, Session is Expired
    if ( (Test-Path variable:script:zvmHeaders) -and $([datetime]$script:zvmLastAction).addMinutes(30) -lt $(Get-Date) -and $Script:Reconnect -eq $False ) {
        Throw "Authorization Token has Expired. Please re-authorize to the Zerto Virtual Manager"
    } elseif (( (Test-Path variable:script:zvmHeaders) -and $([datetime]$script:zvmLastAction).addMinutes(30) -lt $(Get-Date) -and $Script:Reconnect -eq $True )) {
        Write-Verbose "Authorization had expired. Attempting Reauthorization."
        Connect-ZertoServer -zertoServer $Script:zvmServer -zertoPort $script:zvmPort -credential $Script:CachedCredential
    }# else {
    # Build the URI to be submitted
    $submittedURI = "https://{0}:{1}/{2}/{3}" -f $script:zvmServer, $script:zvmPort, $apiVersion, $uri
    try {
        # Set the zvmLastAction time and try to submit the REST Request
        $script:zvmLastAction = (Get-Date).Ticks
        # If running PwSh - Use this Invoke-RestMethod with passed Variables
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            $apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -Body $body -ContentType $contentType -Credential $credential -SkipCertificateCheck -ResponseHeadersVariable responseHeaders -TimeoutSec 100
        } else {
            # If running PowerShell 5.1 --> Do the Following
            # Check to see if All Certs are Trusted. If not, Create the Policy to Trust All Certificates
            if ([System.Net.ServicePointManager]::CertificatePolicy.GetType().Name -ne "TrustAllCertsPolicy") {
                Try {
                    $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;
    }
}
'@

                    Add-Type -TypeDefinition $type -ErrorAction SilentlyContinue
                } Catch {
                    if ($error[0].Exception -ne "Cannot add type. The type name 'TrustAllCertsPolicy already exists.") {
                        Write-Debug $error[0]
                    }
                }
                [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

            }
            # If we are authenticating to the ZVM, Use this block to use Invoke-WebRequest and format the Headers as expected.
            if ($uri -eq "session/add" -and $method -eq "POST") {
                $apiRequestResults = Invoke-WebRequest -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -Body $body -ContentType $contentType -Credential $credential -TimeoutSec 100
                $responseHeaders = @{ }
                $responseHeaders['x-zerto-session'] = @($apiRequestResults.Headers['x-zerto-session'])
            } elseif ($method -ne "GET") {
                # If the Method is something other than 'GET' use this call with a body parameter
                $apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -Body $body -ContentType $contentType -Credential $credential -TimeoutSec 100
            } else {
                # If the Method we are calling is 'GET' use this call without a body parameter
                $apiRequestResults = Invoke-RestMethod -Uri $submittedURI -Headers $script:zvmHeaders -Method $method -ContentType $contentType -Credential $credential -TimeoutSec 100
            }
        }
    } catch {
        # If an error is encountered, Catch
        Write-Error -ErrorRecord $_ -ErrorAction $callerErrorActionPreference
    }

    # If the calling function does not need the headers (Default Action) return the results of the API Call
    if (-not $returnHeaders) {
        return $apiRequestResults
    } else {
        #If Headers are required, build a PS Custom Object with the Results and the Headers
        $apiRequestAndHeaderResults = New-Object -TypeName psobject
        $apiRequestAndHeaderResults | Add-Member -MemberType NoteProperty -Name "apiRequestResults" -Value $apiRequestResults
        $apiRequestAndHeaderResults | Add-Member -MemberType NoteProperty -Name "Headers" -Value $responseHeaders
        return $apiRequestAndHeaderResults
        #}
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function New-ZertoPairingToken {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (

    )

    begin {

    }

    process {
        $uri = "peersites/generatetoken"
        $body = @{ }
        if ($PSCmdlet.ShouldProcess("Obtaining Pairing token from $script:zvmServer")) {
            Invoke-ZertoRestRequest -uri $uri -method "POST" -body $($body | ConvertTo-Json)
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function New-ZertoVpg {
    [cmdletbinding(SupportsShouldProcess = $true, DefaultParameterSetName = "recoveryHostDatastore")]
    param(
        [Parameter(
            HelpMessage = "Name of the VPG",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            HelpMessage = "VPG Priority. High, Medium, or Low. Default value is Medium"
        )]
        [ValidateSet("High", "Medium", "Low")]
        [string]$vpgPriority = "Medium",
        [Parameter(
            HelpMessage = "Journal History in Hours. Min 1 hour, Max 720 Hours (30 days). Default value is 24 hours"
        )]
        [ValidateRange(1, 720)]
        [int]$journalHistoryInHours = 24,
        [Parameter(
            HelpMessage = "Name(s) of the VM(s) to be protected.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$protectedVm,
        [Parameter(
            HelpMessage = "Name of the site where the VM(s) will be recovered",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoverySite,
        [Parameter(
            HelpMessage = "Name of the cluster where the VM(s) will be recovered.",
            ParameterSetName = "recoveryClusterDatastore",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the cluster where the VM(s) will be recovered.",
            ParameterSetName = "recoveryClusterDatastoreCluster",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryCluster,
        [Parameter(
            HelpMessage = "Name of the host where the VM(s) will be recovered.",
            ParameterSetName = "recoveryHostDatastore",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the host where the VM(s) will be recovered.",
            ParameterSetName = "recoveryHostDatastoreCluster",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryHost,
        [Parameter(
            HelpMessage = "Name of the resource pool where the VM(s) will be recovered.",
            ParameterSetName = "recoveryResourcePoolDatastore",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the resource pool where the VM(s) will be recovered.",
            ParameterSetName = "recoveryResourcePoolDatastoreCluster",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryResourcePool,
        [Parameter(
            HelpMessage = "Name of the datastore where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryClusterDatastore",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the datastore where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryHostDatastore",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the datastore where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryResourcePoolDatastore",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastore,
        [Parameter(
            HelpMessage = "Name of the datastore cluster where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryClusterDatastoreCluster",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the datastore cluster where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryHostDatastoreCluster",
            Mandatory
        )]
        [Parameter(
            HelpMessage = "Name of the datastore cluster where the VM(s), Volume(s), and Journal(s) will reside.",
            ParameterSetName = "recoveryResourcePoolDatastoreCluster",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreCluster,
        [Parameter(
            HelpMessage = "Name of folder at recovery location where the recovered virtual machine(s) will be created.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$recoveryFolder,
        [Parameter(
            HelpMessage = "RPO alert"
        )]
        [ValidateRange(60, 864200)]
        [Int32]$rpoInSeconds = 300,
        [Parameter(
            HelpMessage = "Minimum test interval for this VPG. Valid values are 0: Off, 43200: 1 Month, 131040: 3 Months, 262080: 6 Months, 294560: 9 Months, 252600: 12 Months"
        )]
        [ValidateSet(0, 43200, 131040, 262080, 294560, 252600)]
        [int]$testIntervalInMinutes = 262080,
        [Parameter(
            HelpMessage = "Service profile name to use."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$serviceProfile,
        [Parameter(
            HelpMessage = "Turn on or off WAN and Journal Compression. Default is turned on."
        )]
        [bool]$useWanCompression = $true,
        [Parameter(
            HelpMessage = "Name of ZORG to use."
        )]
        [ValidateNotNullOrEmpty()]
        [String]$zorg,
        [Parameter(
            HelpMessage = "Name of the network to use during a Failover Live \ Move VPG operation.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [String]$recoveryNetwork,
        [Parameter(
            HelpMessage = "Name of the network to use during a Failover Test operation",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$testNetwork,
        [Parameter(
            HelpMessage = "Name of the datastore to utilize to store Journal data. If not specified, the default datastore will be used.",
            Mandatory = $false
        )]
        [ValidateNotNullOrEmpty()]
        [string]$journalDatastore,
        [Parameter(
            HelpMessage = "Default journal hard limit in megabytes. Default set to 153600 MB (150 GB). Set to 0 to set the journal to unlimited",
            Mandatory = $false
        )]
        [ValidateNotNullOrEmpty()]
        [uint64]$journalHardLimitInMb = 153600,
        [Parameter(
            HelpMessage = "Default journal warning threshold in megabytes. If unset or greater than the hard limit, will be set to 75% of the journal hard limit.",
            Mandatory = $false
        )]
        [ValidateNotNullOrEmpty()]
        [uint64]$journalWarningThresholdInMb = 0
    )

    begin {
        # Create an identifiers table, and start converting names to identifiers.
        $identifiersTable = @{ }
        $identifiersTable['recoverySiteIdentifier'] = Get-ZertoVirtualizationSite | Where-Object { $_.VirtualizationSiteName -like $recoverySite } | Select-Object -ExpandProperty SiteIdentifier
        $peerSiteNetworks = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -networks)
        $identifiersTable['failoverNetworkIdentifier'] = $peerSiteNetworks | Where-Object { $_.VirtualizationNetworkName -like $recoveryNetwork } | Select-Object -ExpandProperty NetworkIdentifier
        $identifiersTable['testNetworkIdentifier'] = $peerSiteNetworks | Where-Object { $_.VirtualizationNetworkName -like $testNetwork } | Select-Object -ExpandProperty NetworkIdentifier
        $identifiersTable['folderIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -folders | Where-Object { $_.FolderName -like $recoveryFolder }).folderIdentifier
        if ($PSBoundParameters.ContainsKey("zorg")) {
            $identifiersTable['zorgIdentifier'] = $(Get-ZertoZorg | Where-Object { $_.ZorgName -like $zorg }).ZorgIdentifier
        }
        if ($PSBoundParameters.ContainsKey("serviceProfile")) {
            $identifiersTable['serviceProfileIdentifier'] = $(Get-ZertoServiceProfile -siteIdentifier $identifiersTable['recoverySiteIdentifier'] | Where-Object { $_.ServiceProfileName -like $serviceProfile }).serviceProfileIdentifier
        }
        if ($PSBoundParameters.ContainsKey('journalDatastore')) {
            $identifiersTable['journalDatastore'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastores | Where-Object { $_.DatastoreName -like $journalDatastore }).DatastoreIdentifier
        }
        # Get identifiers based on parameter set name
        switch ($PSCmdlet.ParameterSetName) {
            "recoveryClusterDatastoreCluster" {
                $identifiersTable['clusterIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -hostClusters | Where-Object { $_.VirtualizationClusterName -like $recoveryCluster }).ClusterIdentifier
                $identifiersTable['datastoreClusterIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastoreClusters | Where-Object { $_.DatastoreClusterName -like $datastoreCluster }).DatastoreClusterIdentifier
            }

            "recoveryClusterDatastore" {
                $identifiersTable['clusterIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -hostClusters | Where-Object { $_.VirtualizationClusterName -like $recoveryCluster }).ClusterIdentifier
                $identifiersTable['datastoreIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastores | Where-Object { $_.DatastoreName -like $datastore }).DatastoreIdentifier
            }

            "recoveryHostDatastoreCluster" {
                $identifiersTable['recoveryHostIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -hosts | Where-Object { $_.VirtualizationHostName -like $recoveryHost }).HostIdentifier
                $identifiersTable['datastoreClusterIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastoreClusters | Where-Object { $_.DatastoreClusterName -like $datastoreCluster }).DatastoreClusterIdentifier
            }

            "recoveryHostDatastore" {
                $identifiersTable['recoveryHostIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -hosts | Where-Object { $_.VirtualizationHostName -like $recoveryHost }).HostIdentifier
                $identifiersTable['datastoreIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastores | Where-Object { $_.DatastoreName -like $datastore }).DatastoreIdentifier
            }

            "recoveryResourcePoolDatastoreCluster" {
                $identifiersTable['recoveryResourcePoolIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -resourcePools | Where-Object { $_.ResourcePoolName -like $recoveryResourcePool }).ResourcePoolIdentifier
                $identifiersTable['datastoreClusterIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastoreClusters | Where-Object { $_.DatastoreClusterName -like $datastoreCluster }).DatastoreClusterIdentifier
            }

            "recoveryResourcePoolDatastore" {
                $identifiersTable['recoveryResourcePoolIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -resourcePools | Where-Object { $_.ResourcePoolName -like $recoveryResourcePool }).ResourcePoolIdentifier
                $identifiersTable['datastoreIdentifier'] = $(Get-ZertoVirtualizationSite -siteIdentifier $identifiersTable['recoverySiteIdentifier'] -datastores | Where-Object { $_.DatastoreName -like $datastore }).DatastoreIdentifier
            }
        }
        $unprotectedVms = Get-ZertoUnprotectedVm
        $protectedVms = Get-ZertoProtectedVm
        # Create array of VM identifiers
        $vmIdentifiers = foreach ($vm in $protectedVm) {
            # If the VM is unprotected, get the identifier
            $vmIdentifier = $unprotectedVms | Where-Object { $_.vmName -like $vm } | Select-Object -ExpandProperty vmIdentifier
            # If the VM is not unprotected, check the protected VMs
            if ( -not $vmIdentifier) {
                # Get all identifiers to test if the VM is eligible to be a member of an additional VPG
                $results = $protectedVms | Where-Object { $_.VmName -like $vm } | Select-Object -ExpandProperty vmIdentifier
                # If VM is currently a member of 3 VPGs, skip it. If it cannot be found, skip it. Otherwise, set the identifier
                if ($results.count -eq 3) {
                    Write-Warning "$vm is already a part of 3 VPGs and cannot be part of an additional VPG. Skipping $vm"
                    continue
                } elseif ($results.count -eq 0) {
                    Write-Warning "$vm not found. Skipping $vm"
                    continue
                } else {
                    $vmIdentifier = $results | Select-Object -First 1
                }
            }
            # Create a custom object to store the information to easily convert to JSON. Return to vmIdentifiers array.
            $returnObject = New-Object PSObject
            $returnObject | Add-Member -MemberType NoteProperty -Name "VmIdentifier" -Value $vmIdentifier
            $returnObject
        }
        if (($journalWarningThresholdInMb -eq 0) -or ($journalWarningThresholdInMb -gt $journalHardLimitInMb)) {
            $journalWarningThresholdInMb = $journalHardLimitInMb * .75
        }

        #Validate all items in the hashtable are populated with valid data.
        $validSettings = $true
        foreach ($item in $identifiersTable.GetEnumerator()) {
            if ([String]::IsNullOrEmpty($item.value)) {
                $validSettings = $false
                Write-Error "$($item.key) is not associated with a valid identifier. Please check the submitted values and try again."
            }
        }
        if ($vmIdentifiers.count -eq 0) {
            $validSettings = $false
            Write-Error "No valid VM names were passed or all passed VMs are already protected and cannot be further protected."
        }

        if ( -not $validSettings ) {
            Write-Error "One or more parameters passed do not have valid identifiers or 0 valid VMs were found. Please check your settings and try again." -ErrorAction Stop
        }
    }

    process {
        $baseUri = "vpgsettings"
        # Create a VPG Settings Identifier
        $vpgSettingsIdentifier = New-ZertoVpgSettingsIdentifier -newVpg
        # Put base settings into an object easy to manipulate
        $baseSettings = Get-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsIdentifier
        # Set settings equal to passed and default parameters
        $baseSettings.basic.name = $vpgName
        $baseSettings.basic.journalHistoryInHours = $journalHistoryInHours
        $baseSettings.basic.Priority = $vpgPriority
        $baseSettings.basic.recoverySiteIdentifier = $identifiersTable['recoverySiteIdentifier']
        $baseSettings.basic.RpoInSeconds = $rpoInSeconds
        if ($identifiersTable.ContainsKey('serviceProfileIdentifier')) {
            $baseSettings.basic.ServiceProfileIdentifier = $identifiersTable['serviceProfileIdentifier']
        }
        $baseSettings.basic.TestIntervalInMinutes = $testIntervalInMinutes
        $baseSettings.basic.useWanCompression = $useWanCompression
        if ($identifiersTable.ContainsKey('zorgIdentifier')) {
            $baseSettings.basic.ZorgIdentifier = $identifiersTable['zorgIdentifier']
        }
        $baseSettings.Networks.Failover.Hypervisor.DefaultNetworkIdentifier = $identifiersTable['failoverNetworkIdentifier']
        $baseSettings.Networks.FailoverTest.Hypervisor.DefaultNetworkIdentifier = $identifiersTable['testNetworkIdentifier']
        $baseSettings.Recovery.DefaultFolderIdentifier = $identifiersTable['folderIdentifier']
        switch ($PSCmdlet.ParameterSetName) {
            "recoveryClusterDatastoreCluster" {
                $baseSettings.Recovery.DefaultDatastoreClusterIdentifier = $identifiersTable['datastoreClusterIdentifier']
                $baseSettings.Recovery.DefaultHostClusterIdentifier = $identifiersTable['clusterIdentifier']
            }

            "recoveryClusterDatastore" {
                $baseSettings.Recovery.DefaultHostClusterIdentifier = $identifiersTable['clusterIdentifier']
                $baseSettings.Recovery.DefaultDatastoreIdentifier = $identifiersTable['datastoreIdentifier']
            }

            "recoveryHostDatastoreCluster" {
                $baseSettings.Recovery.DefaultDatastoreClusterIdentifier = $identifiersTable['datastoreClusterIdentifier']
                $baseSettings.Recovery.DefaultHostIdentifier = $identifiersTable['recoveryHostIdentifier']
            }

            "recoveryHostDatastore" {
                $baseSettings.Recovery.DefaultHostIdentifier = $identifiersTable['recoveryHostIdentifier']
                $baseSettings.Recovery.DefaultDatastoreIdentifier = $identifiersTable['datastoreIdentifier']
            }

            "recoveryResourcePoolDatastoreCluster" {
                $baseSettings.Recovery.ResourcePoolIdentifier = $identifiersTable['recoveryResourcePoolIdentifier']
                $baseSettings.Recovery.DefaultDatastoreClusterIdentifier = $identifiersTable['datastoreClusterIdentifier']
            }

            "recoveryResourcePoolDatastore" {
                $baseSettings.Recovery.ResourcePoolIdentifier = $identifiersTable['recoveryResourcePoolIdentifier']
                $baseSettings.Recovery.DefaultDatastoreIdentifier = $identifiersTable['datastoreIdentifier']
            }
        }
        $basesettings.Vms += $vmIdentifiers
        if ($identifiersTable.ContainsKey('journalDatastore')) {
            $baseSettings.Journal.DatastoreIdentifier = $identifiersTable['journalDatastore']
        }
        $baseSettings.Journal.Limitation.HardLimitInMB = $journalHardLimitInMb
        $baseSettings.Journal.Limitation.WarningThresholdInMB = $journalWarningThresholdInMb
        $settingsURI = "{0}/{1}" -f $baseUri, $vpgSettingsIdentifier
        if ($PSCmdlet.ShouldProcess($($baseSettings | ConvertTo-Json -Depth 10))) {
            $results = Invoke-ZertoRestRequest -uri $settingsURI -body $($baseSettings | ConvertTo-Json -Depth 10) -method "PUT"
        }
    }

    end {
        # Return vpgSettings Identifier as a string to pass into Save function.
        return $vpgSettingsIdentifier.toString()
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function New-ZertoVpgSettingsIdentifier {
    [cmdletbinding( SupportsShouldProcess = $true, DefaultParameterSetName = "newVpg" )]
    param(
        [Parameter(
            HelpMessage = "Identifier of the VPG to create a VPG settings identifier. If a vpgIdentifier is not provided, a new VPG settings object is created without any configured settings. This would be used for creating a new VPG from scratch.",
            ParameterSetName = "existingVpg",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId")]
        [string[]]$vpgIdentifier,
        [Parameter(
            HelpMessage = "Use this switch when creating a vpgSettingsIdentifier for a new VPG",
            ParameterSetName = "newVpg",
            Mandatory
        )]
        [switch]$newVpg
    )

    begin {
        $baseUri = "vpgSettings"
    }

    process {
        switch ($PSCmdlet.ParameterSetName) {
            "newVpg" {
                $body = "{}"
                if ($PSCmdlet.ShouldProcess("Creating VPG Settings Object")) {
                    Invoke-ZertoRestRequest -uri $baseUri -body $body -Method "POST"
                }
            }
            "existingVpg" {
                foreach ($id in $vpgIdentifier) {
                    $body = "{""VpgIdentifier"":""$id""}"
                    if ($PSCmdlet.ShouldProcess("Creating VPG Settings Object")) {
                        Invoke-ZertoRestRequest -uri $baseUri -body $body -Method "POST"
                    }
                }
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Remove-ZertoPeerSite {
    [cmdletbinding(
        SupportsShouldProcess = $true,
        DefaultParameterSetName = "siteIdentifier"
    )]
    param (
        [Parameter(
            HelpMessage = "Identifier of the site to be removed from the connected site",
            ParameterSetName = "siteIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("siteId")]
        [string[]]$siteIdentifier,
        [Parameter(
            HelpMessage = "Name of the peer site to be removed from the connected site",
            ParameterSetName = "peerSiteName",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$peerSiteName,
        [Parameter(
            HelpMessage = "IP address of the peer site to be removed from the connected site",
            ParameterSetName = "hostName",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory
        )]
        [ValidateScript( { $_ -match [IPAddress]$_ })]
        [string[]]$hostName,
        [Parameter(
            HelpMessage = "Specify this switch to Keep the target replica disks for any VPGs replicating between the sites as the VPGs will be deleted by unpairing the sites. If this switch is not used, the target replica disks will be deleted"
        )]
        [switch]$keepTargetDisks
    )

    begin {
        $baseUri = "peersites"
        $body = @{ }
        if ( $keepTargetDisks ) {
            $body['IsKeepTargetDisks'] = $true
        } else {
            $body['IsKeepTargetDisks'] = $false
        }
    }

    process {
        switch ( $PSCmdlet.ParameterSetName ) {
            "peerSiteName" {
                $siteIdentifier = @()
                $siteIdentifier = foreach ($site in $peerSiteName) {
                    $(Get-ZertoPeerSite -peerName $site).siteIdentifier
                }
            }

            "hostName" {
                $siteIdentifier = @()
                $siteIdentifier = foreach ($name in $hostName) {
                    $(Get-ZertoPeerSite -hostName $name).siteIdentifier
                }
            }
        }

        foreach ($id in $siteIdentifier) {
            $uri = "{0}/{1}" -f $baseUri, $id
            if ($PSCmdlet.ShouldProcess("Removing siteIdentifier $id")) {
                Invoke-ZertoRestRequest -uri $uri -body $($body | ConvertTo-Json) -Method "DELETE"
            }
        }

    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Remove-ZertoVpg {
    [cmdletbinding( SupportsShouldProcess = $true, DefaultParameterSetName = "vpgIdentifier" )]
    param(
        [Parameter(
            Mandatory,
            ParameterSetName = "vpgName",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "Name(s) of the VPG(s) to delete."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            Mandatory,
            ParameterSetName = "vpgIdentifier",
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "vpgIdentifier(s) of the VPG(s) to delete."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("vpgId")]
        [string[]]$vpgidentifier,
        [Parameter(
            HelpMessage = "Use this parameter to keep the recovery volumes at the target site, by setting it to True. If the virtual machines in the deleted VPG are reprotected, these volumes can be used as preseeded volumes to speed up the initial synchronization of the new VPG. Default is to remove Recovery Volumes"
        )]
        [switch]$keepRecoveryVolumes,
        [Parameter(
            HelpMessage = "Use this parameter to force delete the VPG, by setting this parameter equal to true."
        )]
        [switch]$force
    )

    begin {
        $baseUri = "vpgs"
        $body = @{ }
        if ($keepRecoveryVolumes) {
            $body['KeepRecoveryVolumes'] = $True
        } else {
            $body['KeepRecoveryVolumes'] = $False
        }
        if ($force) {
            $body['force'] = $True
        } else {
            $body['force'] = $False
        }
    }

    process {
        switch ($PSCmdlet.ParameterSetName) {
            "vpgName" {
                foreach ($name in $vpgName) {
                    $id = $(get-zertovpg -name $name).vpgIdentifier
                    if ($id) {
                        $uri = "{0}/{1}" -f $baseUri, $id
                        if ($PSCmdlet.ShouldProcess( $name + " and these settings: " + $($body | ConvertTo-Json) ) ) {
                            Invoke-ZertoRestRequest -uri $uri -body $($body | ConvertTo-Json) -Method "DELETE"
                        }
                    } else {
                        Write-Error "VPG with name $vpgName not found. Please check the name and try again"
                    }
                }
            }

            "vpgIdentifier" {
                foreach ($id in $vpgIdentifier) {
                    $uri = "{0}/{1}" -f $baseUri, $id
                    if ($PSCmdlet.ShouldProcess( $id + " and these settings: " + $($body | ConvertTo-Json) ) ) {
                        Invoke-ZertoRestRequest -uri $uri -body $($body | ConvertTo-Json) -Method "DELETE"
                    }
                }
            }
        }
    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Remove-ZertoVpgSettingsIdentifier {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        # Settings Identifier to Remove
        [Parameter(HelpMessage = "VpgSettingsIdentifier to Delete", Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $vpgSettingsIdentifier
    )

    begin {
    }

    process {
        foreach ($id in $vpgSettingsIdentifier) {
            if ($PSCmdlet.ShouldProcess($id)) {
                $uri = "vpgSettings/{0}" -f $id
                Invoke-ZertoRestRequest -uri $uri -method "DELETE"
            }
        }
    }

    end {
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Remove-ZertoVpgVm {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")]
    param (
        [Parameter(
            Mandatory,
            HelpMessage = "Name of the VPG that contains the VM you wish to remove",
            ParameterSetName = "VpgName"
        )]
        [ValidateNotNullOrEmpty()]
        [String]$VpgName,
        [Parameter(
            Mandatory,
            HelpMessage = "Name of VM(s) to remove from the VPG"
        )]
        [ValidateNotNullOrEmpty()]
        [String[]]$Vm
    )

    begin {

    }

    process {
        $VpgData = Get-ZertoVpg -vpgName $VpgName
        if (-not $VpgData) {
            Write-Error "Unable to find Vpg with name $VpgName. Please check your parameters and try again." -ErrorAction Stop
        } else {
            $protectedVms = Get-ZertoProtectedVm -vpgName $VpgData.VpgName
        }
        $VmIdentifiers = foreach ($machine in ($vm | Select-Object -Unique)) {
            if ($machine -in $protectedVms.VmName) {
                $protectedVms.Where( { $_.VmName -like $machine }) | Select-Object -ExpandProperty VmIdentifier
            } else {
                Write-Warning "Virtual Machine: '$machine' is not found in Vpg: '$VpgName'. Check your parameters. Skipping $machine"
            }
        }
        if ($VmIdentifiers.Count -gt 0 -and $PSCmdlet.ShouldProcess(($Vm | Select-Object -Unique), "Removing VM(s): $($Vm | Select-Object -Unique) from Vpg $VpgName")) {
            $vpgSettingsIdentifier = New-ZertoVpgSettingsIdentifier -vpgIdentifier $VpgData.VpgIdentifier
            foreach ($identifier in $VmIdentifiers) {
                $url = "vpgSettings/{0}/vms/{1}" -f $vpgSettingsIdentifier, $identifier
                Invoke-ZertoRestRequest -uri $url -method DELETE
            }
            Save-ZertoVpgSetting -vpgSettingsIdentifier $vpgSettingsIdentifier
        } else {
            Write-Warning "No VMs found to remove. Please check your parameters and try again."
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Resume-ZertoVpg {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to resume replication",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $id = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $id ) {
                Write-Error "VPG: $name not found. Please check the name and try again. Skipping."
            } else {
                $uri = "{0}/{1}/resume" -f $baseUri, $id
                Invoke-ZertoRestRequest -uri $uri -method "POST"
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Save-ZertoVpgSetting {
    [cmdletbinding(
        SupportsShouldProcess = $true
    )]
    param(
        [Parameter(
            HelpMessage = "VpgSettings Identifier to save",
            Mandatory,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("sid", "settingsIdentifier", "vpgSettingsId")]
        [string]$vpgSettingsIdentifier
    )

    Begin {
    }

    Process {
        $baseUri = "vpgsettings/{0}/commit" -f $vpgSettingsIdentifier
        if ($PSCmdlet.ShouldProcess("Commiting VPG Settings with Settigns identifier $vpgSettingsIdentifier")) {
            Invoke-ZertoRestRequest -uri $baseUri -method "POST"
        }
    }

    End {
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Set-ZertoAlert {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param (
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory,
            HelpMessage = "Alert identifier(s) to be dismissed or undismissed."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("alertIdentifier", "identifier", "id")]
        [string[]]$alertId,
        [Parameter(
            ParameterSetName = "dismiss",
            Mandatory,
            HelpMessage = "Will dismiss the selected alert."
        )]
        [switch]$dismiss,
        [Parameter(
            ParameterSetName = "undismiss",
            Mandatory,
            HelpMessage = "Will undismiss the selected alert."
        )]
        [switch]$undismiss
    )

    begin {
        $baseUri = "alerts"
    }

    process {
        foreach ($id in $alertId) {
            $uri = "{0}/{1}/{2}" -f $baseUri, $id, $PSCmdlet.ParameterSetName
            if ($PSCmdlet.ShouldProcess($PSCmdlet.ParameterSetName + " alertId $id")) {
                Invoke-ZertoRestRequest -uri $uri -method "POST" | Out-Null
            }
        }
    }

    end {
        # Nothing to do.
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Set-ZertoLicense {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param (
        [Parameter(
            Mandatory,
            HelpMessage = "License Key to apply to the Zerto Virtual Manager"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$licenseKey
    )

    begin {
        $baseUri = "license"
        $body = @{"LicenseKey" = $licenseKey }
    }

    process {
        if ($PSCmdlet.ShouldProcess("Applying License Key: $licenseKey to server: $($script:zvmServer)")) {
            Invoke-ZertoRestRequest -uri $baseUri -body $($body | ConvertTo-Json) -method "PUT"
        }
    }

    end {
        # Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Set-ZertoUserCredential {
    [cmdletbinding(
        SupportsShouldProcess,
        ConfirmImpact = 'High'
    )]
    param(
        [Parameter(
            HelpMessage = "PSCredential Object that contains the username and password for the updated credentials.",
            Mandatory
        )]
        [pscredential]$UserCredential
    )

    begin {

    }

    process {
        $uri = '/localsite/virtualizationsettings'
        $body = @{
            Credentials = @{
                UserName = $UserCredential.UserName
                Password = $UserCredential.GetNetworkCredential().Password
            }
        }
        if ( $PSCmdlet.ShouldProcess( $script:zvmServer, "Updating hypervisor service account credentials" )) {
            Invoke-ZertoRestRequest -uri $uri -Method PUT -body ($body | ConvertTo-Json)
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Start-ZertoCloneVpg {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            HelpMessage = "Name of the VPG you wish to clone.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            HelpMessage = "The identifier of the checkpoint to use for cloning. If unspecified, the latest checkpoint will be used."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("checkpointId")]
        [string]$checkpointIdentifier,
        [Parameter(
            HelpMessage = "The datastore name where the clone is to be created. If unspecified, will auto select the datastore with the most free space."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$datastoreName,
        [Parameter(
            HelpMessage = "The name(s) of the VMs you wish to clone. If unspecified, all VMs in the VPG will be cloned."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmName
    )

    begin {

    }

    process {
        $baseUri = "vpgs"
        $vpgInfo = Get-ZertoVpg -name $vpgName
        if ( -not $vpgInfo ) {
            Write-Error "VPG: $vpgName could not be found. Please check the name and try again."
        }
        $vpgIdentifier = $vpgInfo.vpgIdentifier
        $body = @{ }
        if ( $PSBoundParameters.ContainsKey('datastoreName') ) {
            $recoverysiteIdentifier = $vpgInfo.recoverysite.identifier
            $recoverySiteDatastores = Get-ZertoVirtualizationSite -siteIdentifier $recoverysiteIdentifier -datastores
            $datastoreIdentifier = $($recoverySiteDatastores | Where-Object { $_.datastoreName -like $datastoreName }).DatastoreIdentifier
            if ( -not $datastoreIdentifier ) {
                Write-Error "Datastore: $datastoreName is not a valid datastore. Please check the name and try again." -ErrorAction Stop
            } else {
                $body['DatastoreIdentifier'] = $datastoreIdentifier
            }
        }
        if ( $PSBoundParameters.ContainsKey('vmName') ) {
            $vpgVmInformation = Get-ZertoProtectedVm -vpgName $vpgName
            [System.Collections.ArrayList]$vmIdentifiers = @()
            foreach ( $name in $vmName ) {
                $selectedVm = $vpgVmInformation | Where-Object { $_.VmName.toLower() -eq $name.toLower() }
                if ($null -eq $selectedVm) {
                    Write-Error "VM: $name NOT found in VPG $vpgName. Check the name and try again." -ErrorAction Stop
                } elseif ($vmIdentifiers.Contains($selectedVm.vmIdentifier.toString())) {
                    Write-Error "VM: $($selectedVm.VmName) specified more than once. Please check parameters and try again." -ErrorAction Stop
                } else {
                    $vmIdentifiers.Add($selectedVm.vmIdentifier.toString()) | Out-Null
                }
            }
            $body['VmIdentifiers'] = $vmIdentifiers
        }
        if ( $PSBoundParameters.ContainsKey('checkpointIdentifier') ) {
            $body['checkpointId'] = $checkpointIdentifier
        }
        Write-Verbose $body
        $uri = "{0}/{1}/CloneStart" -f $baseUri, $vpgIdentifier
        if ($PSCmdlet.ShouldProcess("Clone Vpg")) {
            Invoke-ZertoRestRequest -uri $uri -body $($body | ConvertTo-Json) -method "POST"
            Write-Verbose "Call Submitted to $uri"
            Write-Verbose "With the following information: $($body | ConvertTo-Json)"
        }
    }

    end {

    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Start-ZertoFailoverTest {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            HelpMessage = "Name of VPG to failover test",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName,
        [Parameter(
            HelpMessage = "The identifier of the checkpoint to use for testing. If unspecified, the latest checkpoint will be used."
        )]
        [ValidateNotNullOrEmpty()]
        [Alias("checkpointId")]
        [string]$checkpointIdentifier,
        [Parameter(
            HelpMessage = "The name(s) of the VMs within the selected VPG you wish to test. If unspecified, all VMs in the VPG will be tested."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vmName
    )

    begin {
        $baseUri = "vpgs"
        $vpgIdentifier = $(Get-ZertoVpg -name $vpgName).vpgIdentifier
        if ( -not $vpgIdentifier) {
            Write-Error "VPG: $vpgName Not Found. Please check the name and try again!" -ErrorAction Stop
        }
        $body = @{ }
        if ( $PSBoundParameters.ContainsKey('vmName') ) {
            $vpgVmInformation = Get-ZertoProtectedVm -vpgName $vpgName
            $vmIdentifiers = [System.Collections.Generic.List[string]]::new()
            foreach ( $name in $vmName ) {
                $selectedVm = $vpgVmInformation | Where-Object { $_.VmName.toLower() -eq $name.toLower() }
                if ($null -eq $selectedVm) {
                    Write-Error "VM: $name NOT found in VPG $vpgName. Check the name and try again." -ErrorAction Stop
                } elseif ($vmIdentifiers.Contains($selectedVm.vmIdentifier.toString())) {
                    Write-Error "VM: $($selectedVm.VmName) specified more than once. Please check parameters and try again." -ErrorAction Stop
                } else {
                    $vmIdentifiers.Add($selectedVm.vmIdentifier.toString()) | Out-Null
                }
            }
            $body['VmIdentifiers'] = $vmIdentifiers
            if ($checkpointIdentifier) {
                $body['CheckpointIdentifier'] = $checkpointIdentifier
            }
        }
    }

    process {
        $uri = "{0}/{1}/FailoverTest" -f $baseUri, $vpgIdentifier
        if ($PSCmdlet.ShouldProcess($vpgName)) {
            Invoke-ZertoRestRequest -uri $uri -method "POST" -body $($body | ConvertTo-Json)
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Stop-ZertoCloneVpg {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            HelpMessage = "Name of the VPG to stop cloning",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string]$vpgName
    )

    begin {
        $baseUri = "vpgs"
        $vpgIdentifier = $(Get-ZertoVpg -name $vpgName).vpgIdentifier
        if ( -not $vpgIdentifier ) {
            Write-Error "VPG: $vpgName could not be found. Please check the name and try again." -ErrorAction Stop
        }
    }

    process {
        $uri = "{0}/{1}/CloneAbort" -f $baseUri, $vpgIdentifier
        if ($PSCmdlet.ShouldProcess("Stopping VPG Clone Operation")) {
            invoke-ZertoRestRequest -uri $uri -method "POST"
        }

    }

    end {
        # Nothing to do
    }
}



<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Stop-ZertoFailoverTest {
    [cmdletbinding( SupportsShouldProcess = $true )]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to stop testing.",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName,
        [Parameter(
            HelpMessage = "Was the test successful? True or False. True is Default."
        )]
        [bool]$failoverTestSuccess = $true,
        [Parameter(
            HelpMessage = "Free text field for any notes to add to the test report."
        )]
        [ValidateNotNullOrEmpty()]
        [string]$failoverTestSummary = "Stop Failover Test for $vpgName"
    )

    begin {
        $baseUri = "vpgs"
        $body = @{"FailoverTestSuccess" = $failoverTestSuccess; "FailoverTestSummary" = $failoverTestSummary }
    }

    process {
        foreach ($name in $vpgName) {
            $vpgId = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $vpgId) {
                Write-Error "VPG: $vpgName Not Found. Please check the name and try again!" -ErrorAction Stop
            }
            $uri = "{0}/{1}/FailoverTestStop" -f $baseUri, $vpgId
            if ($PSCmdlet.ShouldProcess("Stopping Failover Test on VPG: $name")) {
                Invoke-ZertoRestRequest -uri $uri -method "POST" -body $($body | ConvertTo-Json)
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Suspend-ZertoVpg {
    [cmdletbinding()]
    param(
        [Parameter(
            HelpMessage = "Name(s) of VPG(s) to pause replication",
            Mandatory
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$vpgName
    )

    begin {
        $baseUri = "vpgs"
    }

    process {
        foreach ($name in $vpgName) {
            $id = $(Get-ZertoVpg -name $name).vpgIdentifier
            if ( -not $id ) {
                Write-Error "VPG: $name not found. Skipping."
            } else {
                $uri = "{0}/{1}/pause" -f $baseUri, $id
                Invoke-ZertoRestRequest -uri $uri -method "POST"
            }
        }
    }

    end {
        #Nothing to do
    }
}


<# .ExternalHelp ./en-us/ZertoApiWrapper-help.xml #>
function Uninstall-ZertoVra {
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Host Name attached to the VRA to be removed."
        )]
        [ValidateNotNullOrEmpty()]
        [string[]]$hostName
    )

    begin {
        $baseUri = "vras"
    }

    process {
        foreach ($name in $hostName) {
            $vraName = "Z-VRA-{0}" -f $name
            $vraIdentifier = get-zertovra -vraName $vraName | Select-Object vraIdentifier -ExpandProperty vraIdentifier
            if ( -not $vraIdentifier ) {
                Write-Error "Host: $hostName either does not have a VRA or was not found. Please check the name and try again. Skipping."
            } else {
                $uri = "{0}/{1}" -f $baseUri, $vraIdentifier.toString()
                Invoke-ZertoRestRequest -uri $uri -method "DELETE"
            }
            if ($hostName.Count -gt 1) {
                Start-Sleep 1
            }
        }
    }

    end {

    }
}