Azure Azure Backup Azure Virtual Desktop

Set up an Azure Backup Recovery Services vault and Backup protection policy to backup your AVD personal session hosts

This blog post will guide you through setting up and configuring a Recovery Services vault and a backup protection policy using PowerShell scripts to safeguard your Azure Virtual Desktop (AVD) personal session hosts with Azure Backup.

Ensuring the safety of critical user data is essential, especially for the virtual machines (VMs) used within the personal host pools of your AVD environment.

As most of you will know, personal desktops have a one-to-one mapping, meaning each user is assigned to a specific personal desktop. So, whenever a user logs in, their session is automatically directed to their designated personal desktop session host.

This personalized approach is ideal for users with resource-intensive workloads. By limiting each session host to a single user, the user experience and session performance are significantly enhanced. This makes it an ideal setup for users with demanding work and application requirements.

So ensuring the integrity and security of not just the data and applications but also the entire individual personal desktop VMs is essential for providing their users with a seamless experience. Luckily, this is where Azure Backup comes into play, helping you protecting these VMs against any data loss and corruption.

To automate the deployment and configuration process of the necessary Recovery Services vault and Backup protection policy for protecting all these personal desktop VMs, I wrote two PowerShell scripts. You can find more details and all about how you can use these scripts below.


Table of Contents


Prerequisites

  • An Azure subscription, preferably more than one if you plan to follow the Cloud Adoption Framework (CAF) enterprise-scale architecture. This includes a connectivity and/or management subscription, as well as an AVD subscription (landing zone), to deploy your AVD-related resources.
  • An Azure Administrator account with the necessary RBAC roles.
  • An existing Log Analytics workspace.
  • Version 10.4.1 of the Azure Az PowerShell module is required.
  • Before you run the second script, ensure a Recovery Services vault is already set up (you can use the first script to deploy and configure one). 





Azure PowerShell scrip to create the Recovery Services vault

By using the first Azure PowerShell script, you can create the necessary Recovery Services vault within your dedicated AVD subscription. This script includes the following steps and configurations:

  • Remove the breaking change warning messages.
  • Change the current context to use a management subscription holding your central Log Analytics workspace.
  • Save the Log Analytics workspace from the management subscription as a variable.
  • Change the current context to the specified subscription.
  • Store a specified set of tags in a hash table.
  • Register required Azure resource provider (Microsoft.RecoveryServices) in your subscription (only necessary if you use Azure Backup for the first time), if not already registered.
  • Create a resource group backup if one does not already exist. Also, apply the necessary tags to this resource group.
  • Create a resource group backup irp if one does not already exist. Also, apply the necessary tags to this resource group.
  • Create the Recovery Services vault if it does not exist.
  • Set specified tags on the Recovery Services vault.
  • Specify the type of backup storage redundancy for the Recovery Services vault (which can be modified only if there are no backup items protected in the vault).
  • Enable Cross Region Restore (CRR).
  • Set the log and metrics settings for the Recovery Services vault if they don’t exist.
  • Remove the default backup protection policies.


To use the script, first make a copy and save it as “Create-Azure-Backup-Recovery-Services-vault-to-backup-AVD-personal-session-hosts.ps1” or you can download it directly from GitHub.

Before utilizing the script, adjust all variables according to your requirements (an example is provided below). Once adjusted, run the customized script using Windows TerminalVisual Studio Code, or Windows PowerShell. Or you can simply run it from Cloud Shell.

If you are not running the script from Cloud Shell, don’t forget to sign in with the Connect-AzAccount cmdlet to connect your Azure account.



You can then run the script with the required parameters:

.\Create-Azure-Backup-Recovery-Services-vault-to-backup-AVD-personal-session-hosts -SubscriptionName <"your Azure (AVD) subscription name here">



<#
.SYNOPSIS

A script used to create an Azure Backup Recovery Services vault to backup AVD personal session-hosts.

.DESCRIPTION

A script used to create an Azure Backup Recovery Services vault to backup AVD personal session-hosts.
The script will do all of the following:

