🚀 Executive Summary
TL;DR: Terraform provisioning of AVD multi-session hosts often fails to automatically enroll them into Intune due to the lack of a user-driven MDM enrollment trigger during service principal deployment. The article details robust solutions, primarily leveraging Group Policy for Hybrid Azure AD Join or adopting full Azure AD Join for a streamlined, cloud-native enrollment process.
🎯 Key Takeaways
- AVD multi-session hosts provisioned by Terraform don’t automatically enroll in Intune because the enrollment process is typically user-driven, which is absent during service principal provisioning.
- The most robust and common solution for Hybrid Azure AD Join environments is to use a Group Policy Object (GPO) to enable “automatic MDM enrollment using default Azure AD credentials” (Device Credential) for the AVD hosts’ Organizational Unit (OU).
- For new or cloud-native environments, transitioning to a full Azure AD Join for AVD hosts simplifies Intune enrollment significantly, as it integrates directly with the VM provisioning process, eliminating the need for separate domain join extensions.
Struggling with Terraform to enroll AVD multi-session hosts into Intune? I break down the core problem and offer three real-world solutions, from the “get it working now” hack to the architecturally sound fix.
AVD, Intune, and Terraform: A Survivor’s Guide to Multi-Session Enrollment
I remember it vividly. It was a Tuesday, of course. We were deploying a new AVD host pool for the finance department—20 hosts, multi-session, the works. The Terraform plan looked perfect, `terraform apply` finished with a sea of green, and I went to grab a coffee. Fifteen minutes later, my Teams was on fire. “None of our compliance policies are applying.” “Where are the apps that Intune is supposed to deploy?” It took us an hour to realize not a single one of our brand new, perfectly provisioned session hosts had actually enrolled in Intune. Terraform built the house, but it forgot to give anyone the keys. That day, I learned the painful difference between a VM being “created” and a VM being “ready.”
So, Why Does This Break in the First Place?
This isn’t a bug; it’s a clash of design philosophies. Intune, at its core, was built for single-user devices—your laptop, your phone. The enrollment process is often tied to a specific user logging in and kicking off the registration. AVD multi-session hosts, however, are cattle, not pets. They’re shared servers provisioned by a non-human service principal via Terraform. There is no “user” present during provisioning to trigger that MDM enrollment handshake.
When Terraform’s Azure provider creates the VM and joins it to the domain (Hybrid Join), it does its job and stops. It doesn’t know, nor does it care, about the Intune-specific enrollment steps that need to happen inside the OS afterward. The VM exists, it’s on the network, but as far as Intune is concerned, it’s a ghost.
The Fixes: From Duct Tape to a New Foundation
After wrestling with this problem on several projects, my team has settled on a few patterns. Which one you choose depends on your environment, your timeline, and your tolerance for “hacky” solutions.
Solution 1: The “Get It Working by 5 PM” Fix (DEM Account & Scheduled Task)
This is the quick and dirty approach. It’s not pretty, but it gets the job done when management is breathing down your neck. The idea is to enroll the devices using a Device Enrollment Manager (DEM) account, which is designed for enrolling large numbers of corporate devices.
How it works:
- You create a DEM account in Azure AD. This account has permissions to enroll up to 1,000 devices.
- In your Terraform configuration, you use a `custom_data` block or a Virtual Machine Extension to run a PowerShell script on the session host after it’s built.
- This script uses the DEM account credentials (safely stored in Key Vault, please!) to install the Intune Company Portal or trigger the enrollment process directly. A common way is to create a scheduled task that runs `deviceenroller.exe /c /AutoEnrollMDM`.
# Example PowerShell snippet for your VM Extension
$username = "dem-account@yourdomain.com"
$password = ConvertTo-SecureString "YourSuperSecretPassword" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username, $password)
# This is a simplified example. In reality, you'd pull this from Key Vault.
# The following command creates a scheduled task to run the enrollment process
$action = New-ScheduledTaskAction -Execute 'C:\Windows\system32\deviceenroller.exe' -Argument '/c /AutoEnrollMDM'
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "IntuneAutoEnroll" -User "NT AUTHORITY\System" -RunLevel Highest
Warning: This is brittle. Storing credentials, even temporarily, is a security risk. If the scheduled task fails, the machine never enrolls, and you’re back to square one. Use this to get out of a jam, but plan to replace it.
Solution 2: The “Permanent” Fix (Hybrid Join & Group Policy)
This is the most common and robust solution for environments that require Hybrid Azure AD Join. Instead of trying to force the enrollment from within the VM, we let the existing domain infrastructure do the heavy lifting.
How it works:
The magic here is in a simple Group Policy Object (GPO). You’ve already configured Azure AD Connect to sync the devices, but you need to tell them to actually enroll in Intune.
- Verify Azure AD Connect: Make sure Hybrid Azure AD Join is configured and the OU where your AVD hosts are being created is in sync.
- Create a GPO: Create a new GPO and link it to the AVD session hosts’ OU.
- Enable the Policy: Navigate to
Computer Configuration > Policies > Administrative Templates > Windows Components > MDM. - Enable the setting “Enable automatic MDM enrollment using default Azure AD credentials“. Set the credential type to use to “Device Credential“.
Now, when Terraform creates a VM and your domain join extension adds it to the correct OU, the machine will automatically pick up this GPO on its next policy refresh. It will then use its own machine identity to complete the Intune enrollment. No scripts, no stored credentials, no fuss.
Pro Tip: This method is elegant because your Terraform code doesn’t need to change much. It just needs to ensure the VM lands in the right Active Directory OU. The rest is standard domain management, which is exactly where this logic belongs.
# In your azurerm_windows_virtual_machine resource
resource "azurerm_windows_virtual_machine" "avd_host" {
# ... other settings
# This extension is the key part for Hybrid Join
resource "azurerm_virtual_machine_extension" "domain_join" {
name = "joindomain"
virtual_machine_id = azurerm_windows_virtual_machine.avd_host.id
publisher = "Microsoft.Compute"
type = "JsonADDomainExtension"
type_handler_version = "1.3"
settings = jsonencode({
"Name" = "yourdomain.com",
"OUPath" = "OU=AVD,OU=Workstations,DC=yourdomain,DC=com", # The OU with your GPO linked!
"User" = "yourdomain\\joinaccount",
"Restart" = "true",
"Options" = "3"
})
protected_settings = jsonencode({
"Password" = data.azurerm_key_vault_secret.domain_password.value
})
}
}
Solution 3: The “Nuclear” Option (Go Full Azure AD Join)
Sometimes, the best way to fix a problem is to eliminate the complexity that causes it. Hybrid Join is powerful, but it’s also a major source of headaches. If your environment can support it, moving to a full Azure AD Join model for your AVD hosts simplifies everything.
How it works:
Instead of joining a local Active Directory domain, the VM joins Azure AD directly during provisioning. This process automatically triggers the Intune enrollment as part of the join itself. It’s a much cleaner, cloud-native workflow.
In Terraform, you simply skip the domain join extension and use the native AAD join functionality. You’ll need to use a Service Principal with the right permissions (`Cloud Device Administrator` or similar) to perform the join.
# In your azurerm_windows_virtual_machine resource
resource "azurerm_windows_virtual_machine" "avd_host_aad" {
name = "avd-prod-aad-01"
# ... other settings like location, size, admin_username etc.
# This is the magic part for AAD Join
identity {
type = "SystemAssigned"
}
# You might use an extension to enroll in Intune if automatic enrollment is not scoped
# Or, configure automatic enrollment for all devices in AAD/Intune settings
}
resource "azurerm_virtual_machine_extension" "aad_login" {
name = "AADLoginForWindows"
virtual_machine_id = azurerm_windows_virtual_machine.avd_host_aad.id
publisher = "Microsoft.Azure.ActiveDirectory"
type = "AADLoginForWindows"
type_handler_version = "1.0"
}
Heads Up! This is an architectural decision, not a quick fix. If you rely on legacy protocols like Kerberos or NTLM for accessing on-prem file shares (looking at you, `prod-fs-01`), you will have a bad day. AAD Join is fantastic for modern applications but requires careful planning for legacy access.
Comparison at a Glance
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| 1. DEM Account Script | Fast to implement in a crisis. | Brittle, insecure credential handling, not scalable. | Emergency fixes or very small, non-critical deployments. |
| 2. Hybrid Join + GPO | Very reliable, uses existing infrastructure, secure. | Requires AD/GPO management, adds Hybrid complexity. | Most enterprise environments with existing on-prem AD. |
| 3. Full Azure AD Join | Simplest workflow, cloud-native, highly automated. | May break access to legacy on-prem resources. | New/Greenfield environments or companies fully committed to the cloud. |
Final Thoughts
The key takeaway is this: Terraform is only responsible for provisioning the infrastructure. The configuration and state of the machine’s OS is a separate, but equally critical, step. Don’t fall into the trap of thinking a green `apply` means the job is done. For AVD and Intune, the “right” way is almost always Solution 2 for established companies. It leverages the tools you already have (GPO) to do the job reliably. But if you have the chance to build fresh, give Solution 3 a serious look. Your future self will thank you.
🤖 Frequently Asked Questions
❓ Why don’t AVD multi-session hosts automatically enroll in Intune when provisioned by Terraform?
AVD multi-session hosts provisioned by Terraform via a service principal lack a user context to trigger Intune’s typical user-driven MDM enrollment handshake, leaving them unenrolled despite being created.
❓ How do the different Intune enrollment methods for AVD multi-session hosts compare?
The DEM account script is a fast but brittle emergency fix. Hybrid Join with GPO is reliable for existing Active Directory environments. Full Azure AD Join offers the simplest, cloud-native workflow but requires careful planning for legacy on-prem resource access.
❓ What is a common implementation pitfall when trying to enroll AVD multi-session hosts into Intune using Terraform, and how can it be avoided?
A common pitfall is assuming a successful Terraform `apply` means Intune enrollment is complete. This is avoided by implementing a post-provisioning enrollment mechanism, such as a GPO for Hybrid Join or configuring full Azure AD Join, to explicitly trigger MDM registration.
Leave a Reply