Category Archives: ARM

Conditional nested ARM template to add WVD application group to Workspace

In Windows Virtual Desktop (ARM version), applications are part of application groups, which in turn get nested under Workspaces.

In an ‘Infra As Code’ world these should be deployed through ARM templates (or Az Cli/Ps scripts). I had a long wrestle with ARM today getting applications assigned to workspaces ONLY if they weren’t already assigned.

Azure throws a friendly 400 error if you try to add an app that already exists, and interestingly, the ARM ‘contains’ function fails to properly evaluate WVD Workspace members when in a nested template.

So, I had to resort to some trickery by converting it to a string. For anyone else wanting to incrementally attach application groups to workspaces, feel free to copy/clone my template 🙂

Git source

{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "workspaceName": {
            "type": "string",
            "metadata": {
                "description": "The name of the Workspace."
            },
            "defaultValue": "NLD-WVD-WS01"
        },
        "workspaceResourceGroup": {
            "type": "string",
            "metadata": {
                "description": "The workspace resource group Name."
            },
            "defaultValue": "WE-WVD-RG"
        },
        "appGroupName": {
            "type": "string",
            "metadata": {
                "description": "The name of the Application Group to be linked."
            },
            "defaultValue": "testag2"
        }
    },
    "variables": {
        "appGroupResourceId": "[resourceId('Microsoft.DesktopVirtualization/applicationgroups/', parameters('appGroupName'))]"
    },
    "resources": [
        {
            "apiVersion": "2018-05-01",
            "name": "AddAppGroupToWorkspaceIncrementally",
            "type": "Microsoft.Resources/deployments",
            "resourceGroup": "[parameters('workspaceResourceGroup')]",
            "properties": {
                "mode": "Incremental",
                "template": {
                    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "resources": [
                        {
                            "name": "[parameters('workspaceName')]",
                            "apiVersion": "2019-12-10-preview",
                            "condition": "[not(greater(indexOf(string(reference(concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',parameters('workspaceResourceGroup'),'/providers/Microsoft.DesktopVirtualization/workspaces/',parameters('workspaceName')),'2019-12-10-preview','Full').properties.applicationGroupReferences),variables('appGroupResourceId')),0))]",
                            "type": "Microsoft.DesktopVirtualization/workspaces",
                            "location": "eastus",
                            "properties": {
                                "applicationGroupReferences": "[union(reference(concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',parameters('workspaceResourceGroup'),'/providers/Microsoft.DesktopVirtualization/workspaces/',parameters('workspaceName')),'2019-12-10-preview','Full').properties.applicationGroupReferences,array(variables('appGroupResourceId')))]"
                            }
                        }
                    ]
                }
            }
        }        
    ]
}

Azure static website with CDN, getting the regional code for an ARM template

When deploying a Static Website to Azure storage with CDN, the CDN endpoint requires the static website hostname. MS docs don’t show how to retrieve this data (other than clicking in the portal). Playing around with Fiddler, I noticed a call to management.azure.com when enabling a static site manually and tried to reproduce this with the Reference function in ARM, which returned the full static website endpoint url including the zone identifier:

"[reference(concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName')), '2019-06-01', 'Full').properties.primaryEndpoints.web]"

Sadly, ‘Reference’ is not available for use in other functions, such as Concat, so you’ll have to pass this as output from the storage template to your CDN template instead of combining both into a single template.

This brings us one step closer to a full ARM deployment of a static website, only actually enabling the static website feature on the storage account still requires using PS or Az Cli. But we’re in luck, running PowerShell in DevOps is easy 🙂

Here’s two ARM templates to showcase the Storage Account + CDN:

CDN Template

Storage Account

Then this is what the Pipeline more or less looks like:

the processStorageAccountOutput.ps1 contains:

Param(
  [parameter(Mandatory=$true)]
  $storageAccountOutput
)

Write-Host "##vso[task.setvariable variable=storageAccountWebEndpointURI;]$($(ConvertFrom-Json $storageAccountOutput).WebEndpointURI.value)"
Write-Host "##vso[task.setvariable variable=storageAccountName;]$($(ConvertFrom-Json $storageAccountOutput).storageAccountName.value.Replace('https://','').Split('.')[0])"

And the Azure Cli step in the DevOps pipeline is configured like this:

enabling azure static website through azure cli in azure devops pipeline