#All sections that need personalization have the comment ##Custom $connectionName = "AzureRunAsConnection" ##Custom $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint -EnvironmentName AzureCloud $subscriptionid = "" ##Custom #Do not update these keys as they are specific to the host - ##Custom $excludedkeys = @() $excludedkeys += "APPINSIGHTS_INSTRUMENTATIONKEY" $excludedkeys += "AzureWebJobsStorage" $excludedkeys += "FUNCTIONS_EXTENSION_VERSION" $excludedkeys += "FUNCTIONS_WORKER_RUNTIME" $excludedkeys += "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" $excludedkeys += "WEBSITE_CONTENTSHARE" $excludedkeys += "WEBSITE_NODE_DEFAULT_VERSION" $excludedkeys += "AzureWebJobsDashboard" $excludedkeys += "FUNCTION_APP_EDIT_MODE" $excludedkeys += "INT_URL" $excludedkeys += "ApplicationInsightsAgent_EXTENSION_VERSION" $excludedkeys += "APPINSIGHTS_PROFILERFEATURE_VERSION" $excludedkeys += "APPINSIGHTS_SNAPSHOTFEATURE_VERSION" $excludedkeys += "DiagnosticServices_EXTENSION_VERSION" $excludedkeys += "InstrumentationEngine_EXTENSION_VERSION" $excludedkeys += "SnapshotDebugger_EXTENSION_VERSION" $excludedkeys += "XDT_MicrosoftApplicationInsights_BaseExtensions" $excludedkeys += "XDT_MicrosoftApplicationInsights_Mode" #Replace Storage Connection keys with new values for HA region - ##Custom $replacedkeys = @() $replacedkeys += "StorageConn1" $replacedkeys += "StorageConn2" $replacedkeys += "StorageConn3" #This is the connection string for HA region $newstorageconn = "" ##Custom #List of apps that need to be started/stopped as they have scheduled jobs $namestofailover = @() $namestofailover += "AppThatHasScheduledJob" ##Custom $allapps = Get-AzureRmWebApp $currentAzureContext = Get-AzureRmContext $azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile) $prefix = "corp-*" ##Custom $domainprefix = "comp-*.corp.com*" ##Custom $manualinclude = "include-this-app-name" ##Custom #Get both primary and HA region apps $primaryapps = $allapps.where{$_.name -like $prefix -and ($_.enabledhostnames -like $domainprefix -or $_.name -eq $manualinclude)} $haapps = $allapps.where{$_.name -like "ha-$($prefix)" -and ($_.enabledhostnames -like $domainprefix -or $_.name -eq $manualinclude)} foreach ($app in $primaryapps) { $haapp = $haapps.where{$_.name -eq "ha-$($app.name)"} Write-Output "$($app.name) > $($haapp.name)" if ($app.name -in $namestofailover) { Write-Output "Starting" Invoke-AzureRmResourceAction -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites -ResourceName "$($haapp.Name)" -Action start -ApiVersion 2018-02-01 -Force | Out-Null } #Get prod and HA settings and compare $settings = Invoke-AzureRmResourceAction -ResourceGroupName $app.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($app.Name)/appsettings" -Action list -ApiVersion 2018-02-01 -Force $connstrings = Invoke-AzureRmResourceAction -ResourceGroupName $app.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($app.Name)/connectionstrings" -Action list -ApiVersion 2018-02-01 -Force $props = $settings.Properties #dont update the app insights keys $props.psobject.properties.name.where{$_ -in $excludedkeys} | ForEach-Object { $props.psobject.properties.remove($_)} $connprops = $connstrings.Properties #replace queue storage with west coast storage $props.psobject.properties.name.where{$_ -in $replacedkeys} | ForEach-Object { $props."$($_)" = $newstorageconn} $existingsettings = Invoke-AzureRmResourceAction -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($haapp.Name)/appsettings" -Action list -ApiVersion 2018-02-01 -Force $existingconnstrings = Invoke-AzureRmResourceAction -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($haapp.Name)/connectionstrings" -Action list -ApiVersion 2018-02-01 -Force $existingprops = $existingsettings.Properties $existingprops.psobject.properties.name.where{$_ -in $props.psobject.properties.name} | ForEach-Object { $props.psobject.properties.remove($_)} $existingconnprops = $existingconnstrings.Properties $props.psobject.properties.where{$_.name -in $existingprops.psobject.properties.name -and $_.value.value -eq $existingprops."$($_.name)".value } | ForEach-Object { $props.psobject.properties.remove($_.Name)} $connprops.psobject.properties.where{$_.name -in $existingconnprops.psobject.properties.name -and $_.value.value -eq $existingconnprops."$($_.name)".value -and $_.value.type -eq $existingconnprops."$($_.name)".type } | ForEach-Object { $connprops.psobject.properties.remove($_.Name)} #Only add props that dont exist or values have changed $newprops = @{} foreach ( $prop in $existingprops.psobject.Properties){ $newprops += @{$prop.Name = $prop.value} } foreach ( $prop in $props.psobject.Properties){ $newprops += @{$prop.Name = $prop.value} } $newconnprops = @{} foreach ( $prop in $existingconnprops.psobject.Properties){ $newconnprops += @{$prop.Name = $prop.value} } foreach ( $prop in $connprops.psobject.Properties){ $newconnprops += @{$prop.Name = $prop.value} } if (![string]::IsNullOrWhiteSpace($props)) { Write-Output "Writing new app settings" New-AzureRmResource -PropertyObject $newprops -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($haapp.name)/appsettings" -ApiVersion 2018-02-01 -Force } if (![string]::IsNullOrWhiteSpace($connprops)) { Write-Output "Writing new connection strings" New-AzureRmResource -PropertyObject $newconnprops -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName "$($haapp.Name)/connectionstrings" -ApiVersion 2018-02-01 -Force } #Get Azure RM token to be able to access Kudu API $token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId).AccessToken $accessTokenHeader = @{ "Authorization" = "Bearer " + $token } $adminBearerTokenUri = "https://management.azure.com/subscriptions/$($subscriptionid)/resourceGroups/$($app.resourcegroup)/providers/Microsoft.Web/sites/$($app.name)/functions/admin/token?api-version=2018-02-01" $bearer = Invoke-RestMethod -Method Get -Uri $adminBearerTokenUri -Headers $accessTokenHeader $haadminBearerTokenUri = "https://management.azure.com/subscriptions/$($subscriptionid)/resourceGroups/$($haapp.resourcegroup)/providers/Microsoft.Web/sites/$($haapp.name)/functions/admin/token?api-version=2018-02-01" $habearer = Invoke-RestMethod -Method Get -Uri $haadminBearerTokenUri -Headers $accessTokenHeader #Get prod and HA host keys and only update new or changed ones from prod $hostkeys = Invoke-RestMethod -uri "https://$($app.name).azurewebsites.net/admin/host/keys" -Headers @{Authorization=("Bearer {0}" -f $bearer)} $keys = $hostkeys.keys foreach ($key in $keys) { $keys.where{$_.name -eq $key.name}[0].name = "HA-" + $key.name } $hahostkeys = Invoke-RestMethod -uri "https://$($haapp.name).azurewebsites.net/admin/host/keys" -Headers @{Authorization=("Bearer {0}" -f $habearer)} $hakeys = $hahostkeys.keys $keystoremove = @() $keys.where{$parent = $_; $_.name -in $hakeys.name -and $_.value -eq $hakeys.where{$_.name -eq $parent.name}.value } | ForEach-Object { $keystoremove += $_.Name} $newkeys = $keys.where{$_.name -notin $keystoremove} Write-Output "New host keys count: $($newkeys.count)" if ($newkeys.count -gt 0) { foreach ($key in $newkeys) { $topost = @" { "name":"$($key.name)", "value":"$($key.value)" } "@ $habearer = Invoke-RestMethod -Method Get -Uri $haadminBearerTokenUri -Headers $accessTokenHeader Invoke-RestMethod -uri "https://$($haapp.name).azurewebsites.net/admin/host/keys/$($key.name)" -Headers @{Authorization=("Bearer {0}" -f $habearer)} -Method "PUT" -Body $topost -ContentType "application/json" | Out-Null } } #Loop through prod and HA functions only update new or changed keys from prod $funcs = Get-AzureRmResource -ResourceGroupName $app.ResourceGroup -ResourceType Microsoft.Web/sites/functions -ResourceName "$($app.Name)" -ApiVersion 2018-02-01 foreach ($func in $funcs) { $name = $func.name -replace "(.*)\/", "" Write-Output $name $bearer = Invoke-RestMethod -Method Get -Uri $adminBearerTokenUri -Headers $accessTokenHeader $funckeys = Invoke-RestMethod -uri "https://$($app.name).azurewebsites.net/admin/functions/$($name)/keys" -Headers @{Authorization=("Bearer {0}" -f $bearer)} | Out-Null $keys = $funckeys.keys foreach ($key in $keys) { $keys.where{$_.name -eq $key.name}[0].name = "HA-" + $key.name } $habearer = Invoke-RestMethod -Method Get -Uri $haadminBearerTokenUri -Headers $accessTokenHeader $hafunckeys = Invoke-RestMethod -uri "https://$($haapp.name).azurewebsites.net/admin/functions/$($name)/keys" -Headers @{Authorization=("Bearer {0}" -f $habearer)} | Out-Null $hakeys = $hafunckeys.keys $keystoremove = @() $keys.where{$parent = $_; $_.name -in $hakeys.name -and $_.value -eq $hakeys.where{$_.name -eq $parent.name}.value } | ForEach-Object { $keystoremove += $_.Name} $newkeys = $keys.where{$_.name -notin $keystoremove} Write-Output "New function keys count: $($newkeys.count)" if ($newkeys.count -gt 0) { foreach ($key in $newkeys) { $topost = @" { "name":"$($key.name)", "value":"$($key.value)" } "@ $habearer = Invoke-RestMethod -Method Get -Uri $haadminBearerTokenUri -Headers $accessTokenHeader Invoke-RestMethod -uri "https://$($haapp.name).azurewebsites.net/admin/functions/$($name)/keys/$($key.name)" -Headers @{Authorization=("Bearer {0}" -f $habearer)} -Method "PUT" -Body $topost -ContentType "application/json" | Out-Null } } } if ($app.name -in $namestofailover) { Write-Output "Stopping" Invoke-AzureRmResourceAction -ResourceGroupName $haapp.ResourceGroup -ResourceType Microsoft.Web/sites -ResourceName "$($haapp.Name)" -Action stop -ApiVersion 2018-02-01 -Force | Out-Null Write-Output "Killing processes in case app isnt already dead" Invoke-RestMethod "https://$($haapp.name).azurewebsites.net" | out-null } }