• 4 min read

Introducing PowerShell support for Azure Site Recovery

Last week we announced PowerShell support for recovery between two Hyper-V sites managed by Azure Site Recovery. The ASR cmdlets can be used to enable protection for virtual machines and performing recovery operations on virtual machines or recovery plan containing virtual machines.

Last week we announced PowerShell support for recovery between two Hyper-V sites managed by Azure Site Recovery. The ASR cmdlets can be used to enable protection for virtual machines and performing recovery operations on virtual machines or recovery plan containing virtual machines. PowerShell support will allow administrator to do scripting against ASR service and also enable hosting service providers to extend their Self-Service portal to offer disaster recovery.

PowerShell support for ASR is shipped as part of Azure PowerShell and available with the Azure PowerShell October 2014 release. If you are already using Azure PowerShell you will need to upgrade to version 0.8.10 or later. Once you have setup and configured Azure PowerShell you will be able to view list all the available Azure Site Recovery cmdlets.

ASR_cmdlet_List

Setup the ASR Vault context

To get started with the Azure Site Recovery cmdlets you will need to setup the PowerShell runspace context with your ASR vault info. To setup you will need to download the Registration key file from Azure portal which is also used during setup and registration of SCVMM to your vault. Once context is setup rest of the cmdlets get executed within the context that has been setup.

ASR_cmdlet_registrationFile2

ASR_cmdlet_Import

List registered SCVMM servers

Once a SCVMM server is setup and registered with Azure Site Recovery, they can be viewed using Get-AzureSiteRecoveryServer cmdlet. The cmdlet outputs communication heartbeat and provider version along with server information enabling the server health monitoring in view of ASR.

ASR_cmdlet_Server

List SCVMM clouds

Azure Site Recovery uses SCVMM clouds to do the scale management of the virtual machines. After the configuration at the SCVMM , information of SCVMM clouds discovered by ASR can be viewed using Get-AzureSiteRecoveryProtectionContainer. You can use either SCVMM cloud name or SCVMM cloud ID to filter the required cloud.

 

ASR_cmdlet_Cloud

ASR_cmdlet_PC

List Virtual Machines

The virtual machines can be viewed in the context of the Protection Container. The information of the SCVMM virtual machine discovered by ASR can be viewed using Get-AzureSiteRecoveryProtectionEntity. Similar to Protection Container one can filter the protection entity using SCVMM VMID or Virtual Machine name.

ASR_cmdlet_PE

Protection of the Virtual Machines

Protection entity list returns both protected and unprotected virtual machines. Protection management can be performed on the protection entity using Set-AzureSiteRecoveryProtectionEntity. This is an asynchronous operation which returns an Azure Site Recovery Job. The job status can be further tracked to completion using Get-AzureSiteRecoveryJobGet-AzureSiteRecoveryJob.

A simple sample script snippet for the same is below:

param
(    
    [parameter(Mandatory=$TRUE, HelpMessage="SCVMM Cloud Name")]
    [ValidateNotNullOrEmpty()]
    [string] $ProtectedContainerName,

    [parameter(Mandatory=$TRUE, HelpMessage="List of VM names in the SCVMM cloud")]
    [ValidateNotNullOrEmpty()]
    [string[]] $VMList,

    [parameter(Mandatory=$TRUE, HelpMessage="Protection State")]
    [ValidateNotNullOrEmpty()]
 [ValidateSet('ENABLE','DISABLE')]
    [string] $ProtectionState
)

$ProtectedContainers =  Get-AzureSiteRecoveryProtectionContainer | %{ $_.Name }
if(!$ProtectedContainers.Contains($ProtectedContainerName))
{ 
 Write-Error "PROTECTED CONTAINER $CloudName NOT FOUND IN ASR"
 return;
}

$ASRProtectedContainer = Get-AzureSiteRecoveryProtectionContainer -Name $ProtectedContainerName
Write-Output "ProtectedContainer " $ASRProtectedContainer

$JobsList = $VMList | %{ 
  Write-Host "Starting $ProtectionState Protections on $_"; 
  Get-AzureSiteRecoveryProtectionEntity -Name $_ -ProtectionContainer $ASRProtectedContainer | Set-AzureSiteRecoveryProtectionEntity -Protection $ProtectionState -WaitForCompletion
 } 

$hasFailed = $FALSE
foreach($Job in $JobsList)
{
    $JobDetails = Get-AzureSiteRecoveryJob -Job $Job
    if($JobDetails.Errors.Count -ne 0)
    {
  $hasFailed = $TRUE
  Write-Host "JobID $Job.Id Failed"
  foreach($JobError in $JobDetails.Errors)
  {
   Write-Host $JobError.ServiceErrorDetails
   Write-Host $JobError.ProviderErrorDetails
   Write-Host $JobError
  }  
    }
}

Write-Host "PROPERTIES AFTER $ProtectionState DR OPERATION"

$VMList | %{ Get-AzureSiteRecoveryProtectionEntity -Name $_ -ProtectionContainer $ASRProtectedContainer }

if(!$hasFailed)
{
 Write-Host "ENABLE DR OF ALL VMs COMPLETED SUCCESSFULLY"
}

 

Creation and management of Recovery Plan

After you’ve enabled protection for virtual machines you can create recovery plans. A recovery plan groups virtual machines together for the purposes of failover and recovery, and it specifies the order in which groups of virtual machines should fail over. Azure Site Recovery cmdlets allows users to download the exiting recovery plan created on Azure portal in form of XML file. The recovery plan XML file can be leveraged for creation of new recovery plan or updating of an existing recovery plan.

