Home / Writing / Automation

Modular AVD Personal Host Pools with Bicep

2026.10.30 · Automation
Modular AVD Personal Host Pools with Bicep

Deploying a Personal desktop environment in Azure Virtual Desktop involves more than creating session hosts. The host pool, desktop application group, workspace, user assignments and scaling plan all need to work together.

I expanded the Bicep modules in endpoint-toolkit to deploy that stack for Entra ID–joined Personal desktops. The modules connect to existing networking and can use an existing Azure Compute Gallery image, which makes them useful in environments where a platform team already manages the surrounding infrastructure.

What the modules deploy

main-personal-hostpool.bicep is the resource-group-scoped entry point. It brings together:

  • The AVD management plane: a Personal host pool with Automatic or Direct assignment, a desktop application group, an optional workspace and user/group assignments.
  • Personal scaling: schedules for starting assigned hosts and handling disconnected or logged-off desktops, with configurable timeouts and time zone.
  • Session hosts: Entra ID–joined VMs using a Marketplace image or an Azure Compute Gallery image version, with options for Intune, Trusted Launch, VM login roles and monitoring.
  • Power-management permissions: optional role assignments for Autoscale and Start VM on Connect, including subscription scope where required.

The main components remain separate modules:

avd/bicep/
├── main-personal-hostpool.bicep
├── modules/
│   ├── hostPool-entraid.bicep
│   ├── scalingPlan-personal.bicep
│   ├── sessionHost-entraid.bicep
│   ├── powerOnOffRbac-subscription.bicep
│   └── powerOnOffRbac.bicep
└── parameters/
    └── personal-hostpool-dewc.bicepparam

Microsoft's AVD Landing Zone Accelerator provides a broader reference implementation, including resource groups, networking, DNS, storage and Key Vaults. This module set focuses on the AVD resources and session hosts that fit into an existing environment. It adopts useful LZA patterns such as scheduled agent maintenance, Entra ID RDP settings, diagnostics and optional monitoring extensions.

The existing main-entraid.bicep and main-legacy.bicep entry points remain available for deploying session-host batches into an existing host pool. The Azure Image Builder module can be used separately to prepare the image.

Deploy a Personal host pool

Start with personal-hostpool-dewc.bicepparam. The example targets germanywestcentral and uses W. Europe Standard Time for the VMs, scaling plan and agent maintenance windows. Adjust those values for your deployment.

Before running the deployment, set:

  • Resource names and groups: choose the host pool, application group and workspace names, and an existing management resource group. Session hosts can use the same group or a separate existing compute resource group.
  • Networking and image: provide the existing subnet resource ID, select VM size and security options, and optionally supply a Gallery image version ID. The example otherwise uses a Windows 11 single-session Marketplace image.
  • User access: populate the Entra ID user/group object IDs for desktop assignments and any VM login role assignments. Select the matching principal types.
  • Power-management access: if the required role is not already assigned, provide avdServicePrincipalObjectId for the Azure Virtual Desktop enterprise application. The deployment identity needs permission to create role assignments at the selected scope.

From the repository root, deploy the stack with Azure CLI:

az deployment group create \
  --resource-group rg-avd-personal-dewc-001 \
  --template-file avd/bicep/main-personal-hostpool.bicep \
  --parameters avd/bicep/parameters/personal-hostpool-dewc.bicepparam \
  --parameters localAdminPassword='<secret>'

The password is a placeholder; use your pipeline's secret handling when automating the deployment. Set deploySessionHosts = false when you want to deploy the management plane and scaling configuration without creating new VMs.

Session-host names with 12-character prefixes

The Personal orchestrator and main-entraid.bicep accept either an explicit vmList or a prefix and sequence. The default three-digit padding leaves room for a 12-character prefix within Windows' 15-character computer-name limit.

For example, these illustrative parameters produce DEMOAVD1DEWC001 and DEMOAVD1DEWC002:

param vmPrefix = 'DEMOAVD1DEWC'
param vmCount = 2
param vmStartIndex = 1
param vmIndexPadLength = 3

The complete name must still fit within 15 characters. A four-digit suffix, or a sequence that rolls past 999, exceeds that limit when paired with a full 12-character prefix. The orchestrators validate the resulting names, including names supplied through vmList.

Deployment considerations

Personal scaling schedules. The scaling module uses Personal schedule child resources. Its generated defaults follow the host pool's startVMOnConnect setting; custom schedules must specify consistent phase settings themselves. Review disconnect/logoff actions and timeouts for your users.

If you select Hibernate, the orchestrator enables hibernation on the VMs it creates. You still need a compatible VM SKU and OS image; it does not retrofit existing hosts when deploySessionHosts = false. Microsoft's Autoscale prerequisites also list FSLogix and App Attach as unsupported with Personal Autoscale hibernation.

Autoscale permissions. Azure Virtual Desktop needs the Desktop Virtualization Power On Off Contributor role at subscription scope for Autoscale. The optional RBAC module defaults to that scope. A resource-group-scoped option is available for standalone Start VM on Connect and covers both management and compute groups when they are separate.

Session-host registration. The full orchestrator creates or refreshes the host pool's registration token. The session-host module passes that token through the DSC extension's protectedSettings and pins a versioned Configuration_1.0.03299.1133.zip package that supports Entra ID join. Keep the package version deliberate when overriding avdAgentPackageUrl. When using a session-host module independently, supply a valid token or ensure a valid token already exists on the pool and the deploying identity can read it.

Entra ID access. The host-pool module can enforce the RDP properties used for Entra authentication. Configure the tenant and client requirements described in Microsoft's AVD single sign-on guidance as well; a template property alone does not complete that setup.

Keep Personal desktop lifecycle separate from pooled replacements

The repository's blue/green update pipelines deploy replacement hosts and drain old ones for pooled environments. They do not migrate Personal desktop user assignments, per-VM login permissions, hibernation settings or local user state. Plan those separately before adapting a replacement workflow for Personal desktops.

Also serialize planning and deployment for each host pool. The pre-flight helper blocks matching active deploy-*, canary-* and blast-* deployments by default when -ComputeResourceGroupName is supplied; -AllowConcurrentDeployments bypasses that active-deployment check. It does not provide a lock across the rollout, so two simultaneous runs can still plan the same names before either starts deploying.

The module documentation and parameter files cover the remaining configuration options. Start by adapting the example to your existing network, image and access model, then pilot the resulting Personal desktop environment before expanding it.