Skip to main content

AVD Deployment Runbook

This runbook covers the sequence of steps to deploy a production-ready Azure Virtual Desktop secure enclave in GCC High — from an empty subscription to 20 Entra-joined, Intune-enrolled session hosts. Steps are ordered to respect Azure resource dependencies.

For architecture context, firewall rules, and cost guidance, see Scenario: Azure Virtual Desktop. For the full 65-hour phased timeline, see AVD Deployment Timeline.


AVD Runbook Prerequisites

Complete these before starting. None of the steps below can proceed without them.

ItemWhere to Configure
Azure Government subscription active, engineer has Subscription OwnerAzure Government portal — portal.azure.us
GCC High Entra tenant active, engineer has Global AdministratorEntra admin center — entra.microsoft.us
M365 GCC High E3 or E5 licenses assigned to all usersMicrosoft 365 admin center
MDM auto-enrollment enabled for All usersEntra admin center > Mobility (MDM and MAM) > Microsoft Intune > MDM user scope: All
"Users may join devices to Microsoft Entra ID" set to AllEntra admin center > Devices > Device settings
Set MDM user scope to All before provisioning session hosts

If MDM user scope is set to a named group rather than All, the AADLoginForWindows extension will join the VM to Entra but Intune enrollment will silently fail. Verify this setting before deploying any session hosts.


Tenant Device Settings

Configure these in the Entra admin center > Devices > Device settings before provisioning any session hosts. These are tenant-wide settings that apply to all Entra-joined devices.

SettingValueReason
Users may join devices to Microsoft Entra IDAllRequired for AVD provisioning — the AADLoginForWindows extension joins as SYSTEM, not as a named user. See compensating controls below.
Additional local administrators on all Microsoft Entra joined devices (Global Administrator role)DisabledGlobal Admin is a tenant-level role and must not carry local machine admin rights on session hosts. Use LAPS for local admin access instead.
Registering user is added as local administrator during Microsoft Entra joinDisabledAVD session hosts are joined by a system extension, not a user. Users must not have local admin rights on CUI session hosts — doing so would undermine AC, AU, and SI domain controls.
Enable Microsoft Entra Local Administrator Password Solution (LAPS)EnabledRotates the local admin password per device on a configurable schedule and stores it in Entra with a full access audit trail. Satisfies MA.L2-3.7.5 and IA.L2-3.5.3.
Users can see their own BitLocker recovery keyNoBitLocker recovery keys provide full disk decryption capability. In a CUI enclave, key retrieval must be an IT admin function only, with an audit trail. Supports MP.L2-3.8.x.
After enabling LAPS here, configure the rotation policy in Intune

Enabling LAPS in Entra activates the feature but does not set rotation schedule or complexity. Create a Local Administrator Password Solution policy in Intune > Endpoint security > Account protection and target it to your AVD device group. Set backup directory to Azure Active Directory, rotation to every 30 days, and complexity to the maximum available setting.

"Users may join devices" set to All — required compensating controls

Setting this to All creates a surface where any user could join a personal device to Entra. Close this gap with:

  • Intune enrollment restrictions — block personally-owned device enrollment
  • Conditional Access — require compliant device for all resource access
  • B06: Block Device Registration from Non-Approved Network Locations — prevents joins from outside trusted locations

Document this as a known constraint with compensating controls in your CMMC SSP.


Step 1: Create the Resource Group

All AVD resources should live in a dedicated resource group for cost attribution and RBAC scoping.

  1. Navigate to Azure Government portal > Resource groups > Create
  2. Set Subscription to your AVD subscription
  3. Set Resource group name — e.g., rg-avd-prod-usgovva
  4. Set Region to US Gov Virginia
  5. Add tags as required by your tagging policy (e.g., environment: production, workload: avd)
  6. Select Review + Create > Create

Step 2: Deploy the Virtual Network

