Created
July 18, 2024 16:52
-
-
Save adbertram/b6817436a9689545f2ce7793373d436a to your computer and use it in GitHub Desktop.
N2WS Azure Site Recovery Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Corrected Azure Site Recovery PowerShell Script with Azure CLI Commands | |
# Set variables (modify these as needed) | |
$ResourceGroup = "MyASRTestRG" | |
$Location = "eastus" | |
$RecoveryLocation = "westus" | |
$VaultName = "MyASRTestVault" | |
$PrimaryVNet = "PrimaryTestVNet" | |
$RecoveryVNet = "RecoveryTestVNet" | |
$StorageAccount = "myasrteststorage" | |
$RecoveryPlan = "EcommerceTestRecoveryPlan" | |
$TestVNet = "TestFailoverVNet" | |
$ContainerName = "scripts" | |
# VM Configuration | |
$VMConfig = @( | |
@{Name="VM-DB1"; Size="Standard_DS2_v2"; Image="Win2019Datacenter"}, | |
@{Name="VM-APP1"; Size="Standard_DS2_v2"; Image="Win2019Datacenter"}, | |
@{Name="VM-WEB1"; Size="Standard_DS2_v2"; Image="Win2019Datacenter"} | |
) | |
# Ensure you're logged in to Azure CLI | |
az login | |
# Create Resource Group | |
az group create --name $ResourceGroup --location $Location | |
# Create Recovery Services Vault | |
az backup vault create --name $VaultName --resource-group $ResourceGroup --location $Location | |
# Create Primary VNet | |
az network vnet create --resource-group $ResourceGroup --name $PrimaryVNet --address-prefixes 10.0.0.0/16 --subnet-name default --subnet-prefix 10.0.0.0/24 --location $Location | |
# Create Recovery VNet | |
az network vnet create --resource-group $ResourceGroup --name $RecoveryVNet --address-prefixes 10.1.0.0/16 --subnet-name default --subnet-prefix 10.1.0.0/24 --location $RecoveryLocation | |
# Create Test Failover VNet | |
az network vnet create --resource-group $ResourceGroup --name $TestVNet --address-prefixes 10.2.0.0/16 --subnet-name default --subnet-prefix 10.2.0.0/24 --location $RecoveryLocation | |
# Create subnets for ASR | |
az network vnet subnet create ` | |
--name ASR_Subnet ` | |
--resource-group $ResourceGroup ` | |
--vnet-name $PrimaryVNet ` | |
--address-prefix 10.0.1.0/24 | |
az network vnet subnet create ` | |
--name ASR_Subnet ` | |
--resource-group $ResourceGroup ` | |
--vnet-name $RecoveryVNet ` | |
--address-prefix 10.1.1.0/24 | |
# Set up VNet peering | |
az network vnet peering create ` | |
--name PrimaryToRecovery ` | |
--resource-group $ResourceGroup ` | |
--vnet-name $PrimaryVNet ` | |
--remote-vnet $RecoveryVNet ` | |
--allow-vnet-access | |
az network vnet peering create ` | |
--name RecoveryToPrimary ` | |
--resource-group $ResourceGroup ` | |
--vnet-name $RecoveryVNet ` | |
--remote-vnet $PrimaryVNet ` | |
--allow-vnet-access | |
# Create and configure Network Security Groups (NSGs) | |
az network nsg create --name ASR_NSG --resource-group $ResourceGroup --location $Location | |
az network nsg rule create ` | |
--name AllowASRTraffic ` | |
--nsg-name ASR_NSG ` | |
--priority 100 ` | |
--resource-group $ResourceGroup ` | |
--access Allow ` | |
--protocol Tcp ` | |
--direction Inbound ` | |
--source-address-prefixes AzureSiteRecovery ` | |
--source-port-ranges "*" ` | |
--destination-address-prefixes "*" ` | |
--destination-port-ranges 443 | |
# Configure storage | |
az storage account create ` | |
--name $StorageAccount ` | |
--resource-group $ResourceGroup ` | |
--location $Location ` | |
--sku Standard_RAGRS ` | |
--kind StorageV2 | |
# Create a container for scripts | |
az storage container create --name $ContainerName --account-name $StorageAccount | |
# Create check_db.ps1 script | |
$CheckDbScript = @" | |
# check_db.ps1 | |
`$ServerInstance = "VM-DB1" | |
`$Database = "TestDB" | |
try { | |
`$query = "SELECT COUNT(*) FROM sys.databases WHERE name = '`$Database'" | |
`$result = Invoke-Sqlcmd -ServerInstance `$ServerInstance -Query `$query | |
if (`$result.Column1 -eq 1) { | |
Write-Output "Database '`$Database' exists and is accessible." | |
# Perform a simple query to check data | |
`$dataQuery = "SELECT TOP 1 * FROM TestTable" | |
`$dataResult = Invoke-Sqlcmd -ServerInstance `$ServerInstance -Database `$Database -Query `$dataQuery | |
if (`$dataResult) { | |
Write-Output "Successfully queried data from the database." | |
} else { | |
Write-Output "Database exists but no data retrieved. Further investigation may be needed." | |
} | |
} else { | |
Write-Error "Database '`$Database' does not exist or is not accessible." | |
} | |
} catch { | |
Write-Error "An error occurred: `$(`$_.Exception.Message)" | |
} | |
"@ | |
# Save check_db.ps1 to a local file | |
$CheckDbScript | Out-File -FilePath "check_db.ps1" -Encoding utf8 | |
# Upload check_db.ps1 to the storage account | |
az storage blob upload ` | |
--account-name $StorageAccount ` | |
--container-name $ContainerName ` | |
--name check_db.ps1 ` | |
--file check_db.ps1 | |
# Create VMs | |
foreach ($vm in $VMConfig) { | |
az vm create ` | |
--resource-group $ResourceGroup ` | |
--name $vm.Name ` | |
--image $vm.Image ` | |
--size $vm.Size ` | |
--vnet-name $PrimaryVNet ` | |
--subnet default ` | |
--admin-username azureuser ` | |
--admin-password "ComplexPassword123!" ` | |
--location $Location | |
} | |
# Enable backup for the VMs | |
foreach ($vm in $VMConfig) { | |
az backup protection enable-for-vm ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--vm $vm.Name ` | |
--policy-name DefaultPolicy | |
} | |
# Create a Recovery Services fabric | |
az site-recovery fabric create ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--name "PrimaryFabric" | |
az site-recovery fabric create ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--name "RecoveryFabric" | |
# Create a protection container in the primary fabric | |
az site-recovery protection-container create ` | |
--fabric-name "PrimaryFabric" ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--name "PrimaryProtectionContainer" | |
# Create a protection container in the recovery fabric | |
az site-recovery protection-container create ` | |
--fabric-name "RecoveryFabric" ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--name "RecoveryProtectionContainer" | |
# Create a replication policy | |
az site-recovery replication-policy create ` | |
--name "ReplicationPolicy" ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--recovery-point-retention-in-hours 24 ` | |
--app-consistent-frequency-in-minutes 60 | |
# Create protection container mapping between primary and recovery containers | |
az site-recovery protection-container-mapping create ` | |
--name "ContainerMapping" ` | |
--policy-name "ReplicationPolicy" ` | |
--protection-container "PrimaryProtectionContainer" ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--recovery-fabric "RecoveryFabric" ` | |
--recovery-protection-container "RecoveryProtectionContainer" | |
# Enable replication for each VM | |
foreach ($vm in $VMConfig) { | |
az site-recovery replicated-item create ` | |
--name $vm.Name ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--source-vm $vm.Name ` | |
--protection-container "PrimaryProtectionContainer" ` | |
--recovery-fabric "RecoveryFabric" ` | |
--recovery-protection-container "RecoveryProtectionContainer" ` | |
--recovery-point-retention-in-hours 24 | |
} | |
# Create a Recovery Plan | |
az site-recovery recovery-plan create ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--primary-fabric "PrimaryFabric" ` | |
--recovery-fabric "RecoveryFabric" | |
# Add VMs to the Recovery Plan | |
$VMNames = $VMConfig.Name -join " " | |
az site-recovery recovery-plan update ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--add-protectable-items $VMNames | |
# Add custom actions to the Recovery Plan | |
$ScriptUri = "https://$StorageAccount.blob.core.windows.net/$ContainerName/check_db.ps1" | |
az site-recovery recovery-plan update ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--add-post-action ` | |
"{`"resourceId`": `"`", `"actionType`": `"AutomationRunbookAction`", `"customDetails`": {`"runbookUri`": `"$ScriptUri`", `"name`": `"CheckDB`", `"description`": `"Check DB after failover`"}}" | |
az site-recovery recovery-plan update ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--add-pre-action ` | |
"{`"resourceId`": `"`", `"actionType`": `"ManualAction`", `"customDetails`": {`"name`": `"Update DNS records`", `"description`": `"Update DNS A record for app.mycompany.com to point to new IP`"}}" | |
# Initiate a test failover | |
az site-recovery recovery-plan test-failover start ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName ` | |
--recovery-point Latest ` | |
--test-network $TestVNet | |
# Clean up test failover | |
# Note: Run this after you've verified the test failover | |
az site-recovery recovery-plan test-failover cleanup ` | |
--name $RecoveryPlan ` | |
--resource-group $ResourceGroup ` | |
--vault-name $VaultName | |
Write-Output "Azure Site Recovery setup and test completed." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment