AVD DrainMode dependent on Compliance

An AVD deployment is often joined to Intune. This results in a compliance state in Intune used in Conditional Access for access to Microsoft 365 applications. We don’t want users logging onto AVD machines that aren’t compliant hence the DrainMode dependent on Compliance.

Also, AVD deployments are often Hybrid Entra Joined. That comes with the Hybrid Join shenanigans and after that the compliance shenanigans. The Intune device is replaced instead of joined. As a result, it takes a long time to get compliant. So, we only want AVD machines that are compliant to be available for users.

So, how do we achieve this? I use Powershell to first set the drain mode to enabled. After that, we check the compliance in Intune via Graph API and if the machine is compliant we disable drain mode and allow users to log on. Lastly, we use Azure DevOps to run this task right after deploying the AVD sessionhosts.

It looks like this:


You must have Azure DevOps set up for AVD. You can read all about it in previous posts:

Setup Azure DevOps

Setup A DevOps Packer Image Pipeline

The Service Principal needs permissions in Graph API. For example:

AVD DrainMode dependent on Compliance Script

This is the script:

Link to Github

I use the script in an Azure DevOps Pipeline. That was fairly obvious in the first screenshot but it felt worth mentioning.

When running the script you need to provide some parameters:

The “$devicenames” parameter is a special one because of the input format. For now, when providing multiple devices for the script, use this format: “avd-dev-1,avd-dev-2”.

This parameter is split further in the script:

I use this format because this script to populates the $devicenames from my JSON parameter file that builds my development environment.

#Gather variables from the parameters file
$Variables = Get-Content -Path "/Users/nko/VSCodeWorkspaces/NKO/NielsKokTechTest/Packer/NewSessionHosts/Dev_SessionHosts_parameters.json" | ConvertFrom-Json

$InitialNumber = $Variables.parameters.vmInitialNumber.value
$Sessionhostinstances = $Variables.parameters.sessionhostinstances.value
$Sessionhostprefix = $Variables.parameters.sessionhostprefix.value
$endnumber = $InitialNumber + $Sessionhostinstances - 1

$Devices = @()

$InitialNumber..$endnumber | ForEach-Object {
    $Devices += "$Sessionhostprefix$_"
$DeviceNames = $Devices -join ","

This script populates my sessionhostprefix, sessionhostinstances and the vminitialnumber to build the devicenames parameters with the correct information.

If you want to know how to use bicep to deploy sessionhosts, check this blog:

If you just want to pass the parameter with the correct info just use the format I provided earlier.

Furthermore, the script uses a very cool feature within PowerShell 7 called parallelization. The scripts runs in parallel so it checks the compliance state for 10 machines at the same time:

Change this if you like.

Running the Script

When the script runs, it first puts the AVD machines in DrainMode:

After that, it’s checking the compliance state of the AVD machine in Intune. When the machine is compliant DrainMode is disabled and new sessions are allowed. It checks for the compliance state every 15 seconds. Change this if you like.

And thats how you can set DrainMode on AVD dependent on the Intune Compliance state! How awesome is that!

Leave a Comment