Architecting a VMware vCloud Availability for vCloud Director Solution

Another vCloud Architecture Toolkit whitepaper that I authored was published on the vCAT SP website – it discusses how to architect vCloud Availability solution in large production scenarios.

It is based on real live deployments and includes the following chapters:

 

 

 

  • Introduction
  • Use Cases
    • Disaster Recovery
    • Migration
  • vCloud Availability Architecture Design Overview
    • vCloud Availability Architecture
    • Network Flows
    • Conceptual Architecture
  • vCloud Availability Management Components
    • Logical Architecture
    • vCloud Availability Portal
    • Cloud Proxy
    • RabbitMQ
    • Cassandra Database
    • VMware Platform Services Controller
    • vSphere Replication Cloud Service
    • vSphere Replication Manager
    • vSphere Replication Servers
    • ESXi Hosts
    • vCloud Availability Metering
    • vRealize Orchestrator
    • Management Component Resiliency Considerations
  • vCloud Director Configuration
    • User Roles
    • Tenant Limits and Leases
    • Organization Virtual Data Center
    • Network Management
    • Storage Management
    • vApps and Virtual Machines
  • Billing
  • vRealize Orchestrator Configuration
    • On-Premises Deployment
    • In-the-Cloud Deployment
    • Provider Deployment
    • Failover Orchestration
  • Monitoring
    • Component Monitoring
    • VM Replication Monitoring
    • Backup Strategy
  • Appendix A – Port Requirements / Firewall Rules
  • Appendix B – Glossary
  • Appendix C – Maximums
  • Appendix D – Reference Documents
  • Appendix E – Tenant API Structure
  • Appendix F – Undocumented HybridSettings vCloud API
  • Appendix G – Monitoring

Download from the vCAT-SP website: https://www.vmware.com/solutions/cloud-computing/vcat-sp.html or direct link to pdf.

vCloud Availability – Orchestration with PowerCLI

vCloud Availability – Orchestration with PowerCLI

In my last post I have introduced vCloud Availability – a Disaster Recovery extension for vCloud Director and also have shown how service providers can monitor the key components of the solution.

Today I will show how tenants can orchestrate failover of their VMs to the cloud with PowerCLI without the need to have access to their on-prem vCenter Server which in case of disaster might be down.

vCloud Availability is extending vCloud APIs with new API calls that can be used to gather information about ongoing replications and provide fail over, test failover and cleanup test failover actions.

I have created the following PowerCLI cmdlets that demonstrate usage of the new APIs.

Get-VRReplication

The function returns one (based on its name) or all tenant configured replications, displays their status and also vCloud vApp identifier which is important for additional orchestration as I will show later below.

FailOver-VRReplication

This function needs an Replication object (which can be obtain with the previous command) as an input and performs real replication to the cloud. Additional parameters specifie if the recovered VM should be powered on or if the task should run asynchronously.

TestFailover-VRReplication

This is identical function to the previous one, however it performs only Test Failover to the cloud. This means replication still goes on and the recovered VM is connected to a test network in the cloud instead of the production one. Input parameters are identical.

TestCleanup-VRRreplication

This command cleans up replication that is in Test Recovery State.

Orchestration

As I hinted above, these new cmdlets can be combined with existing vCloud PowerCLI cmdlets to orchestrate complex workflows that require changes on the recovered VMs. As an example I am showing simple script that recovers one VM and changes its IP address. The code is heavily commented to explain each step.

#Replication name matches the protected VM name
$Name = "VM1"
#New IP addresses(s) - can be array of multiple entries, if VM has multiple NICs
[array] $IPAddress = '192.168.1.150'

#First we need to get the replication object
$Replication = Get-VRReplication $Name

#Now we can perform the failover however we will not power-on the VM yet.
FailOver-VRReplication -Replication $Replication -PowerOn $false

#Now we need to find the recovered VM within the vApp. There is always 1:1 relationship between vApp and recovery VM.
$VM = Get-CIVApp -Id $Replication.VappId | Get-CIVM

#We will go through all VM NICs and change their IP allocation mode from DHCP to manual and set new IP address
$i = 0
foreach ($NetworkAdapter in $VM|Get-CINetworkAdapter) {
 Set-CINetworkAdapter $NetworkAdapter -IPAddressAllocationMode Manual -IPAddress $IPAddress[$i]
 $i++
 }
 
