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.
| Item | Where to Configure |
|---|---|
| Azure Government subscription active, engineer has Subscription Owner | Azure Government portal — portal.azure.us |
| GCC High Entra tenant active, engineer has Global Administrator | Entra admin center — entra.microsoft.us |
| M365 GCC High E3 or E5 licenses assigned to all users | Microsoft 365 admin center |
| MDM auto-enrollment enabled for All users | Entra admin center > Mobility (MDM and MAM) > Microsoft Intune > MDM user scope: All |
| "Users may join devices to Microsoft Entra ID" set to All | Entra admin center > Devices > Device settings |
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.
| Setting | Value | Reason |
|---|---|---|
| Users may join devices to Microsoft Entra ID | All | Required 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) | Disabled | Global 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 join | Disabled | AVD 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) | Enabled | Rotates 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 key | No | BitLocker 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. |
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.
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.
- Navigate to Azure Government portal > Resource groups > Create
- Set Subscription to your AVD subscription
- Set Resource group name — e.g.,
rg-avd-prod-usgovva - Set Region to US Gov Virginia
- Add tags as required by your tagging policy (e.g.,
environment: production,workload: avd) - 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.
- Navigate to Virtual networks > Create
- Set Resource group to
rg-avd-prod-usgovva - Set Name — e.g.,
vnet-avd-usgovva - Set Region to US Gov Virginia
- Under IP addresses, the portal defaults to
10.0.0.0/16for the VNet address space. You may use any RFC 1918 range that does not conflict with your on-premises or peered networks. - The wizard creates a
defaultsubnet automatically at10.0.0.0/24. You may rename it for clarity, but the name has no functional impact. Do not addAzureFirewallSubnetmanually — enabling Azure Firewall in the next step creates it automatically at10.0.1.0/26.
| Subnet | Default CIDR | Purpose |
|---|---|---|
default (or your chosen name) | 10.0.0.0/24 | AVD session host NICs |
AzureFirewallSubnet | auto-created at 10.0.1.0/26 | Created automatically when Azure Firewall is enabled below |
- Under Security, configure as follows:
| Option | Setting | Reason |
|---|---|---|
| Virtual network encryption | Disabled | AVD traffic is already TLS-encrypted at the application layer. No CMMC requirement is unmet without this. |
| Azure Bastion | Disabled | Admin 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 Firewall | Enabled | Enable here to provision the firewall inline with the VNet. Select Standard tier and create a new public IP. |
| Azure DDoS Network Protection | Disabled | The 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. |
- Select Review + Create > Create
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.
- Navigate to Route tables > Create
- Set Resource group to
rg-avd-prod-usgovva - Set Name — e.g.,
udr-avd-sessionhosts - Set Region to US Gov Virginia
- Set Propagate gateway routes to No
- Select Review + Create > Create
After creation, add the default route:
- Open
udr-avd-sessionhosts> Routes > Add - Set Route name:
route-all-to-firewall - Set Destination:
0.0.0.0/0 - Set Next hop type: Virtual appliance
- Set Next hop address: the Azure Firewall private IP from Step 2
- Select Add
Associate the UDR with the session host subnet:
- Open
udr-avd-sessionhosts> Subnets > Associate - Select your VNet and the session host subnet (
defaultunless renamed — notAzureFirewallSubnet) - Select OK
Step 4: Create the Log Analytics Workspace
Required for AVD Insights, firewall logs, and Defender for Endpoint telemetry.
- Navigate to Log Analytics workspaces > Create
- Set Resource group to
rg-avd-prod-usgovva - Set Name — e.g.,
law-avd-usgovva - Set Region to US Gov Virginia
- Select Review + Create > Create
Once created, enable diagnostic logging on the firewall:
- Open the firewall resource > Diagnostic settings > Add diagnostic setting
- Name it
diag-afw-avd - Check AzureFirewallApplicationRule, AzureFirewallNetworkRule, AzureFirewallDnsProxy
- Check Send to Log Analytics workspace and select
law-avd-usgovva - Set Destination table to Resource specific
- Leave Archive to a storage account, Stream to an event hub, and Send to partner solution unchecked
- Select Save
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
- Navigate to Azure Virtual Desktop > Workspaces > Create
- Set Resource group to
rg-avd-prod-usgovva - Set Workspace name — e.g.,
avdws-prod - Set Location to US Gov Virginia
- Skip the Application groups tab — the application group will be created with the host pool in Step 6
- On the Advanced tab, select
law-avd-usgovvaas the Log Analytics workspace. Leave the storage account and event hub checkboxes unchecked. - Select Review + Create > Create
After creation, configure the full diagnostic settings:
- Open
avdws-prod> Diagnostic settings > Add diagnostic setting - Name it
diag-avdws-prod - Check all four log categories: Checkpoint, Error, Management, Feed
- Check Send to Log Analytics workspace and select
law-avd-usgovva - Set Destination table to Resource specific
- Select Save
Step 6: Create the AVD Host Pool
- Navigate to Azure Virtual Desktop > Host pools > Create
- Basics tab:
| Setting | Value |
|---|---|
| Resource group | rg-avd-prod-usgovva |
| Host pool name | hp-avd-prod |
| Location | US Gov Virginia |
| Host pool type | Personal |
| Assignment type | Automatic |
| Load balancing algorithm | Breadth-first |
| Preferred app group type | Desktop |
- Virtual machines tab: Leave empty — session hosts are added in Step 9
- Workspace tab: Select
avdws-prod - Diagnostics tab: Select
law-avd-usgovvaas the Log Analytics workspace. Check all eight log categories. Leave archive to storage account and stream to event hub unchecked. - Select Review + Create > Create
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.
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:
- Open
hp-avd-prod> RDP properties - Set the following under Device redirection:
| Property | Value | Reason |
|---|---|---|
| Clipboard redirection | Disabled | Prevent CUI from leaving the session |
| Drive redirection | Disabled | Prevent local drive mounting |
| Camera redirection | Disabled | |
| Printer redirection | Disabled (or selectively enabled) | |
| WebAuthn redirection | Enabled | Allows YubiKeys and Windows Hello to authenticate inside the session — extends phishing-resistant auth to resources accessed within AVD |
| USB redirection | Disabled | Generic USB redirection includes storage devices — a direct CUI exfiltration path. WebAuthn uses a separate channel and is unaffected by this setting. |
| Smart card redirection | Enabled | Allows CAC/PIV cards to authenticate inside the session. No data exfiltration risk. |
- Under Advanced, add the following custom RDP properties:
| Property | Value | Reason |
|---|---|---|
enablerdsaadauth:i:1 | Enables SSO via Entra ID, preventing a second authentication prompt at the VM | |
screencaptureprotection:i:2 | Blocks screen capture on both client and server, preventing screenshots of CUI from inside the session |
- 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
- Select Save
Enable Start VM on Connect:
- Open
hp-avd-prod> Properties - Set Start VM on connect to Yes
- Select Save
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:
- Navigate to Azure Virtual Desktop > Application groups
- Open
hp-avd-prod-DAG> Assignments > Add - Add the users or security group that should have access to AVD
- 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:
- Navigate to Entra admin center > Groups > New group
- Set Group type to Security
- Set Membership type to Dynamic Device
- Set Group name — e.g.,
AVD Session Hosts - Under Dynamic device members, add the following rule:
(device.displayName -startsWith "avd-")
- Select Create
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.
- Replace
AVD DEVICE GROUP HEREin the script with the object ID of theAVD Session Hostsgroup created above - 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
- Verify output confirms RDP is enabled on both service principals
Enable SSO on the host pool:
- Open
hp-avd-prod> RDP properties > Connections - Set Microsoft Entra single sign-on to Enabled
- 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.
- Open
hp-avd-prod> Session hosts > Add - Virtual machines tab:
| Setting | Value |
|---|---|
| Resource group | rg-avd-prod-usgovva |
| Name prefix | avd (Azure appends -0, -1, etc. — dashes are not allowed in the prefix) |
| Virtual machine type | Azure virtual machine |
| Availability options | No infrastructure redundancy required |
| VM size | Standard_D8as_v6 (or D16as_v6 for power users) |
| Number of VMs | 20 |
| Security type | Trusted Launch |
| Secure Boot | Enabled |
| vTPM | Enabled |
| Integrity monitoring | Enabled |
| OS disk type | Premium SSD LRS |
| OS disk size | 128 GB (default) |
| Boot diagnostics | Enabled with managed storage account |
-
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.
-
Network tab:
| Setting | Value |
|---|---|
| Virtual network | vnet-avd-usgovva |
| Subnet | default (or your session host subnet name) |
| Network security group | None |
| Public inbound ports | None |
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.
- Domain to join tab:
| Setting | Value |
|---|---|
| Select which directory you would like to join | Microsoft Entra ID |
| Enroll VM with Intune | Yes |
| Add VM to a single group | Optional — specify a device group if targeting scoped Intune policies |
-
Virtual machine administrator account: Set a local admin username and password (stored in the VM, not synced to Entra)
-
Select Review + Create > Add
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.usfor 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.