scripts/PowerShell/Scripts/Recovery/Remove-rsv.ps1 (223 lines of code) (raw):

[CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory)] [string]$VaultName, [Parameter(Mandatory)] [string]$ResourceGroup, [Parameter(Mandatory)] [string]$SubscriptionId, [Parameter()] [string]$Tenant = (Get-AzContext).Tenant.Id ) # LATER: Add PS version check (7) # LATER: Add SYNOPSIS, DESCRIPTION, EXAMPLES, PARAMETERS $RSmodule = Get-Module -Name Az.RecoveryServices -ListAvailable $NWmodule = Get-Module -Name Az.Network -ListAvailable $RSversion = $RSmodule.Version.ToString() $NWversion = $NWmodule.Version.ToString() if ($RSversion -lt "5.3.0") { Uninstall-Module -Name Az.RecoveryServices Set-ExecutionPolicy -ExecutionPolicy Unrestricted Install-Module -Name Az.RecoveryServices -Repository PSGallery -Force -AllowClobber } if ($NWversion -lt "4.15.0") { Uninstall-Module -Name Az.Network Set-ExecutionPolicy -ExecutionPolicy Unrestricted Install-Module -Name Az.Network -Repository PSGallery -Force -AllowClobber } Select-AzSubscription $SubscriptionId -Tenant $Tenant | Out-Null $VaultToDelete = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup # Ignore WhatIfPreference here because future cmdlets will fail without this being set # This should have no side effects Set-AzRecoveryServicesAsrVaultContext -Vault $VaultToDelete -WhatIf:$false $UpdatedVault = Update-AzRecoveryServicesVault -ResourceGroupName $VaultToDelete.ResourceGroupName -Name $VaultToDelete.Name -ImmutabilityState "Disabled" Write-Host "Immutability state set to $($UpdatedVault.Properties.ImmutabilitySettings.ImmutabilityState)" Set-AzRecoveryServicesVaultProperty -Vault $VaultToDelete.ID -SoftDeleteFeatureState Disable #disable soft delete Write-Host "Soft delete disabled for the vault" $VaultName $containerSoftDelete = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $VaultToDelete.ID | Where-Object { $_.DeleteState -eq "ToBeDeleted" } #fetch backup items in soft delete state foreach ($softitem in $containerSoftDelete) { Undo-AzRecoveryServicesBackupItemDeletion -Item $softitem -VaultId $VaultToDelete.ID -Force #undelete items in soft delete state } # Fetch MSSQL backup items in soft delete state $containerSoftDeleteSql = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $VaultToDelete.ID | Where-Object { $_.DeleteState -eq "ToBeDeleted" } foreach ($softitemsql in $containerSoftDeleteSql) { Undo-AzRecoveryServicesBackupItemDeletion -Item $softitemsql -VaultId $VaultToDelete.ID -Force #undelete items in soft delete state } # Invoking API to disable Security features (Enhanced Security) to remove MARS/MAB/DPM servers. Set-AzRecoveryServicesVaultProperty -VaultId $VaultToDelete.ID -DisableHybridBackupSecurityFeature $true Write-Host "Disabled Security features for the vault" # Fetch all protected items and servers $backupItemsVM = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $VaultToDelete.ID $backupItemsSQL = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $VaultToDelete.ID $backupItemsAFS = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $VaultToDelete.ID $backupItemsSAP = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $VaultToDelete.ID $backupContainersSQL = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -VaultId $VaultToDelete.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } $protectableItemsSQL = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $VaultToDelete.ID | Where-Object { $_.IsAutoProtected -eq $true } $backupContainersSAP = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -VaultId $VaultToDelete.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } $StorageAccounts = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -VaultId $VaultToDelete.ID $backupServersMARS = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $VaultToDelete.ID $backupServersMABS = Get-AzRecoveryServicesBackupManagementServer -VaultId $VaultToDelete.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } $backupServersDPM = Get-AzRecoveryServicesBackupManagementServer -VaultId $VaultToDelete.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } $pvtendpoints = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $VaultToDelete.ID foreach ($item in $backupItemsVM) { Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $VaultToDelete.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure VM backup items } Write-Host "Disabled and deleted Azure VM backup items" foreach ($item in $backupItemsSQL) { Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $VaultToDelete.ID -RemoveRecoveryPoints -Force #stop backup and delete SQL Server in Azure VM backup items } Write-Host "Disabled and deleted SQL Server backup items" foreach ($item in $protectableItemsSQL) { Disable-AzRecoveryServicesBackupAutoProtection -BackupManagementType AzureWorkload -WorkloadType MSSQL -InputItem $item -VaultId $VaultToDelete.ID #disable auto-protection for SQL } Write-Host "Disabled auto-protection and deleted SQL protectable items" foreach ($item in $backupContainersSQL) { Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $VaultToDelete.ID #unregister SQL Server in Azure VM protected server } Write-Host "Deleted SQL Servers in Azure VM containers" foreach ($item in $backupItemsSAP) { Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $VaultToDelete.ID -RemoveRecoveryPoints -Force #stop backup and delete SAP HANA in Azure VM backup items } Write-Host "Disabled and deleted SAP HANA backup items" foreach ($item in $backupContainersSAP) { Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $VaultToDelete.ID #unregister SAP HANA in Azure VM protected server } Write-Host "Deleted SAP HANA in Azure VM containers" foreach ($item in $backupItemsAFS) { Disable-AzRecoveryServicesBackupProtection -Item $item -VaultId $VaultToDelete.ID -RemoveRecoveryPoints -Force #stop backup and delete Azure File Shares backup items } Write-Host "Disabled and deleted Azure File Share backups" foreach ($item in $StorageAccounts) { Unregister-AzRecoveryServicesBackupContainer -container $item -Force -VaultId $VaultToDelete.ID #unregister storage accounts } Write-Host "Unregistered Storage Accounts" foreach ($item in $backupServersMARS) { Unregister-AzRecoveryServicesBackupContainer -Container $item -Force -VaultId $VaultToDelete.ID #unregister MARS servers and delete corresponding backup items } Write-Host "Deleted MARS Servers" foreach ($item in $backupServersMABS) { Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $VaultToDelete.ID #unregister MABS servers and delete corresponding backup items } Write-Host "Deleted MAB Servers" foreach ($item in $backupServersDPM) { Unregister-AzRecoveryServicesBackupManagementServer -AzureRmBackupManagementServer $item -VaultId $VaultToDelete.ID #unregister DPM servers and delete corresponding backup items } Write-Host "Deleted DPM Servers" Write-Host "Ensure that you stop protection and delete backup items from the respective MARS, MAB and DPM consoles as well. Visit https://go.microsoft.com/fwlink/?linkid=2186234 to learn more." -ForegroundColor Yellow #Deletion of ASR Items $fabricObjects = Get-AzRecoveryServicesAsrFabric if ($null -ne $fabricObjects) { # First DisableDR all VMs. foreach ($fabricObject in $fabricObjects) { $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject foreach ($containerObject in $containerObjects) { $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject # DisableDR all protected items foreach ($protectedItem in $protectedItems) { Write-Host "Triggering DisableDR(Purge) for item:" $protectedItem.Name Remove-AzRecoveryServicesAsrReplicationProtectedItem -InputObject $protectedItem -Force Write-Host "DisableDR(Purge) completed" } $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping -ProtectionContainer $containerObject # Remove all Container Mappings foreach ($containerMapping in $containerMappings) { Write-Host "Triggering Remove Container Mapping: " $containerMapping.Name Remove-AzRecoveryServicesAsrProtectionContainerMapping -ProtectionContainerMapping $containerMapping -Force Write-Host "Removed Container Mapping." } } $NetworkObjects = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject foreach ($networkObject in $NetworkObjects) { # Get the PrimaryNetwork $PrimaryNetwork = Get-AzRecoveryServicesAsrNetwork -Fabric $fabricObject -FriendlyName $networkObject $NetworkMappings = Get-AzRecoveryServicesAsrNetworkMapping -Network $PrimaryNetwork foreach ($networkMappingObject in $NetworkMappings) { # Get the Network Mappings $NetworkMapping = Get-AzRecoveryServicesAsrNetworkMapping -Name $networkMappingObject.Name -Network $PrimaryNetwork Remove-AzRecoveryServicesAsrNetworkMapping -InputObject $NetworkMapping } } # Remove Fabric Write-Host "Triggering Remove Fabric:" $fabricObject.FriendlyName Remove-AzRecoveryServicesAsrFabric -InputObject $fabricObject -Force Write-Host "Removed Fabric." } } Write-Host "Warning: This script will only remove the replication configuration from Azure Site Recovery and not from the source. Please cleanup the source manually. Visit https://go.microsoft.com/fwlink/?linkid=2182781 to learn more." -ForegroundColor Yellow foreach ($item in $pvtendpoints) { $penamesplit = $item.Name.Split(".") $pename = $penamesplit[0] Remove-AzPrivateEndpointConnection -ResourceId $item.Id -Force #remove private endpoint connections Remove-AzPrivateEndpoint -Name $pename -ResourceGroupName $ResourceGroup -Force #remove private endpoints } Write-Host "Removed Private Endpoints" # Recheck ASR items in vault $fabricCount = 0 $ASRProtectedItems = 0 $ASRPolicyMappings = 0 $fabricObjects = Get-AzRecoveryServicesAsrFabric if ($null -ne $fabricObjects) { foreach ($fabricObject in $fabricObjects) { $containerObjects = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabricObject foreach ($containerObject in $containerObjects) { $protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $containerObject foreach ($protectedItem in $protectedItems) { $ASRProtectedItems++ } $containerMappings = Get-AzRecoveryServicesAsrProtectionContainerMapping -ProtectionContainer $containerObject foreach ($containerMapping in $containerMappings) { $ASRPolicyMappings++ } } $fabricCount++ } } #Recheck presence of backup items in vault $backupItemsVMFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureVM -WorkloadType AzureVM -VaultId $VaultToDelete.ID $backupItemsSQLFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType MSSQL -VaultId $VaultToDelete.ID $backupContainersSQLFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -VaultId $VaultToDelete.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SQL" } $protectableItemsSQLFin = Get-AzRecoveryServicesBackupProtectableItem -WorkloadType MSSQL -VaultId $VaultToDelete.ID | Where-Object { $_.IsAutoProtected -eq $true } $backupItemsSAPFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureWorkload -WorkloadType SAPHanaDatabase -VaultId $VaultToDelete.ID $backupContainersSAPFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureVMAppContainer -VaultId $VaultToDelete.ID | Where-Object { $_.ExtendedInfo.WorkloadType -eq "SAPHana" } $backupItemsAFSFin = Get-AzRecoveryServicesBackupItem -BackupManagementType AzureStorage -WorkloadType AzureFiles -VaultId $VaultToDelete.ID $StorageAccountsFin = Get-AzRecoveryServicesBackupContainer -ContainerType AzureStorage -VaultId $VaultToDelete.ID $backupServersMARSFin = Get-AzRecoveryServicesBackupContainer -ContainerType "Windows" -BackupManagementType MAB -VaultId $VaultToDelete.ID $backupServersMABSFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $VaultToDelete.ID | Where-Object { $_.BackupManagementType -eq "AzureBackupServer" } $backupServersDPMFin = Get-AzRecoveryServicesBackupManagementServer -VaultId $VaultToDelete.ID | Where-Object { $_.BackupManagementType -eq "SCDPM" } $pvtendpointsFin = Get-AzPrivateEndpointConnection -PrivateLinkResourceId $VaultToDelete.ID #Display items which are still present in the vault and might be preventing vault deletion. if ($backupItemsVMFin.count -ne 0) { Write-Host $backupItemsVMFin.count "Azure VM backups are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupItemsSQLFin.count -ne 0) { Write-Host $backupItemsSQLFin.count "SQL Server Backup Items are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupContainersSQLFin.count -ne 0) { Write-Host $backupContainersSQLFin.count "SQL Server Backup Containers are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($protectableItemsSQLFin.count -ne 0) { Write-Host $protectableItemsSQLFin.count "SQL Server Instances are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupItemsSAPFin.count -ne 0) { Write-Host $backupItemsSAPFin.count "SAP HANA Backup Items are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupContainersSAPFin.count -ne 0) { Write-Host $backupContainersSAPFin.count "SAP HANA Backup Containers are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupItemsAFSFin.count -ne 0) { Write-Host $backupItemsAFSFin.count "Azure File Shares are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($StorageAccountsFin.count -ne 0) { Write-Host $StorageAccountsFin.count "Storage Accounts are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupServersMARSFin.count -ne 0) { Write-Host $backupServersMARSFin.count "MARS Servers are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupServersMABSFin.count -ne 0) { Write-Host $backupServersMABSFin.count "MAB Servers are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($backupServersDPMFin.count -ne 0) { Write-Host $backupServersDPMFin.count "DPM Servers are still registered to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($ASRProtectedItems -ne 0) { Write-Host $ASRProtectedItems "ASR protected items are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($ASRPolicyMappings -ne 0) { Write-Host $ASRPolicyMappings "ASR policy mappings are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($fabricCount -ne 0) { Write-Host $fabricCount "ASR Fabrics are still present in the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($pvtendpointsFin.count -ne 0) { Write-Host $pvtendpointsFin.count "Private endpoints are still linked to the vault. Remove the same for successful vault deletion." -ForegroundColor Red } if ($PSCmdlet.ShouldProcess($VaultName, "DELETE")) { $RestMethodParameters = @{ Method = 'DELETE' SubscriptionId = $SubscriptionId ResourceGroupName = $ResourceGroup ResourceProviderName = 'Microsoft.RecoveryServices' ResourceType = 'vaults' Name = $VaultName ApiVersion = '2024-04-01' } $Response = Invoke-AzRestMethod @RestMethodParameters Write-Verbose "DELETE HTTP request returned status code: $($Response.StatusCode)" $VaultDeleted = Get-AzRecoveryServicesVault -Name $VaultName -ResourceGroupName $ResourceGroup -ErrorAction 'SilentlyContinue' if ($null -eq $VaultDeleted) { Write-Host "Recovery Services Vault '$VaultName' successfully deleted." } else { Write-Error "Recovery Services Vault '$VaultName' was not successfully deleted. Status code: $($Response.StatusCode)." } }