#Guest customization must be enabled so new IP addresses are assigned within the Guest OS upon first boot 
$GuestCustomization = $VM.ExtensionData.Section | Where {$_.GetType() -like "*GuestCustomizationSection"}
$GuestCustomization.Enabled = $True
$Result = $GuestCustomization.UpdateServerData()

#We can finaly start the VM
Start-CIVM $VM -RunAsync:$true

And here are the PowerShell functions:

Function Get-VRReplication {
<#
.SYNOPSIS
Collects specific or all replications in particular organization
.DESCRIPTION
Collects specific or all replications in particular organization, their compliance status and other information
.EXAMPLE
PS C:\> Connect-CIServer -Org ACME
PS C:\> Get-VRReplication
PS C:\> Get-VRReplication VM1
.EXAMPLE
PS C:\> Get-VRReplication -Org ACME -Name VM1
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false,Position=1)]
[String]$Name,
[Parameter(Mandatory=$false,Position=2)]
[String]$Org
)
if (-not $global:DefaultCIServers) {Connect-CIServer}
If ($Org -eq "") {$Org = $global:DefaultCIServers[0].Org}

$VRReplications = @()

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + ((get-org $org).id).Replace("urn:vcloud:org:","org/") + "/replications"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

foreach ($Replication in $sxml.References.Reference) {
$n = @{} | select Name,href,Rpo,ReplicationState,CurrentRpoViolation,TestRecoveryState,RecoveryState,VappId,VrServerInfo,ReplicaSpaceRequirements, Instance
$n.href = $Replication.href

$r = Invoke-WebRequest -URI $Replication.href -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$n.name = $sxml.ReplicationGroup.name
$n.Rpo = $sxml.ReplicationGroup.Rpo
$n.ReplicationState = $sxml.ReplicationGroup.ReplicationState
$n.CurrentRpoViolation = $sxml.ReplicationGroup.CurrentRpoViolation
$n.TestRecoveryState = $sxml.ReplicationGroup.TestRecoveryState
$n.RecoveryState = $sxml.ReplicationGroup.RecoveryState
$n.VappId = $sxml.ReplicationGroup.PlaceholderVappId
$n.VrServerInfo = $sxml.ReplicationGroup.VrServerInfo.Uuid

$VRReplications += $n
}
if ( $name ) {
 $VRReplications | ? { $_.name -eq $name }
 } else {
 $VRReplications}

}


Function FailOver-VRReplication {
<#
.SYNOPSIS
Fails over replicated VM in the cloud 
.DESCRIPTION
Fails over replicated VM in the cloud. The input must be replication object, power-on (default = true) and RunAsync (default false) booleans 
.EXAMPLE
PS C:\> Connect-CIServer -Org ACME
PS C:\> FailOver-VRReplication (Get-VRReplication VM1)
.EXAMPLE
PS C:\> FailOver-VRReplication -Replication (Get-VRReplication -Org ACME -Name VM1) -PowerOn:$False -RunAsync:$True
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=1)]
$Replication,
[Parameter(Mandatory=$false,Position=2)]
[boolean]$PowerOn=$true,
[Parameter(Mandatory=$false,Position=3)]
[boolean]$RunAsync=$false
)

if (-not $global:DefaultCIServers) {Connect-CIServer}
If ($Org -eq "") {$Org = $global:DefaultCIServers[0].Org}



$Uri = $Replication.href + "/action/failover"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=4.0"} + @{"Content-Type"="application/vnd.vmware.hcs.failoverParams+xml"}