AVD session hosts require a VNet with two subnets: one dedicated to Azure Firewall (required size /26) and one for session hosts.

  1. Navigate to Virtual networks > Create
  2. Set Resource group to rg-avd-prod-usgovva
  3. Set Name — e.g., vnet-avd-usgovva
  4. Set Region to US Gov Virginia
  5. Under IP addresses, the portal defaults to 10.0.0.0/16 for the VNet address space. You may use any RFC 1918 range that does not conflict with your on-premises or peered networks.
  6. The wizard creates a default subnet automatically at 10.0.0.0/24. You may rename it for clarity, but the name has no functional impact. Do not add AzureFirewallSubnet manually — enabling Azure Firewall in the next step creates it automatically at 10.0.1.0/26.
SubnetDefault CIDRPurpose
default (or your chosen name)10.0.0.0/24AVD session host NICs
AzureFirewallSubnetauto-created at 10.0.1.0/26Created automatically when Azure Firewall is enabled below
  1. Under Security, configure as follows:
OptionSettingReason
Virtual network encryptionDisabledAVD traffic is already TLS-encrypted at the application layer. No CMMC requirement is unmet without this.
Azure BastionDisabledAdmin access to session hosts uses the AVD client and Azure portal Run Command — not direct RDP. Bastion adds ~$170/month for a capability this architecture does not need.
Azure FirewallEnabledEnable here to provision the firewall inline with the VNet. Select Standard tier and create a new public IP.
Azure DDoS Network ProtectionDisabledThe enclave has one public IP (firewall egress only) and no inbound internet traffic. The default platform-level DDoS protection is sufficient. DDoS Standard (~$2,944/month) is warranted only for public-facing workloads.
  1. Select Review + Create > Create
Firewall deployment takes 5–10 minutes

The VNet and firewall provision together. Do not proceed to Step 3 until both show as succeeded. Note the firewall private IP address from the firewall's Overview blade — you will need it for the UDR in Step 3.

Once the firewall is provisioned, add the required application and network rules for AVD. See AVD Firewall Reference for the complete rule set.


Step 3: Create the User Defined Route

The UDR forces all session host outbound traffic through the Azure Firewall, enforcing the deny-all-by-default posture.

  1. Navigate to Route tables > Create
  2. Set Resource group to rg-avd-prod-usgovva
  3. Set Name — e.g., udr-avd-sessionhosts
  4. Set Region to US Gov Virginia
  5. Set Propagate gateway routes to No
  6. Select Review + Create > Create

After creation, add the default route:

  1. Open udr-avd-sessionhosts > Routes > Add
  2. Set Route name: route-all-to-firewall
  3. Set Destination: 0.0.0.0/0
  4. Set Next hop type: Virtual appliance
  5. Set Next hop address: the Azure Firewall private IP from Step 2
  6. Select Add

Associate the UDR with the session host subnet:

  1. Open udr-avd-sessionhosts > Subnets > Associate
  2. Select your VNet and the session host subnet (default unless renamed — not AzureFirewallSubnet)
  3. Select OK

Step 4: Create the Log Analytics Workspace

Required for AVD Insights, firewall logs, and Defender for Endpoint telemetry.

  1. Navigate to Log Analytics workspaces > Create
  2. Set Resource group to rg-avd-prod-usgovva
  3. Set Name — e.g., law-avd-usgovva
  4. Set Region to US Gov Virginia
  5. Select Review + Create > Create

Once created, enable diagnostic logging on the firewall:

  1. Open the firewall resource > Diagnostic settings > Add diagnostic setting
  2. Name it diag-afw-avd
  3. Check AzureFirewallApplicationRule, AzureFirewallNetworkRule, AzureFirewallDnsProxy
  4. Check Send to Log Analytics workspace and select law-avd-usgovva
  5. Set Destination table to Resource specific
  6. Leave Archive to a storage account, Stream to an event hub, and Send to partner solution unchecked
  7. Select Save
Resource specific vs. Azure Diagnostics

