#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
    }
}