7

Adding Azure App Service Application Settings with PowerShell

Azure App Services

Within Azure there is a option to change several configuration settings. When working with  Deployment Slots this means you have to click a lot within the Azure Portal and that can be a very time consuming operation.

The configuration of the Azure App Service can be automated by using PowerShell, for this first example we will start configuring Application settings.

To maintain the application settings values we start off by making a configuration file in which the key value pairs can be saved.

<?xml version="1.0" encoding="utf-8"?>
<Azure SubscriptionName="Pay-As-You-Go">
  <AppService Name="api-app" ResourceGroup="Demo-Group">
      <AppSettings>
        <AppSetting Key="Test" Value="Test"></AppSetting>
      </AppSettings>    
  </AppService>
  <AppService Name="api-app" ResourceGroup="Demo-Group" Slot="acc">
    <AppSettings>
      <AppSetting Key="Test" Value="Test"></AppSetting>
    </AppSettings>
  </AppService>
</Azure>

If you look at the configuration file you will notice that there is one API application within Azure. This API Application also has a deployment slot called “acc”.

With the use of PowerShell we can read out this configuration file and add the application settings to the right deployment slot.

$fileName = "configuration.xml";

Write-Host "Loading configuration file for Azure:" $fileName; 
$config = [xml] (Get-Content $fileName)

if ($config -eq $null) {
    Write-Host "Error loading configuration file, make sure the file exists." -ForegroundColor Red
    Exit
}
$subscription = $config.Azure.SubscriptionName

Write-Host "Login to the Azure Environment:" -ForegroundColor Green

#login to Azure
Login-AzureRmAccount

Write-Host "Setting the correct Subscription:" -ForegroundColor Green

#get the Azure Subscription
Get-AzureRmSubscription –SubscriptionName $subscription | Select-AzureRmSubscription

foreach($webApp in $config.Azure.AppService){
    
    $appService = '';
    $group = $webApp.ResourceGroup;
    $name = $webApp.Name;
    $slot = $webApp.Slot;

    if(!$slot){
        Write-Host "Applying settings for app service : " $name " in group: " $group -ForegroundColor Green
       $appService = Get-AzureRmWebApp -Name $name -ResourceGroupName $group;
    }else{
      Write-Host "Applying settings for app service : " $name " in group: " $group "in slot: " $slot -ForegroundColor Green
      $appService = Get-AzureRmWebAppSlot -Name $name -Slot $slot -ResourceGroupName $group;
    }

    $appSettings = $appService.SiteConfig.AppSettings

    #setup the current app settings
    $settings = @{}
    ForEach ($setting in $appSettings) {
        $settings[$setting.Name] = $setting.Value
    }

    #adding new settings to the app settigns
    foreach($appSetting in $webApp.AppSettings.AppSetting){
        $settings[$appSetting.Key] = $appSetting.Value;
    }

    if(!$slot){
        $app = Set-AzureRMWebApp -Name $name -ResourceGroupName $group -AppSettings $settings
    }else{
        $app = Set-AzureRMWebAppSlot -Name $name -ResourceGroupName $group -AppSettings $settings -Slot $slot
    }

    Write-Host "Application settings applied to: " $appService.Name -ForegroundColor Green
}

In the code snip-it above there are a lot of comments so I hope you understand what happens within the script. The main difference for updating the production environment in the slot is described in the following paragraph.

By using “Set-AzureRMWebApp” you can set the the properties of the production version. By using “Set-AzureRMWebAppSlot” and specifying the “Slot” parameter you update the settings of the specified slot.

Know I hear you think: What about the specific slot settings as within the picture below.

image

Until know I haven’t found a solution other then doing this in the Azure Portal or by using Azure Classic scripts.