if ($PowerOn -eq $False) {$body = 
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:FailoverParams xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ns2="http://www.vmware.com/vr/v6.0" xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:ns7="http://schemas.dmtf.org/ovf/environment/1">
<ns2:PowerOn>false</ns2:PowerOn>
</ns2:FailoverParams>'} else
{$body = 
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:FailoverParams xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ns2="http://www.vmware.com/vr/v6.0" xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:ns7="http://schemas.dmtf.org/ovf/environment/1">
<ns2:PowerOn>true</ns2:PowerOn>
</ns2:FailoverParams>'}

$r = Invoke-WebRequest -URI $Uri -Method Post -Headers $head -Body $Body -ErrorAction:Stop
[xml]$sxml = $r.Content

$Uri = $sxml.Task.href
if ($RunAsync -eq $false) {
 Do
 {
 $r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
 [xml]$sxml = $r.Content
 $Progress = $sxml.Task.Progress
 Write-Progress -Activity FailOver -Status 'Progress->' -PercentComplete $Progress
 Start-Sleep -s 5
 } until ($Progress -eq 100)
 }
}

Function TestFailOver-VRReplication {
<#
.SYNOPSIS
Performs test failover of replicated VM in the cloud 
.DESCRIPTION
Performs test failover replicated VM in the cloud. The input must be replication object, power-on (default = true) and RunAsync (default false) booleans
.EXAMPLE
PS C:\> Connect-CIServer -Org ACME
PS C:\> TestFailOver-VRReplication (Get-VRReplication VM1) -PowerOn:$False
.EXAMPLE
PS C:\> TestFailOver-VRReplication -Replication (Get-VRReplication -Org ACME -Name VM1) -RunAsync:$True
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=1)]
$Replication,
[Parameter(Mandatory=$false,Position=2)]
[boolean]$PowerOn=$true,
[Parameter(Mandatory=$false,Position=3)]
[boolean]$RunAsync=$false
)

if (-not $global:DefaultCIServers) {Connect-CIServer}
If ($Org -eq "") {$Org = $global:DefaultCIServers[0].Org}



$Uri = $Replication.href + "/action/testFailover"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=4.0"} + @{"Content-Type"="application/vnd.vmware.hcs.failoverParams+xml"}

if ($PowerOn -eq $False) {$body = 
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:TestFailoverParams
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:ns2="http://www.vmware.com/vr/v6.0"
xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:ns7="http://schemas.dmtf.org/ovf/environment/1">
<ns2:PowerOn>false</ns2:PowerOn>
<ns2:Synchronize>false</ns2:Synchronize>
</ns2:TestFailoverParams>'} else
{$body = 
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:TestFailoverParams
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:ns2="http://www.vmware.com/vr/v6.0"
xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
xmlns:ns7="http://schemas.dmtf.org/ovf/environment/1">
<ns2:PowerOn>true</ns2:PowerOn>
<ns2:Synchronize>false</ns2:Synchronize>
</ns2:TestFailoverParams>'}

$r = Invoke-WebRequest -URI $Uri -Method Post -Headers $head -Body $Body -ErrorAction:Stop
[xml]$sxml = $r.Content

$Uri = $sxml.Task.href
if ($RunAsync -eq $false) {
 Do
 {
 $r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
 [xml]$sxml = $r.Content
 $Progress = $sxml.Task.Progress
 Write-Progress -Activity 'Test FailOver' -Status 'Progress->' -PercentComplete $Progress
 Start-Sleep -s 5
 } until ($Progress -eq 100)
 }
}

Function TestCleanup-VRReplication {
<#
.SYNOPSIS
Performs test replication cleanup in the cloud.
.DESCRIPTION
Performs test replication cleanup in the cloud. The input must be replication object and optional RunAsync (default false) boolean.
.EXAMPLE
PS C:\> Connect-CIServer -Org ACME
PS C:\> TeastCleanup-VRReplication (Get-VRReplication VM1)
.EXAMPLE
PS C:\> TestCleanup-VRReplication -Replication (Get-VRReplication -Org ACME -Name VM1) -RunAsync:$True
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=1)]
$Replication,
[Parameter(Mandatory=$false,Position=2)]
[boolean]$RunAsync=$false
)

if (-not $global:DefaultCIServers) {Connect-CIServer}
If ($Org -eq "") {$Org = $global:DefaultCIServers[0].Org}



$Uri = $Replication.href + "/action/testCleanup"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=4.0"} + @{"Content-Type"="application/vnd.vmware.hcs.failoverParams+xml"}

$body = 
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:SyncParams
xmlns="http://www.vmware.com/vcloud/v1.5"
xmlns:ns2="http://www.vmware.com/vr/v6.0"
xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1"
xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cimschema/
2/CIM_VirtualSystemSettingData"
xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common"
xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cimschema/
2/CIM_ResourceAllocationSettingData"
xmlns:ns7="http://schemas.dmtf.org/ovf/environment/1">
<ns2:RepeatOngoingOnlineSync>false</ns2:RepeatOngoingOnlineSync>
</ns2:SyncParams>'

