Restore an encrypted VM via PowerShell

Restoring an encrypted VM from the Recovery Services vault using the Azure Portal is relatively simple to do; select the desired restore point, choose to restore the VM and deploy the template.
This process takes care of the heavy lifting by rebuilding the VM from that point in time and ensuring it has also has access to the secret stored in the Key vault to start BitLocker.

You can also achieve the same result via PowerShell. While this approach requires much more effort, it has its advantages.
If you are experiencing issues restoring an encrypted VM via the Azure Portal (this was an issue I experienced some time ago), wanting to have control over the names of the dependent resources to rebuild the VM, ie: NIC and disk(s), but importantly, it providing you with more visibility on how the restore process works.

The script below will need to be edited to suit your environment and is best suited to run this locally on a computer that has the latest Az PowerShell modules installed:

# Reference:
# Firstly, ensure you have the latest 'Install 'Az' modules, Install-Module Az -Scope AllUsers
# Steps 1 to 6 is to perform the restore of the recovery point, Steps 7 re-creates the VM
# Step 1 - Clear any existing variables and connect to the subscription
Remove-Variable * -ErrorAction SilentlyContinue
$Subscription = 'aaaaaaaa-bbbbbb-cccccc-dddddd-eeeeee-ffffff'
Connect-AzAccount -Subscription $Subscription

# Step 2 - Declare some variables
$RecoveryVaultRGName = "myrsvname"
$RecoveryVault = Get-AzRecoveryServicesVault
$KeyVaultName = "mykeyvault"
$KeyVault = Get-AzKeyVault -VaultName $KeyVaultName
$KeyVaultID = $KeyVault.ResourceId
$VMName = "test1"
$VMRGName = "Test"
$StorageAccountRestore = "mystorageaccount"
$StorageAccountRestoreRGName = "Storage"
$VMRestoreName = "test1-restored"
$VMRestoreRGName = "Test"
$VMVNETName = "magrin"
$VMVNETRGName = "Servers"
# Select the desired Subnet Index. The 1st Subnet in the VNET starts with '0', the second is '1', etc... 
$VMNICLocation = "eastus"

# Step 3 - Select the VM to restore
$NamedContainer = Get-AzRecoveryServicesBackupContainer  -ContainerType "AzureVM" -Status "Registered" -FriendlyName "$VMName" -VaultId $RecoveryVault.ID -ResourceGroupName $VMRGName
$BackupItem = Get-AzRecoveryServicesBackupItem -Container $NamedContainer  -WorkloadType "AzureVM" -VaultId $RecoveryVault.ID

# Step 4 - Select the latest recovery point to restore the VM
$StartDate = (Get-Date).AddDays(-7)
$EndDate = Get-Date
$RestorePoint = Get-AzRecoveryServicesBackupRecoveryPoint -Item $BackupItem -StartDate $StartDate.ToUniversalTime() -EndDate $EndDate.ToUniversalTime() -VaultId $RecoveryVault.ID

# Step 5 - Restore the latest recovery point
Get-AzRecoveryServicesVault | Set-AzRecoveryServicesVaultContext
$RestoreJob = Restore-AzRecoveryServicesBackupItem -RecoveryPoint $RestorePoint[0] -StorageAccountName "$StorageAccountRestore" -StorageAccountResourceGroupName "$RecoveryVaultRGName" -VaultId $RecoveryVault.ID

# Step 6 - Retrieve restoration details of the recovery point
$Details = Get-AzRecoveryServicesBackupJobDetails -Job $RestoreJob -VaultId $targetVault.ID
Write-Host ""
Write-Host Before proceeding, make sure the restore has completed -ForegroundColor Yellow
Write-Host ""

# Step 7 - Prepare the VM creation from restore recovery point
# You can discover the $ContainerName, $TemplateName, $ConfigBlobName and $ConfigBlobName values within the container of the restored recovery point
# Declare some variables for VM's with BitLocker
$ConfigBlobName = "config-test1-aaaaaaaa-bbbb-bbbb-cccc-dddd-eeee-ffff.json"
$ContainerName = "test1-a7896a4a92c64fa894c84cdf4d94f314"
$TemplateName = "azuredeployaaaaaaaa-bbbb-bbbb-cccc-dddd-eeee-ffff.json"
$VMKeyVaultSecret = ""
$JSONpath = ".\vmconfig.json"

# Step 8 - Prepare the VM restore
Set-AzCurrentStorageAccount -Name $StorageAccountRestore -ResourceGroupName $StorageAccountRestoreRGName
New-AzStorageBlobSASToken -Container $ContainerName -Blob $TemplateName -Permission r -FullUri
Get-AzStorageBlobContent -Container $ContainerName -Blob $ConfigBlobName -Destination $JSONpath
$VMObject = ((Get-Content -Path $JSONpath -Raw -Encoding Unicode)).TrimEnd([char]0x00) | ConvertFrom-Json
$VMCreateName = New-AzVMConfig -VMSize $VMObject.'properties.hardwareProfile'.vmSize -VMName "$VMRestoreName"
Set-AzVMOSDisk -VM $VMCreateName -Name "$VMRestoreName" -VhdUri $VMObject.'properties.StorageProfile'.OsDisk.vhd.Uri -CreateOption "Attach"
$VMCreateName.StorageProfile.OsDisk.OsType = $VMObject.'properties.StorageProfile'.OsDisk.OsType
$VMKeyVaultSecret = "$VMKeyVaultSecret"
Set-AzVMOSDisk -VM $VMCreateName -Name "test1-restored-OsDisk" -VhdUri $VMObject.'properties.storageProfile'.osDisk.vhd.uri -DiskEncryptionKeyUrl $VMKeyVaultSecret -DiskEncryptionKeyVaultId $KeyVaultId -CreateOption "Attach" -Windows
$VMCreateName.StorageProfile.OsDisk.OsType = $VMObject.'properties.storageProfile'.osDisk.osType

# Add additional disk(s) or comment out the additional 'Add-AzVMDataDisk' lines below, including the correct Disk Sizes
$VMCreateName = Add-AzVMDataDisk -VM $VMCreateName -Name "test1-restored-datadisk0" -VhdUri -DiskSizeInGB 32 -Lun 0 -CreateOption "Attach"
#$VMCreateName = Add-AzVMDataDisk -VM $VMCreateName -Name "test1-restored-datadisk1" -VhdUri -DiskSizeInGB 128 -Lun 1 -CreateOption "Attach"
#$VMCreateName = Add-AzVMDataDisk -VM $VMCreateName -Name "test1-restored-datadisk2" -VhdUri -DiskSizeInGB 256 -Lun 2 -CreateOption "Attach"
#$VMCreateName = Add-AzVMDataDisk -VM $VMCreateName -Name "test1-restored-datadisk3" -VhdUri -DiskSizeInGB 128 -Lun 3 -CreateOption "Attach"
$VNETName = Get-AzVirtualNetwork -Name "$VMVNETName" -ResourceGroupName "$VMVNETRGName"
$VMNIC = New-AzNetworkInterface -Name $VMNICName -ResourceGroupName "$VMRestoreRGName" -Location "$VMNICLocation" -SubnetId $VNETName.Subnets[$VNETSubnetIndex].Id 
$VMCreateName=Add-AzVMNetworkInterface -VM $VMCreateName -Id $VMNIC.Id

# Step 9 - Start the VM restore
New-AzVM -ResourceGroupName "$VMRestoreRGName" -Location "$VMNICLocation" -VM $VMCreateName