Remove the breaking change warning messages.
Change the current context to use a management subscription holding your central Log Analytics workspace.
Save the Log Analytics workspace from the management subscription as a variable.
Change the current context to the specified Azure Virtual Desktop (AVD) subscription.
Store a specified set of tags in a hash table.
Register required Azure resource provider (Microsoft.RecoveryServices) in your subscription (only necessary if you use Azure Backup for the first time), if not already registered.
Create a resource group backup if one does not already exist. Also, apply the necessary tags to this resource group.
Create a resource group backup irp if one does not already exist. Also, apply the necessary tags to this resource group.
Create the Recovery Services vault if it does not exist.
Set specified tags on the Recovery Services vault.
Specify the type of backup storage redundancy for the Recovery Services vault (which can be modified only if there are no backup items protected in the vault).
Enable Cross Region Restore (CRR).
Set the log and metrics settings for the Recovery Services vault if they don't exist.
Remove the default backup protection policies.

.NOTES

Filename:       Create-Azure-Backup-Recovery-Services-vault-to-backup-AVD-personal-session-hosts.ps1
Created:        09/10/2023
Last modified:  09/10/2023
Author:         Wim Matthyssen
Version:        1.0
PowerShell:     Azure PowerShell and Azure Cloud Shell
Requires:       PowerShell Az (v10.4.1)
Action:         Change variables were needed to fit your needs. 
Disclaimer:     This script is provided "as is" with no warranties.

.EXAMPLE

Connect-AzAccount
Get-AzTenant (if not using the default tenant)
Set-AzContext -tenantID "xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx" (if not using the default tenant)
.\Create-Azure-Backup-Recovery-Services-vault-to-backup-AVD-personal-session-hosts -SubscriptionName <"your Azure (AVD) subscription name here">

.LINK


#>

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Parameters

param(
    # $subscriptionName -> Name of the Azure Subscription
    [parameter(Mandatory =$true)][ValidateNotNullOrEmpty()] [string] $subscriptionName
)

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Variables

$purpose = "backup"
$region = #<your region here> The used Azure public region. Example: "westeurope"
$providerNameSpace = "Microsoft.RecoveryServices"

$rgNameBackup = #<your backup resource group name here> The name of the Azure resource group in which your new or existing Recovery Services vault deployed. Example: "rg-prd-myh-avd-backup-01"
$rgNameBackupIrp = #<your backup irp resource group name here> The name of the Azure resource group in which your store your instant restore snapshots . Example: "rg-prd-myh-avd-backup-irp-01"

$logAnalyticsWorkSpaceName = #<your Log Analytics workspace name here> The name of your existing Log Analytics workspace. Example: "law-hub-myh-01"

$vaultName = #<your Recovery Services vault name here> The name of your new Recovery Services vault. Example: "rsv-prd-myh-avd-bck-we-01"
$backupStorageRedundancy = "GeoRedundant" # "LocallyRedundant" (LRS) - "ZoneRedundant" (ZRS)
$vaultDiagnosticsName = "diag" + "-" + $vaultName

$tagSpokeName = #<your environment tag name here> The environment tag name you want to use. Example:"Env"
$tagSpokeValue = #<your environment tag value here> The environment tag value you want to use. Example: "Hub"
$tagCostCenterName  = #<your costCenter tag name here> The costCenter tag name you want to use. Example:"CostCenter"
$tagCostCenterValue = #<your costCenter tag value here> The costCenter tag value you want to use. Example: "23"
$tagCriticalityName = #<your businessCriticality tag name here> The businessCriticality tag name you want to use. Example: "Criticality"
$tagCriticalityValue = #<your businessCriticality tag value here> The businessCriticality tag value you want to use. Example: "High"
$tagPurposeName  = #<your purpose tag name here> The purpose tag name you want to use. Example:"Purpose"
$tagPurposeValue = "$($purpose[0].ToString().ToUpper())$($purpose.SubString(1))"

Set-PSBreakpoint -Variable currenttime -Mode Read -Action {$global:currenttime = Get-Date -Format "dddd MM/dd/yyyy HH:mm"} | Out-Null 
$foregroundColor1 = "Green"
$foregroundColor2 = "Yellow"
$writeEmptyLine = "`n"
$writeSeperatorSpaces = " - "

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Remove the breaking change warning messages

Set-Item -Path Env:\SuppressAzurePowerShellBreakingChangeWarnings -Value $true | Out-Null
Update-AzConfig -DisplayBreakingChangeWarning $false | Out-Null
$warningPreference = "SilentlyContinue"

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script started