$r = Invoke-WebRequest -URI $Uri -Method Post -Headers $head -Body $Body -ErrorAction:Stop
[xml]$sxml = $r.Content

$Uri = $sxml.Task.href
if ($RunAsync -eq $false) {
 Do
 {
 $r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
 [xml]$sxml = $r.Content
 $Progress = $sxml.Task.Progress
 Write-Progress -Activity 'Test Cleanup' -Status 'Progress->' -PercentComplete $Progress
 Start-Sleep -s 5
 } until ($Progress -eq 100)
 }
}

vCloud Availability PowerCLI Monitoring Cmdlets

vCloud Availability PowerCLI Monitoring Cmdlets


vCloud Availability for vCloud Director
is a new product for vCAN service providers released in July 2016 that enables disaster recovery to and from the cloud. It allows any vSphere customer who installes vSphere Replication to protect her on-prem workloads into the multitenant service provider cloud environment.

vCloud Availability

vCloud Availability adds additional vCloud APIs thanks to its vCloud Extensibility Framework. I have created a few simple PowerCLI cmdlets that demonstrate how easy is to use the new APIs. The cmdlets allow service provider to monitor state of vCloud Availability components as well as state of tenant replications.

Get-VRCells

Discovers all vCloud Director cells (including Cloud Proxies) and reports their status.

Get-VRCells

Get-VRCSNodes

Discovers all vSphere Replication Cloud Service nodes, their version and amount of seconds since last successful heartbeat.

Get-VRCSNodes

Get-VRMServers

Discovers all vSphere Replication Manager Servers and reports their status and paired vCenter Server

Get-VRMServers

Get-VRServers

Discovers all vSphere Replication Servers, their status and statistics about utilization.

Get-VRServers

Get-VRReplications

Collects all replications in particular organization, their compliance status and other information (RPO, storage used, number of snapshots, etc.). This cmdlet can be used also with tenant credentials.

Get-VRReplications

Function Get-VRCells {
<#
.SYNOPSIS
Discovers all vCloud Director cells
.DESCRIPTION
Discovers all vCloud Director cells including Cloud Proxies and report their status and version and if they ran VC proxy .EXAMPLE PS C:\> Get-VRCells
.NOTES
Author: Tomas Fojta
#>

if (-not $global:DefaultCIServers) {Connect-CIServer}

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + "query?type=cell"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content
$VRCells = $sxml.QueryResultRecords.CellRecord


$VRCells
}

Function Get-VRCSNodes {
<#
.SYNOPSIS
Discovers all vSphere Replication Cloud Service nodes
.DESCRIPTION
Discovers all vSphere Replication Cloud Service nodes, their version and last heartbeat
.EXAMPLE
PS C:\> Get-VRCSNodes
.NOTES
Author: Tomas Fojta
#>
if (-not $global:DefaultCIServers) {Connect-CIServer}

$VRCSNodes = @()
$CurrentTime = (New-TimeSpan -Start (Get-Date -Date "01/01/1970") -End (Get-Date).ToUniversalTime()).TotalMilliseconds

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + "admin/vr/nodes"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

foreach ($VRCS in $sxml.VrcsNodes.Node) {
$n = @{} | select VRCS,MaxSupportedAPiVersion,LastHeartbeatTimestamp,LastHeartbeatAgoInSeconds
$n.VRCS = $VRCS.Id
$n.MaxSupportedAPiVersion = $VRCS.MaxSupportedAPiVersion
$n.LastHeartbeatTimestamp = $VRCS.LastHeartbeatTimestamp
$n.LastHeartbeatAgoInSeconds = [math]::Truncate(($CurrentTime - [convert]::ToInt64($VRCS.LastHeartbeatTimestamp))/1000)

$VRCSNodes += $n
}

$VRCSNodes
}

Function Get-VRMServers {
<#
.SYNOPSIS
Discovers all vSphere Replication Manager Servers and reports their status
.DESCRIPTION
Discovers all vSphere Replication Manager Servers, reports their status and paired vCenter Server
.EXAMPLE
PS C:\> Get-VRMServers
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false,Position=1)]
[String]$Org
)
if (-not $global:DefaultCIServers) {Connect-CIServer}