In order to run the upcoming PowerShell a Azure subscription needs to be configured (https://www.opsgility.com/blog/windows-azure-powershell-reference-guide/getting-started-with-windows-azure-powershell/).

With the use of “Select-AzureSubscription” the default Azure subscription will be set. The subscription that will be used is configured in the configuration file.

After that the “Set-AzureWebsite” will be used to set the property “SlotStickyAppSettingNames”. This property needs to be set to a string array that contains all the key’s that need to be sticky slot settings.

Set-AzureWebsite -Name "api-app" -SlotStickyAppSettingNames @("Test") 

To support this within the configuration file we alter the app settings. Besides that you must make sure that you set this property on the default (production) slot of your app service. Otherwise you will get the following exception.

Set-AzureWebsite : <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"Code":"BadRequest","Message":"The names 
of the app settings and connection strings can be only set on a parent site level because they apply to all site's slots.","Exten
dedCode":"04084","MessageTemplate":"The names of the app settings and connection strings can be only set on a parent site level b
ecause they apply to all site's slots.","Parameters":[],"InnerErrors":null}</string>
At line:2 char:1
+ Set-AzureWebsite -Name "api-app" -SlotStickyAppSettingNames @("Test") -Slot "acc"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [Set-AzureWebsite], CloudException
    + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Websites.SetAzureWebsiteCommand

With the extension the configuration file know looks liked the below code snip-it.

<?xml version="1.0" encoding="utf-8"?>
<Azure SubscriptionName="Pay-As-You-Go">
  <AppService Name="api-app" ResourceGroup="Demo-Group">
      <AppSettings>
        <AppSetting Key="Test" Value="Test" Slot="true"></AppSetting>
      </AppSettings>    
  </AppService>
  <AppService Name="api-app" ResourceGroup="Demo-Group" Slot="acc">
    <AppSettings>
      <AppSetting Key="Test" Value="Test"></AppSetting>
    </AppSettings>
  </AppService>
</Azure>

With the configuration file altered the classic PowerShell code and the “Set-AzureWebsite” can be added to the PowerShell script that results in the following file.

$fileName = "configuration.xml";

Write-Host "Loading configuration file for Azure:" $fileName; 
$config = [xml] (Get-Content $fileName)

if ($config -eq $null) {
    Write-Host "Error loading configuration file, make sure the file exists." -ForegroundColor Red
    Exit
}
$subscription = $config.Azure.SubscriptionName

Write-Host "Login to the Azure Environment:" -ForegroundColor Green

#login to Azure
Login-AzureRmAccount

Write-Host "Setting the correct Subscription:" -ForegroundColor Green

#get the Azure Subscription
Get-AzureRmSubscription –SubscriptionName $subscription | Select-AzureRmSubscription
Select-AzureSubscription -SubscriptionName $subscription

foreach($webApp in $config.Azure.AppService){
    
    $appService = '';
    $group = $webApp.ResourceGroup;
    $name = $webApp.Name;
    $slot = $webApp.Slot;

    if(!$slot){
        Write-Host "Applying settings for app service : " $name " in group: " $group -ForegroundColor Green
       $appService = Get-AzureRmWebApp -Name $name -ResourceGroupName $group;
       
       if(!$slot){
            if($appSetting.Slot -eq 'true' -or $appSetting.Slot -eq '1'){
                $stickyslot += $appSetting.Key;
            }
        }
       
    }else{
      Write-Host "Applying settings for app service : " $name " in group: " $group "in slot: " $slot -ForegroundColor Green
      $appService = Get-AzureRmWebAppSlot -Name $name -Slot $slot -ResourceGroupName $group;
    }

    $appSettings = $appService.SiteConfig.AppSettings

    #setup the current app settings
    $settings = @{}
    ForEach ($setting in $appSettings) {
        $settings[$setting.Name] = $setting.Value
    }

    #adding new settings to the app settigns
    foreach($appSetting in $webApp.AppSettings.AppSetting){
        $settings[$appSetting.Key] = $appSetting.Value;
    }

    if(!$slot){
        $app = Set-AzureRMWebApp -Name $name -ResourceGroupName $group -AppSettings $settings
        
        if($stickyslot.Count -lt 0){
            Write-Host "Set Sticky Slot Settings" -ForegroundColor Yellow
            Set-AzureWebsite -Name $name -SlotStickyAppSettingNames $stickyslot
        }
    }else{
        $app = Set-AzureRMWebAppSlot -Name $name -ResourceGroupName $group -AppSettings $settings -Slot $slot
    }

    Write-Host "Application settings applied to: " $appService.Name -ForegroundColor Green
}

It may occur that setting the parameter “SlotStickyAppSettingNames” results in the following error: “Requested value ‘VS2015’ was not found”

This can be fixed by taking the following steps:

  1. Switch on remote debugging.
  2. Select VS2013 instead of VS2015
  3. Save
  4. Switch Off remote debugging
  5. Save

I hope that the Resource Manager PowerShell will get an extension for setting the sticky slot settings. For know I will keep using the Azure Classic PowerShell. If there is another option that I totally missed  please inform me I would really appreciate it.

Complete source can be downloaded here.

Update: As Karl mentioned in the comments setting the sticky slot settings can be done with Azure Resource Management PowerShell. For this you need to use “Set-AzureRmResource”.

//Get the current values
$resourceName = $webappname + "/slotconfigname"
$stickySlot = Get-AzureRmResource -ResourceName $resourceName -ResourceGroupName -ResourceType "Microsoft.Web/Sites/config" -ApiVersion "2015-08-01"

//Check the AppSettings
$stickySlot.Properties.AppSettingNames

//If the existing items are empty, you need to create a new array with settings
$settings = @("AppSetting1", "AppSetting2")
$stickySlot.Properties.AppSettingNames = $settings

$stickySlot.Properties.AppSettingNames += "AppSetting1"
$stickySlot.Properties.AppSettingNames += "AppSetting2"

//setting the sticky settings
Set-AzureRmResource -ResourceName $resourceName -ResourceGroupName -ResourceType "Microsoft.Web/Sites/config" -Properties $stickySlot.Properties -ApiVersion "2015-08-01"

Related Posts

Azure DevOps Automation A couple of weeks ago the rename / rebranding of Visual Studio Team Services to Azure DevOps was announced. The rebranding is a great step forward int...
Function parameters while debugging PowerShell in Visual Studio Code Visual Studio Code is becoming one of the tools that you need to use when developing PowerShell scripts. It allows you to debug your scripts. But how ...
AKS (Kubernetes) and no connection could be made because the target machine acti... A client of my had an error while connecting to different resources within their Kubernetes cluster in Azure (AKS). Kubectl error On the kubectl com...
Kubernetes (AKS) attached to Azure Storage (Files) Kubernetes (AKS) can be used for many situations. For a client we needed to make files available trough a Kubernetes Pod. The files needed to be share...
Resource Group deployment via ARM templates When deploying an Azure Resource Manager (ARM) template you have to create a resource group within Azure. To deploy a template via script your script ...
Azure Managed Service Identity and Local Development Instead of storing user credentials of an external system in a configuration file, you should store them in the Azure Key Vault. Before MSI (Managed S...

7 Comments

  1. Actually I discovered today that you can set sticky settings through ARM PowerShell. You need to use Set-AzureRmResource.
    I will show an example:

    $resourceName = $webappname + “/slotconfigname”
    $stickySlot = Get-AzureRmResource -ResourceName $resourceName -ResourceGroupName -ResourceType “Microsoft.Web/Sites/config” -ApiVersion “2015-08-01”

    You can then check the existing ones by:
    $stickySlot.Properties.AppSettingNames

    Here you need to different approaches. If these are empty from the get go, you need to create a new array with settings:
    $settings = @(“AppSetting1, “AppSetting2”)
    $stickySlot.Properties.AppSettingNames = $settings

    If there already are other values, and you want to keep them:
    $stickySlot.Properties.AppSettingNames += “AppSetting1”
    $stickySlot.Properties.AppSettingNames += “AppSetting2”

    Then after that is done:
    Set-AzureRmResource -ResourceName $resourceName -ResourceGroupName -ResourceType “Microsoft.Web/Sites/config” -Properties $stickySlot.Properties -ApiVersion “2015-08-01

    By using the Get first, you make sure any existing properties and settings will remain in place.

  2. Nice article and very usefull. I had to make $config of type xml to get it to work:

    [xml]$config = (Get-Content $fileName)

  3. But how do you give those appsettings a value, and how do you deal with connection strings? This stuff is really starting to annoy me, every time i go back to my script the thing has stopped working as MS have completely broken the API … every single time! Argh!

    • Hi Dan,

      The values are saved within my own configuration file. But since I wrote this post the API’s have changed a lot and the settings and configuration string are also made possible within a Azure Resource Manager template. They also keep supporting those all the time so I would suggest to look into that.

      If you need further assistance with PowerShell just let me know.

        • Hi Dan,

          The powershell function Set-AzureRMWebApp and Set-AzureRMWebAppSlot both have a “ConnectionStrings” parameter in which you have to pass a Hashtable with your information.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.