The recovery plan management cmdlets are listed as below:

ASR_cmdlet_RPcmdList

A sample XML for the recovery Plan will look like below:



  
  
    
      
      
    
    
      
      
    
    
      
      
      
      
    
    
      
      
      
      
      
    
  
  
    
    
    
    
  

 

Failover

Azure Site Recovery supports 3 types of failovers – Test, Planned and Unplanned. All the failover operations are supported on both individual Virtual Machines and Recovery Plans. These capabilities are now available in PowerShell cmdlets as well. As ASR failovers are asynchronous operations, cmdlets execution of these will return an Azure Site Recovery Job in response. The job status can be further tracked to completion using Get-AzureSiteRecoveryJob.

A simple sample script snippet for the same is below:

param
(    
    [parameter(Mandatory=$FALSE, HelpMessage="Name of the RP")]
    [ValidateNotNullOrEmpty()]
    [string] $RPName,

    [parameter(Mandatory=$TRUE, HelpMessage="Failover Type")]
    [ValidateNotNullOrEmpty()]
 [ValidateSet('PLANNED','UNPLANNED', 'TEST')]
 [string] $FailoverType,

    [parameter(Mandatory=$TRUE, HelpMessage="Failover direction")]
    [ValidateNotNullOrEmpty()]
 [ValidateSet('PrimaryToRecovery','RecoveryToPrimary')]
    [string] $FailoverDirection,

    [parameter(Mandatory=$TRUE, HelpMessage="Should do commit on the RP after failover")]
    [ValidateNotNullOrEmpty()]
    [bool] $ShouldCommit,

    [parameter(Mandatory=$TRUE, HelpMessage="Should do reverse replicate on the RP after commit")]
    [ValidateNotNullOrEmpty()]
    [bool] $ShouldReverseReplicate
)

##
## This routine checks for error in jobs.
##
function WaitForJobCompletionAndCheck-JobErrors([string] $JobId)
{
        $IsCompleted = $false

        while(!$IsCompleted)
        {

         $Job = Get-AzureSiteRecoveryJob -Id $JobId

         if($Job.State -eq "Succeeded")
         {
          $IsCompleted = $true
                Write-Output "Job with Id $JobId executed successfully."
                return
         }
         if($Job.State -eq "Failed")
         {
          $IsCompleted = $true;
                 Write-Output "The Job Id $JobId has failed in execution"
         }

         if($Job.State -eq "Suspended" )
         {
         Resume-AzureSiteRecoveryJob -Job $Job
         }
            else
            {
                Write-Output "The job $JobID is in progress"  
          Start-Sleep -s 15
            }
        }

  $hasFailed = $false

  $JobDetails = Get-AzureSiteRecoveryJob -Id $JobId
  if($JobDetails.Errors.Count -ne 0)
  {
   $hasFailed = $true
   Write-Error "JobID $JobId Failed"
   foreach($JobError in $JobDetails.Errors)
   {
    Write-Error $JobError.ServiceErrorDetails
    Write-Error $JobError.ProviderErrorDetails
   }
  }

}

$RecoveryPlans =  Get-AzureSiteRecoveryRecoveryPlan | %{ $_.Name }
if(!$RecoveryPlans.Contains($RPName))
{ 
 Write-Error "RECOVERY PLAN $RPName NOT FOUND IN ASR"
 return;
}

$RecoveryPlanObject = Get-AzureSiteRecoveryRecoveryPlan -Name $RPName

Write-Output "RECOVERY PLAN DETAILS : " 
Write-Output $RecoveryPlanObject

Write-Output "Starting RP $FailoverType Failover of $RPName :";

if($FailoverType.ToUpper() -eq "PLANNED")
{
 $Job = Start-AzureSiteRecoveryPlannedFailoverJob -RecoveryPlan $RecoveryPlanObject -Direction $FailoverDirection 
}
elseif($FailoverType.ToUpper() -eq "UNPLANNED")
{
 $Job = Start-AzureSiteRecoveryUnplannedFailoverJob -RecoveryPlan $RecoveryPlanObject -Direction $FailoverDirection 
}
elseif($FailoverType.ToUpper() -eq "TEST")
{
 $Job = Start-AzureSiteRecoveryTestFailoverJob -RecoveryPlan $RecoveryPlanObject -Direction $FailoverDirection 
}
else
{
 Write-Error "Invalid RP Failover Type - $FailoverType"
} 
WaitForJobCompletionAndCheck-JobErrors $Job.ID

if($ShouldCommit)
{
 Write-Output "Starting RP Commit Failover for $RPName"; 

 $RecoveryPlanObject = Get-AzureSiteRecoveryRecoveryPlan -Name $RPName
 Write-Output $RecoveryPlanObject

 $JobsList = Start-AzureSiteRecoveryCommitFailoverJob -RecoveryPlan $RecoveryPlanObject 

 WaitForJobCompletionAndCheck-JobErrors $JobsList.ID
}

if($ShouldReverseReplicate)
{
 Write-Output "Starting RP Reverse Replication for $RPName"; 

 $RecoveryPlanObject = Get-AzureSiteRecoveryRecoveryPlan -Name $RPName
 Write-Output $RecoveryPlanObject

 $JobsList = Update-AzureSiteRecoveryProtectionDirection  -RecoveryPlan  $RecoveryPlanObject -Direction $FailoverDirection 

 WaitForJobCompletionAndCheck-JobErrors $JobsList.ID
}

$RecoveryPlanObject = Get-AzureSiteRecoveryRecoveryPlan -Name $RPName
Write-Output $RecoveryPlanObject