Resource specific stores each log category in its own table (AZFWApplicationRule, AZFWNetworkRule, AZFWDnsQuery), which is faster to query and less expensive to retain than the consolidated AzureDiagnostics table. Use Azure Diagnostics only if you are aggregating logs from multiple resource types into a single table for a SIEM or compliance requirement.


Step 5: Create the AVD Workspace

  1. Navigate to Azure Virtual Desktop > Workspaces > Create
  2. Set Resource group to rg-avd-prod-usgovva
  3. Set Workspace name — e.g., avdws-prod
  4. Set Location to US Gov Virginia
  5. Skip the Application groups tab — the application group will be created with the host pool in Step 6
  6. On the Advanced tab, select law-avd-usgovva as the Log Analytics workspace. Leave the storage account and event hub checkboxes unchecked.
  7. Select Review + Create > Create

After creation, configure the full diagnostic settings:

  1. Open avdws-prod > Diagnostic settings > Add diagnostic setting
  2. Name it diag-avdws-prod
  3. Check all four log categories: Checkpoint, Error, Management, Feed
  4. Check Send to Log Analytics workspace and select law-avd-usgovva
  5. Set Destination table to Resource specific
  6. Select Save

Step 6: Create the AVD Host Pool

  1. Navigate to Azure Virtual Desktop > Host pools > Create
  2. Basics tab:
SettingValue
Resource grouprg-avd-prod-usgovva
Host pool namehp-avd-prod
LocationUS Gov Virginia
Host pool typePersonal
Assignment typeAutomatic
Load balancing algorithmBreadth-first
Preferred app group typeDesktop
  1. Virtual machines tab: Leave empty — session hosts are added in Step 9
  2. Workspace tab: Select avdws-prod
  3. Diagnostics tab: Select law-avd-usgovva as the Log Analytics workspace. Check all eight log categories. Leave archive to storage account and stream to event hub unchecked.
  4. Select Review + Create > Create
Personal pool: one VM per user, always

With Automatic assignment, AVD permanently assigns each user to a specific VM on their first connection — no admin action required. Every subsequent connection returns that user to the same VM — their desktop, files, and application state are exactly as they left them. Users cannot land on a different VM. This is the key distinction from a pooled host pool, where users can land on any available VM and typically receive a fresh profile each session.

Assignments do not release automatically. If a user leaves or needs to free their VM for someone else, an admin must remove the assignment manually: Host pool > Session hosts > select the VM > Remove user assignment. Until cleared, the VM remains reserved for that user even if they never connect again. Direct assignment requires the same admin step to unassign, but also requires admin action to assign in the first place — making Automatic the better choice for most deployments.

Capacity must equal or exceed user count

With Automatic assignment, AVD assigns one VM per user. If all session hosts are assigned and a new user attempts to connect, AVD will find no available VM and deny the connection — there is no queue. The number of session hosts in the pool must always equal or exceed the number of users who need access. To add capacity, open the host pool > Session hosts > Add and provision additional VMs.

After creation, configure RDP properties:

  1. Open hp-avd-prod > RDP properties
  2. Set the following under Device redirection:
PropertyValueReason
Clipboard redirectionDisabledPrevent CUI from leaving the session
Drive redirectionDisabledPrevent local drive mounting
Camera redirectionDisabled
Printer redirectionDisabled (or selectively enabled)
WebAuthn redirectionEnabledAllows YubiKeys and Windows Hello to authenticate inside the session — extends phishing-resistant auth to resources accessed within AVD
USB redirectionDisabledGeneric USB redirection includes storage devices — a direct CUI exfiltration path. WebAuthn uses a separate channel and is unaffected by this setting.
Smart card redirectionEnabledAllows CAC/PIV cards to authenticate inside the session. No data exfiltration risk.
  1. Under Advanced, add the following custom RDP properties:
