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')))]"
                            }
                        }
                    ]
                }
            }
        }        
    ]
}

Grouping devices in MDATP based on registered users

Microsoft Defender Advanced Threat Protection seems to be becoming the defacto leader in the A/V industry, at least when Windows is concerned, but other OS’es seem to be following quickly 🙂

At one of my international customers, many different locations and departments exist and we’d like to group devices in MDATP based on their primary user so we can assigned different administrators automatically, and apply different web filtering policies.

MDATP has the following options available for grouping:

These membership rules don’t say anything about the user, and the machine domains are all cloud native (no hybrid joins). So we need to use Tags to gain flexible targeting in MDATP.

The following PowerShell script can be scheduled as an Azure Runbook to automatically tag all your MDATP devices based on the ‘Company’ attribute of the device’s primary user. It could also be modified easily to e.g. parse a user’s group membership or UPN’s domain.

https://gitlab.com/Lieben/assortedFunctions/-/blob/master/set-MDATPCustomTags.ps1

If you have a lot of devices, it may take a while for the first run (beyond Azure Automation limits), in that case run it locally first and then schedule it.

Sensitive group protection

It is best practise in IT to secure access to resources with Groups.

Membership of a security group means access to whatever resources are secured by that group. Sometimes these groups are self-managed by an owner, sometimes centrally.

In all cases, fairly low privileged users, that are not global admins, can add users to these groups including themselves. Imagine that you have a group called ‘Global Admins’, and your helpdesk user assigns himself to that group. You’d like to know right?

With Privileged Access Groups in Azure AD (Preview) you can protect groups like these actively, but, this requires a P2 license and still lacks some customization features.

An alternative method is to use a simple alerting rule in MCAS (Microsoft Cloud App Security), where you set an alert when ‘someone’ joins a specific group, or if you want to do more than alerting you could also run an automation playbook.

Here’s how to protect a specific Azure AD or Office 365 group with MCAS:

  1. look up its GUID in AzureAD
  2. Create an Activity Policy in the MCAS console
  3. Specify the group GUID as ‘Activity object ID’ in the policy and the correct action type: