Update : updated script to support Azure Az powershell module.
Today , I am going to share a script to take Snapshot of Azure Managed disks. Taking a snapshot of business critical systems before working on any system change which can potentially cause business impact is crucial. If something goes wrong, you can quickly restore it from the snapshot.
Following script is written in a format to run as an Automation Account Runbook in Azure. However, you can easily change it to run as a normal Powershell script. You can take snapshots of both OS Disk and Data Disks based on passed parameters.
Before start using this script, make sure, you have Azure Az Module installed and imported on the system. For more information on how to install and configure Az module refer following article : https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az?view=azps-5.5.0 .
Param(
[String]$vmName,
[Parameter(Mandatory=$true)]
[String]$resourceGroupName,
[Parameter(Mandatory=$false)]
[bool]$includeOSDisk = $true,
[Parameter(Mandatory=$true)]
[bool]$includeDataDisk = $false,
[Parameter(Mandatory=$true)]
[bool]$allowShutdown
)
#region - login to Azure from the Automation Account.Setup Automation account as prerequisite.
$connectionName = "AzureRunAsConnection"
try{
#Get the connection 'AzureRunAsConnection'
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch{
if(!$ServicePrincipalConnection){
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
}else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
#endregion
#get vm details check if vm exists, if no, exit out
try{
$vmDetails = Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName
if([string]::IsNullOrEmpty($vmDetails)){
Write-Error -Message "ERROR: No such VM $vmName exists in the resource group or subscription.Try again with correct VM name."
Exit
}
}
catch{
Write-Error -Message $_.Exception
throw $_.Exception
Exit
}
#
#function to take snapshot
function take-snapshot($dUri,$dName,$vm,$rgName,$loc){
try{
$snapshot = New-AzSnapshotConfig -SourceUri $dUri -Location $loc -CreateOption Copy
$snapshotName = "$($dName)-$((Get-Date).ToString("MM-dd-yyyy-HHmmss"))"
$snapshotStatus = New-AzSnapshot -SnapshotName $snapshotName -ResourceGroupName $rgName -Snapshot $snapshot
if($snapshotStatus.ProvisioningState -ne "Succeeded"){
Write-Error -Message "ERROR: Failed to take snapshot disk $dName of $vm."
}
else{
Write-Output "SUCCESS: Snapshot for disk $dName has been completed successfully.Snapshot Name : $snapshotName. "
}
}
catch{
Write-Error -Message "ERROR: Failed to take snapshot of disk $dName of $vm."
Exit
}
}
#
#shutdown if the parameter set to allow shutdown
if($allowShutdown){
try{
$vmPowerStatus = (Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Status).Statuses.code
if($vmPowerStatus -contains "PowerState/running"){
$vmRunning = $true
Stop-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -StayProvisioned -Force -Confirm:$false
do
{
Start-Sleep -Seconds 5
$vmPowerStatus = (Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Status).Statuses.code
}while($vmPowerStatus -contains "PowerState/running")
}
}
catch{
Write-Error -Message "ERROR: Failed to shutdown $vm.Script will exit"
Exit
}
}
#
#based on disk selection take snapshot of disks
if($includeOSDisk){
$diskUri = $vmDetails.StorageProfile.OsDisk.ManagedDisk.Id
$diskName = $vmDetails.StorageProfile.OsDisk.Name
take-snapshot $diskUri $diskName $vmName $resourceGroupName $vmDetails.Location
}
if($includeDataDisk){
$dataDisks = $vmDetails.StorageProfile.DataDisks
if(!([string]::IsNullOrEmpty($dataDisks))){
foreach($disk in $dataDisks){
$diskUri = $disk.ManagedDisk.Id
$diskName = $disk.Name
take-snapshot $diskUri $diskName $vmName $resourceGroupName $vmDetails.Location
}
}
else{
Write-Output "INFORMATION: No Data disk attached to this VM.Skipping Snapshot process for Data disks."
}
}
#
Write-Output "INFORMATION: Snapshot operation has been completed for $vmName."
#bring server back online if it was shutdown earlier
if($allowShutdown -and $vmRunning){
try{
Start-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Confirm:$false
do
{
Start-Sleep -Seconds 5
$vmPowerStatus = (Get-AzVM -Name $vmName -ResourceGroupName $resourceGroupName -Status).Statuses.code
}while(!($vmPowerStatus -contains "PowerState/running"))
Write-Output "INFORMATION: Virtual Machine $vmName is back online now."
}
catch{
Write-Error "ERROR: Failed to bring $vmName online.Please check the $vmName through portal"
}
}
#
Login to Azure Portal using https://portal.azure.com and open Azure Automation Accounts from left pane.
Open configured Azure Automation account and select Runbooks from Process Automation option in the left pane.
Note: To run this script you will need to Import Powershell Az Modules, otherwise, it will throw error. Refer following article on how to import different modules :
https://docs.microsoft.com/en-us/azure/automation/shared-resources/modules
Create a new Runbook using the script above and save it. Once, it is saved run the Runbook from the list.