Write-Host ($writeEmptyLine + "# Script started. Without errors, it can take up to 2 minutes to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Change the current context to use a management subscription holding your central Log Anlytics workspace

# Replace <your subscription purpose name here> with purpose name of your subscription. Example: "*management*"
$subNameManagement = Get-AzSubscription | Where-Object {$_.Name -like "*management*"}

Set-AzContext -SubscriptionId $subNameManagement.SubscriptionId | Out-Null 

Write-Host ($writeEmptyLine + "# Management subscription in current tenant selected" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Save Log Analytics workspace from the management subscription in a variable

$workSpace = Get-AzOperationalInsightsWorkspace | Where-Object Name -Match $logAnalyticsWorkSpaceName

Write-Host ($writeEmptyLine + "# Log Analytics workspace variable created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Change the current context to the specified subscription

$subName = Get-AzSubscription | Where-Object {$_.Name -like $subscriptionName}

Set-AzContext -SubscriptionId $subName.SubscriptionId | Out-Null 

Write-Host ($writeEmptyLine + "# Specified subscription in current tenant selected" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Register the required Azure resource provider (Microsoft.RecoveryServices) in the current subscription context, if not yet registerd

Register-AzResourceProvider -ProviderNamespace $providerNameSpace | Out-Null

Write-Host ($writeEmptyLine + "# All required resource providers for a Recovery Services vault are currently registering or have already registered" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Store the specified set of tags in a hash table

$tags = @{$tagSpokeName=$tagSpokeValue;$tagCostCenterName=$tagCostCenterValue;$tagCriticalityName=$tagCriticalityValue;$tagPurposeName=$tagPurposeValue}

Write-Host ($writeEmptyLine + "# Specified set of tags available to add" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create a resource group backup if one does not already exist. Also, apply the necessary tags to this resource group

try {
    Get-AzResourceGroup -Name $rgNameBackup -ErrorAction Stop | Out-Null 
} catch {
    New-AzResourceGroup -Name $rgNameBackup -Location $region -Force | Out-Null   
}

# Save variable tags in a new variable to add tags.
$tagsResourceGroup = $tags

# Set tags rg storage.
Set-AzResourceGroup -Name $rgNameBackup -Tag $tagsResourceGroup | Out-Null

Write-Host ($writeEmptyLine + "# Resource group $rgNameBackup available with tags" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create a resource group backup irp if one does not already exist. Also, apply the necessary tags to this resource group.

try {
    Get-AzResourceGroup -Name $rgNameBackupIrp -ErrorAction Stop | Out-Null 
} catch {
    New-AzResourceGroup -Name $rgNameBackupIrp -Location $region -Force | Out-Null
}

# Save variable tags in a new variable to add tags.
$tagsResourceGroup = $tags

# Set tags rg storage.
Set-AzResourceGroup -Name $rgNameBackupIrp -Tag $tagsResourceGroup | Out-Null

Write-Host ($writeEmptyLine + "# Resource group $rgNameBackupIrp available with tags" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create the Recovery Services vault if it does not exist

try {
    Get-AzRecoveryServicesVault -Name $vaultName -ResourceGroupName $rgNameBackup -ErrorAction Stop | Out-Null 
} catch {
    New-AzRecoveryServicesVault -Name $vaultName -ResourceGroupName $rgNameBackup -Location $region | Out-Null
}

Write-Host ($writeEmptyLine + "# Recovery Services vault $vaultName created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Set specified tags on the Recovery Services vault

$vault = Get-AzRecoveryServicesVault -Name $vaultName -ResourceGroupName $rgNameBackup

# Replace exisiting tags on the Recovery Services vault
Update-AzTag -ResourceId ($vault.Id) -Tag $tags -Operation Replace | Out-Null

Write-Host ($writeEmptyLine + "# Tags Recovery Services vault $vaultName set" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Specify the type of backup storage redundancy for the Recovery Services vault (which can be modified only if there are no backup items protected in the vault)

Set-AzRecoveryServicesBackupProperty -Vault $vault -BackupStorageRedundancy $backupStorageRedundancy

Write-Host ($writeEmptyLine + "# Backup storage redundancy is set to $backupStorageRedundancy for Recovery Services vault $vaultName" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Enable Cross Region Restore (CRR)

Set-AzRecoveryServicesBackupProperty -Vault $vault -EnableCrossRegionRestore

Write-Host ($writeEmptyLine + "# Cross Region Restore is enabled for Recovery Services vault $vaultName" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Set the log and metrics settings for the Recovery Services vault if they don't exist

try {
    Get-AzDiagnosticSetting -Name $vaultDiagnosticsName -ResourceId ($vault.Id) -ErrorAction Stop | Out-Null
} catch {   
    $metric = @()
    $metric += New-AzDiagnosticSettingMetricSettingsObject -Enabled $true -Category AllMetrics
    $log = @()
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AzureBackupReport
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category CoreAzureBackup
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AddonAzureBackupJobs
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AddonAzureBackupAlerts
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AddonAzureBackupPolicy
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AddonAzureBackupStorage
    $log += New-AzDiagnosticSettingLogSettingsObject -Enabled $true -Category AddonAzureBackupProtectedInstance
    
    New-AzDiagnosticSetting -Name $vaultDiagnosticsName -ResourceId ($vault.Id) -WorkspaceId ($workSpace.ResourceId) -Log $log -Metric $metric | Out-Null
}

Write-Host ($writeEmptyLine + "# Recovery Services vault $vaultName diagnostic settings set" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Remove the default backup protection policies

Remove-AzRecoveryServicesBackupProtectionPolicy -Name "DefaultPolicy" -VaultId $vault.ID -Force | Out-Null
Remove-AzRecoveryServicesBackupProtectionPolicy -Name "HourlyLogBackup" -VaultId $vault.ID -Force | Out-Null
Remove-AzRecoveryServicesBackupProtectionPolicy -Name "EnhancedPolicy" -VaultId $vault.ID -Force | Out-Null

Write-Host ($writeEmptyLine + "# Default Backup protection policies removed from vault $vaultName" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script completed

Write-Host ($writeEmptyLine + "# Script completed" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------











Azure PowerShell scrip to create a new Backup protection policy

The second Azure PowerShell script automates the deployment process for the Backup protection policy required to back up your AVD personal session hosts. This script includes the following steps and configurations:

  • Remove the breaking change warning messages.
  • Change the current context to the specified subscription.
  • Save the Recovery Services vault from the AVD subscription in a variable.
  • Create a Backup retention policy.


To use the script, first make a copy and save it as “Create-Backup-protection-policy-to-backup-AVD-personal-session-hosts” or you can download it directly from GitHub.

Before running the script, make sure to customize all variables according to your requirements (an example is provided below). Once customized, execute the script from Windows Terminal, Visual Studio Code, or Windows PowerShell. Alternatively, you can directly run it from Cloud Shell.


After adjusting the variables to suit your needs, proceed to run the script with the required parameters:

.\Create-Backup-protection-policy-to-backup-AVD-personal-session-hosts -SubscriptionName <"your Azure (AVD) subscription name here"> -VaultName <"your Azure Recovery Services vault name here">  



<#
.SYNOPSIS

A script used to create a Backup protection policy in a Recovery Services vault to backup AVD personal session-hosts.

.DESCRIPTION

A script used to create a Backup protection policy in a Recovery Services vault to backup AVD personal session-hosts.
The script will do all of the following:

Remove the breaking change warning messages.
Change the current context to the specified Azure Virtual Desktop (AVD) subscription.
Save the Recovery Services vault from the AVD subscription in a variable.
Create a Backup retention policy.

.NOTES

Filename:       Create-Backup-protection-policy-to-backup-AVD-personal-session-hosts.ps1
Created:        10/10/2023
Last modified:  10/10/2023
Author:         Wim Matthyssen
Version:        1.0
PowerShell:     Azure PowerShell and Azure Cloud Shell
Requires:       PowerShell Az (v10.4.1)
Action:         Change variables were needed to fit your needs. 
Disclaimer:     This script is provided "as is" with no warranties.

.EXAMPLE

Connect-AzAccount
Get-AzTenant (if not using the default tenant)
Set-AzContext -tenantID "xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx" (if not using the default tenant)
.\Create-Backup-protection-policy-to-backup-AVD-personal-session-hosts -SubscriptionName <"your Azure (AVD) subscription name here"> -VaultName <"your Azure Recovery Services vault name here">  

.LINK


#>

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Parameters

param(
    # $subscriptionName -> Name of the Azure Subscription
    [parameter(Mandatory =$true)][ValidateNotNullOrEmpty()] [string] $subscriptionName,
    # $vaultName -> Name of the Recovery Services vault
    [parameter(Mandatory =$true)][ValidateNotNullOrEmpty()] [string] $vaultName
)

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Variables

$abbraviationBackupPolicyResourceType = "vm"

$rgNameBackup = #<your backup resource group name here> The name of the Azure resource group in which your new or existing Recovery Services vault deployed. Example: "rg-prd-myh-avd-backup-01"
$rgNameBackupIrpWithoutSuffix = #<your backup irp resource group name here without suffix> The name of the Azure resource group in which your store your instant restore snapshots. Example: "rg-prd-myh-avd-backup-irp-0"

$backupTime = #<your backup schedule time here> The time of your backup schedule. Example: "23:00"
$backupDayOfWeek = #<your backup retention day here> The day of your weekly, monthly and yearly backup retention. Example: "Thursday"
$backupNumberOfWeek = #<your backup retention number of week here> The number of week of your monthly and yearly backup retention. Example: "Third"
$backupYMonthOfYear = #<your backup retention month of year here> The month of your yearly backup retention. Example: "December"

$durationCountInDays = #<your daily backup number here> The number of dialy backup points. Example: 27
$durationCountInWeeks = #<your daily backup number here> The number of weekly backup points. Example: 54
$durationCountInMonths = #<your daily backup number here> The number of monthly backup points. Example: 12
$durationCountInYears = #<your daily backup number here> The number of yearly backup points. Example: 3

$backupPolicyWorkloadType = "AzureVM"
$backupPolicyTime = #<your backup policy name time part here> The time part of your backup policy name. Example: "11pm"
$backupPolicyDayShort = #<your backup policy name shortend day part here> The shortend day part of your backup policy name. Example: "thu"
$backupPolicyInstantRestoreDays = "ir" + "2"
$backupPolicyRetentionDays = "d" + $durationCountInDays.ToString()
$backupPolicyRetentionWeeks = "w" + $durationCountInWeeks.ToString()
$backupPolicyRetentionMonths = "m" + $durationCountInMonths.ToString()
$backupPolicyRetentionYears = "y" + $durationCountInYears.ToString()
 
$backupPolicyRetentionSettings = $backupPolicyInstantRestoreDays + "-" + $backupPolicyRetentionDays + "-" + $backupPolicyRetentionWeeks + "-" + $backupPolicyRetentionMonths + "-" + $backupPolicyRetentionYears 
$backupPolicyName = "bp" + "-" + $spoke + "-" + $abbraviationLZPurpose + "-" + $abbraviationBackupPolicyResourceType + "-" + $backupPolicyTime + "-" + $backupPolicyDayShort + "-" + $backupPolicyRetentionSettings

Set-PSBreakpoint -Variable currenttime -Mode Read -Action {$global:currenttime = Get-Date -Format "dddd MM/dd/yyyy HH:mm"} | Out-Null 
$foregroundColor1 = "Green"
$foregroundColor2 = "Yellow"
$writeEmptyLine = "`n"
$writeSeperatorSpaces = " - "

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Remove the breaking change warning messages

Set-Item -Path Env:\SuppressAzurePowerShellBreakingChangeWarnings -Value $true | Out-Null
Update-AzConfig -DisplayBreakingChangeWarning $false | Out-Null
$warningPreference = "SilentlyContinue"

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script started

Write-Host ($writeEmptyLine + "# Script started. Without errors, it can take up to 1 minute to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Change the current context to the specified subscription

$subName = Get-AzSubscription | Where-Object {$_.Name -like $subscriptionName}

Set-AzContext -SubscriptionId $subName.SubscriptionId | Out-Null 

Write-Host ($writeEmptyLine + "# Specified subscription in current tenant selected" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Save the Recovery Services vault from the AVD subscription in a variable

$vault = Get-AzRecoveryServicesVault -Name $vaultName -ResourceGroupName $rgNameBackup

Write-Host ($writeEmptyLine + "# Recovery Services vault variable created" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create a Backup retention policy

$backupTimeObject = Get-Date -Date ("2023-10-1 " + $backupTime + ":00Z")

# Gets a base SchedulePolicyObject and stores it in the $schedulePolicy variable
$schedulePolicy = Get-AzRecoveryServicesBackupSchedulePolicyObject -WorkloadType $backupPolicyWorkloadType

# Set timezone, remove all the scheduled run times from the $schedulePolicy, and set the backup time
$timeZone = Get-TimeZone
$schedulePolicy.ScheduleRunTimeZone = $timeZone.Id
$schedulePolicy.ScheduleRunTimes.Clear()
$schedulePolicy.ScheduleRunTimes.Add($backupTimeObject.ToUniversalTime())

# Gets the base RetentionPolicy object and then stores it in the $retentionPolicy variable
$retentionPolicy = Get-AzRecoveryServicesBackupRetentionPolicyObject -WorkloadType $backupPolicyWorkloadType
$retentionPolicy.ScheduleRunTimes

# Sets the retention duration policy settings
# Number of backups
$retentionPolicy.DailySchedule.DurationCountInDays = $durationCountInDays
$retentionPolicy.WeeklySchedule.DurationCountInWeeks = $durationCountInWeeks
$retentionPolicy.MonthlySchedule.DurationCountInMonths = $durationCountInMonths
$retentionPolicy.YearlySchedule.DurationCountInYears = $durationCountInYears

# Additional weekly settings
$retentionPolicy.WeeklySchedule.DaysOfTheWeek  = $backupDayOfWeek

# Additional monthly settings
$retentionPolicy.MonthlySchedule.RetentionScheduleWeekly.WeeksOfTheMonth = $backupNumberOfWeek
$retentionPolicy.MonthlySchedule.RetentionScheduleWeekly.DaysOfTheWeek = $backupDayOfWeek

# Additional yearly settings
$retentionPolicy.YearlySchedule.MonthsOfYear = $backupYMonthOfYear
$retentionPolicy.YearlySchedule.RetentionScheduleWeekly.WeeksOfTheMonth = $backupNumberOfWeek
$retentionPolicy.YearlySchedule.RetentionScheduleWeekly.DaysOfTheWeek = $backupDayOfWeek

# Create new policy with Archive smart tiering with TieringMode TierRecommended enabled
New-AzRecoveryServicesBackupProtectionPolicy -Name $backupPolicyName -RetentionPolicy $retentionPolicy -SchedulePolicy $schedulePolicy -VaultId $vault.ID -WorkloadType $backupPolicyWorkloadType `
-MoveToArchiveTier $true -TieringMode TierRecommended -BackupSnapshotResourceGroup $rgNameBackupIrpWithoutSuffix | Out-Null 

Write-Host ($writeEmptyLine + "# Backup retention policy with name $backupPolicyName available" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script completed

Write-Host ($writeEmptyLine + "# Script completed" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------







After deploying the backup policy, you can add your AVD personal session hosts* as protected items within your Recovery Services vault.





*For governance and management reasons, it’s recommended to attach a tag to the Azure VM resource specifying the backup protection policy in use.


Conclusion

Securing and maintaining the integrity of your users’ individual desktops in your AVD infrastructure is vital. This ensures a strong and dependable AVD setup, reduces disruptions, and preserves the smooth operation of the workloads and applications running on these desktops.

I hope that the PowerShell scripts shared in this blog post will prove valuable to you, offering a solid foundation for setting up an Azure Backup Recovery Services vault along with a Backup Protection Policy.

Should you have any questions or suggestions regarding these scripts, feel free to reach out to me through my Twitter handle (@wmatthyssen) or simply leave a comment, and I’ll be more than happy to assist.


Unknown's avatar

Wim is an Azure Technical Advisor and Trainer with over fifteen years of Microsoft technology experience. As a Microsoft Certified Trainer (MCT), his strength is assisting companies in the transformation of their businesses to the Cloud by implementing the latest features, services, and solutions. Currently, his main focus is on the Microsoft Hybrid Cloud Platform, and especially on Microsoft Azure and the Azure hybrid services.   Wim is also a Microsoft MVP in the Azure category and a founding board member of the MC2MC user group. As a passionate community member, he regularly writes blogs and speaks about his daily experiences with Azure and other Microsoft technologies.

1 comment on “Set up an Azure Backup Recovery Services vault and Backup protection policy to backup your AVD personal session hosts

  1. Pingback: AVD Community Newsletter – 12th October 2023 – AVD Community

Leave a comment