PropertyValueReason
enablerdsaadauth:i:1Enables SSO via Entra ID, preventing a second authentication prompt at the VM
screencaptureprotection:i:2Blocks screen capture on both client and server, preventing screenshots of CUI from inside the session
  1. This is a set of RDP properties I have found to work. watermarking:i:1;screen capture protection:i:2;drivestoredirect:s:;usbdevicestoredirect:s:;redirectclipboard:i:0;redirectprinters:i:0;audiomode:i:0;videoplaybackmode:i:1;devicestoredirect:s:;redirectcomports:i:0;redirectsmartcards:i:1;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;targetisaadjoined:i:1
  2. Select Save

Enable Start VM on Connect:

  1. Open hp-avd-prod > Properties
  2. Set Start VM on connect to Yes
  3. Select Save
Start VM on Connect requires a role assignment

The AVD service principal (Windows Virtual Desktop) must have the Desktop Virtualization Power On Off Contributor role on the subscription or resource group. Assign this before session hosts are added.

Navigate to the resource group > Access control (IAM) > Add role assignment > Desktop Virtualization Power On Off Contributor > Assign access to: User, group, or service principal > Search: "Azure Virtual Desktop".


Step 7: Assign Users to the Application Group

Azure automatically creates a Desktop Application Group named hp-avd-prod-DAG when the host pool is created and associates it with the workspace. No manual creation is needed.

Assign users:

  1. Navigate to Azure Virtual Desktop > Application groups
  2. Open hp-avd-prod-DAG > Assignments > Add
  3. Add the users or security group that should have access to AVD
  4. Select Select

Step 8: Configure Entra SSO for AVD

Entra SSO eliminates the second authentication prompt users would otherwise see when connecting to a session host. It requires enabling RDP on two AVD service principals and scoping that permission to a device group containing your session hosts.

Create the AVD device group:

  1. Navigate to Entra admin center > Groups > New group
  2. Set Group type to Security
  3. Set Membership type to Dynamic Device
  4. Set Group name — e.g., AVD Session Hosts
  5. Under Dynamic device members, add the following rule:
(device.displayName -startsWith "avd-")
  1. Select Create
Dynamic group processing takes a few minutes

The group will not contain devices immediately. Once session hosts are provisioned in Step 10, they will be added automatically within 5–15 minutes based on the naming rule. If your session hosts use a different name prefix, adjust the rule accordingly.

Run the SSO configuration script:

The following script enables RDP on the two Entra service principals that back AVD SSO and scopes the permission to your device group. It requires the Microsoft.Graph.Authentication and Microsoft.Graph.Applications PowerShell modules and must be run by a Global Administrator.

  1. Replace AVD DEVICE GROUP HERE in the script with the object ID of the AVD Session Hosts group created above
  2. Run the script:
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Applications

function Set-RdpEnabledForServicePrincipal {
param (
[Parameter(Mandatory = $true)]
[string] $ServicePrincipalId
)
$config = Get-MgServicePrincipalRemoteDesktopSecurityConfiguration -ServicePrincipalId $ServicePrincipalId
if (-not $config -or $config.IsRemoteDesktopProtocolEnabled -ne $true) {
Update-MgServicePrincipalRemoteDesktopSecurityConfiguration -ServicePrincipalId $ServicePrincipalId -BodyParameter @{ isRemoteDesktopProtocolEnabled = $true }
Write-Host "RDP enabled for service principal $ServicePrincipalId"
} else {
Write-Host "RDP already enabled for service principal $ServicePrincipalId"
}
}

Connect-MgGraph -Environment USGov -Scopes "Application.Read.All","Application-RemoteDesktopConfig.ReadWrite.All"

$MSRDspId = (Get-MgServicePrincipal -Filter "AppId eq 'a4a365df-50f1-4397-bc59-1a1564b8bb9c'").Id
$WCLspId = (Get-MgServicePrincipal -Filter "AppId eq '270efc09-cd0d-444b-a71f-39af4910ec45'").Id