$VRMServers = @()

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + "admin/extension/vimServerReferences"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

foreach ($VimServer in $sxml.VMWVimServerReferences.VimServerReference) {
$n = @{} | select VRMS,IsConnected,VIMName,VIMhref
$n.VIMname = $VimServer.name
$n.VIMhref = $VimServer.href

$r = Invoke-WebRequest -URI ($VimServer.href + "/vrmServer") -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content
$n.VRMS = $sxml.AdminVrmServer.Uuid
$n.IsConnected = $sxml.AdminVrmServer.IsConnected

$VRMServers += $n
}

$VRMServers
}

Function Get-VRServers {
<#
.SYNOPSIS
Collects all vSphere Replication Servers
.DESCRIPTION
Collects all vSphere Replication Servers and basic statistics
.EXAMPLE
PS C:\> Get-VRServers
.NOTES
Author: Tomas Fojta
#>

if (-not $global:DefaultCIServers) {Connect-CIServer}

$VRServers = @()

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + "admin/extension/vr/vrServers"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

foreach ($vRS in $sxml.References.Reference) {
$n = @{} | select Name,href,IsConnected,ReplicationsCount,DisksCount
$n.href = $vRS.href

$r = Invoke-WebRequest -URI $vRS.href -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$n.Name = $sxml.AdminVrServer.ReplicationTrafficAddress
$n.IsConnected = $sxml.AdminVrServer.IsConnected

$r = Invoke-WebRequest -URI ($vRS.href+"/statistics") -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content
$n.ReplicationsCount = $sxml.VrServerStatistics.ReplicationsCount
$n.DisksCount = $sxml.VrServerStatistics.DisksCount

$VRServers += $n
}

$VRServers

}

Function Get-VRReplications {
<#
.SYNOPSIS
Collects all replications in particular organization
.DESCRIPTION
Collects all replications in particular organization, their compliance status and other information
.EXAMPLE
PS C:\> Connect-CIServer -Org ACME
PS C:\> Get-VRReplications
.EXAMPLE
PS C:\> Get-VRReplications -Org ACME
.NOTES
Author: Tomas Fojta
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false,Position=1)]
[String]$Org
)
if (-not $global:DefaultCIServers) {Connect-CIServer}
If ($Org -eq "") {$Org = $global:DefaultCIServers[0].Org}

$VRReplications = @()

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + ((get-org $org).id).Replace("urn:vcloud:org:","org/") + "/replications"
$head = @{"x-vcloud-authorization"=$global:DefaultCIServers[0].SessionSecret} + @{"Accept"="application/*+xml;version=20.0;vr-version=3.0"}
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

foreach ($Replication in $sxml.References.Reference) {
$n = @{} | select Name,href,Rpo,ReplicationState,CurrentRpoViolation,TestRecoveryState,RecoveryState,VappId,VrServerInfo,ReplicaSpaceRequirements, Instance
$n.href = $Replication.href

$r = Invoke-WebRequest -URI $Replication.href -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$n.Rpo = $sxml.ReplicationGroup.Rpo
$n.ReplicationState = $sxml.ReplicationGroup.ReplicationState
$n.CurrentRpoViolation = $sxml.ReplicationGroup.CurrentRpoViolation
$n.TestRecoveryState = $sxml.ReplicationGroup.TestRecoveryState
$n.RecoveryState = $sxml.ReplicationGroup.RecoveryState
$n.VappId = $sxml.ReplicationGroup.PlaceholderVappId.Replace("urn:vcloud:vapp:","")
$n.VrServerInfo = $sxml.ReplicationGroup.VrServerInfo.Uuid

$r = Invoke-WebRequest -URI ($Replication.href + "/instances") -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$n.ReplicaSpaceRequirements = $sxml.ReplicationGroupInstanceList.ReplicaSpaceRequirements
$n.Instance = $sxml.ReplicationGroupInstanceList.Instance

$Uri = $global:DefaultCIServers[0].ServiceUri.AbsoluteUri + "vApp/vapp-" + $n.VappId
$r = Invoke-WebRequest -URI $Uri -Method Get -Headers $head -ErrorAction:Stop
[xml]$sxml = $r.Content

$n.Name = $sxml.VApp.Children.Vm.name

$VRReplications += $n
}

$VRReplications

}