Set-RdpEnabledForServicePrincipal -ServicePrincipalId $MSRDspId
Set-RdpEnabledForServicePrincipal -ServicePrincipalId $WCLspId

$tdg = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphTargetDeviceGroup
$tdg.Id = "<Object ID of AVD Session Hosts group>"
$tdg.DisplayName = "AVD Session Hosts"

New-MgServicePrincipalRemoteDesktopSecurityConfigurationTargetDeviceGroup -ServicePrincipalId $MSRDspId -BodyParameter $tdg
New-MgServicePrincipalRemoteDesktopSecurityConfigurationTargetDeviceGroup -ServicePrincipalId $WCLspId -BodyParameter $tdg
  1. Verify output confirms RDP is enabled on both service principals

Enable SSO on the host pool:

  1. Open hp-avd-prod > RDP properties > Connections
  2. Set Microsoft Entra single sign-on to Enabled
  3. Select Save

Step 10: Add Session Hosts

Session hosts are Entra-joined and Intune-enrolled automatically during provisioning — no user interaction, no MFA challenge. See Entra Join and Intune Enrollment: No User Interaction Required for details.

  1. Open hp-avd-prod > Session hosts > Add
  2. Virtual machines tab:
SettingValue
Resource grouprg-avd-prod-usgovva
Name prefixavd (Azure appends -0, -1, etc. — dashes are not allowed in the prefix)
Virtual machine typeAzure virtual machine
Availability optionsNo infrastructure redundancy required
VM sizeStandard_D8as_v6 (or D16as_v6 for power users)
Number of VMs20
Security typeTrusted Launch
Secure BootEnabled
vTPMEnabled
Integrity monitoringEnabled
OS disk typePremium SSD LRS
OS disk size128 GB (default)
Boot diagnosticsEnabled with managed storage account
  1. Image: Select Windows 11 Enterprise (single-session) from the gallery. Personal pools use single-session — one user per VM, with persistent desktop and user data.

  2. Network tab:

SettingValue
Virtual networkvnet-avd-usgovva
Subnetdefault (or your session host subnet name)
Network security groupNone
Public inbound portsNone
NSG not required with Azure Firewall

Session hosts have no public IPs and no inbound internet path. The Azure Firewall and UDR provide the network perimeter. An NSG on the session host subnet would be redundant for outbound control and adds no meaningful inbound protection in this topology.

  1. Domain to join tab:
SettingValue
Select which directory you would like to joinMicrosoft Entra ID
Enroll VM with IntuneYes
Add VM to a single groupOptional — specify a device group if targeting scoped Intune policies
  1. Virtual machine administrator account: Set a local admin username and password (stored in the VM, not synced to Entra)

  2. Select Review + Create > Add

Provisioning time

20 VMs typically take 25–45 minutes to fully provision. Monitor progress under Host pool > Session hosts. Each VM transitions through: Provisioning → Available. Intune enrollment completes within 5–15 minutes of the VM reaching Available state.


Step 11: Validate

Entra Join:

  • Entra admin center > Devices > All devices — each session host should appear as Join type: Microsoft Entra joined, MDM: Microsoft Intune

Intune Enrollment:

  • Intune admin center > Devices > All devices — each session host should appear with Enrollment type: AzureAD, Compliance: Compliant (once compliance policies have been applied and evaluated)

AVD connectivity:

  • Open the AVD client (remote.apps.powerapps.us for GCC High) and sign in as a test user
  • Verify the session launches, SSO completes without a second prompt, and clipboard/drive redirection is blocked

Firewall logging:

  • In Log Analytics, run: AZFWApplicationRule | limit 50
  • Verify traffic is flowing through the firewall and expected FQDNs are being allowed

Start VM on Connect:

  • Power off a session host from the Azure portal
  • Sign in as the assigned user via the AVD client
  • Verify the VM starts automatically and the session connects within 2–3 minutes

📩 Don't Miss the Next Solution

Join the list to see the real-time solutions I'm delivering to my GCC High clients.