Automating AVD Context-Based Redirections
What Are Context-Based Redirections?

Context-Based Redirections is a Preview feature in Azure Virtual Desktop that lets you control peripheral and device redirection — clipboard, drives, printers, USB — based on the compliance state of the connecting device, rather than applying a blanket allow or deny for all users.
Instead of a binary on/off toggle on the host pool, you map an Entra ID Authentication Context to a redirection type. A Conditional Access policy then evaluates whether the connecting device is Intune-compliant. Compliant devices get the redirection; non-compliant or BYOD devices do not.
|
Why this matters Clipboard and drive redirection are the most common data exfiltration vectors in VDI environments. Traditional AVD policies apply equally to corporate laptops and personal BYOD devices. Context-Based Redirections lets you allow clipboard on a managed device while blocking it on the same session from a personal machine — without creating separate host pools. |
How It Works — The Three-Layer Model
The feature works across three separate Azure / Microsoft 365 control planes, each configured independently:
|
Layer |
Service |
What you configure |
|
1 |
Entra ID |
Authentication Context Class Reference (c1–c25) |
|
2 |
Conditional Access |
Policy: target auth context → require compliant device |
|
3 |
AVD Host Pool |
customRdpProperty: map context ID to redirection types |
Prerequisites
|
Requirement |
Detail |
|
Azure Subscription |
With an AVD host pool already deployed |
|
Entra ID P1 or P2 |
Required for Conditional Access policies |
|
Microsoft Intune |
Devices must be enrolled and compliance policies in place |
|
Entra Role |
Conditional Access Administrator or Global Administrator |
|
Azure RBAC Role |
Desktop Virtualization Contributor (on the host pool) |
|
PowerShell Modules |
Microsoft.Graph, Az.DesktopVirtualization |
# Install required modules (one-time)
Install-Module Microsoft.Graph -Scope CurrentUser -Force
Install-Module Az.DesktopVirtualization -Scope CurrentUser -Force
Step 1 — Create the Authentication Context
An Authentication Context is a named signal within Entra ID (ID c1 through c25) that Conditional Access policies can target. Think of it as a label you attach to a resource request, which CA then evaluates against your policies.
Script: New-AVDAuthenticationContext.ps1
What the script does
- Connects to Microsoft Graph with Policy.ReadWrite.ConditionalAccess scope
- Checks if the context ID is already in use and offers to update it
- Creates the authentication context with IsAvailable = $true (equivalent to checking Publish to apps in the portal)
- Disconnects cleanly on exit
Key Graph API call
$params = @{
Id = $ContextId
DisplayName = $DisplayName
Description = $Description
IsAvailable = $true # Publishes the context to apps
}
New-MgIdentityConditionalAccessAuthenticationContextClassReference `
-BodyParameter $params
Usage
.\New-AVDAuthenticationContext.ps1 `
-DisplayName "AVD Compliant Device" `
-Description "Requires compliant device for AVD clipboard/drive/USB/printer redirection" `
-ContextId "c1" `
-TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
Context ID allocation tip IDs c1–c25 are tenant-wide. Keep a register of which ID maps to which purpose. Example: c1 = AVD Compliant Device, c2 = AVD Privileged Admin, c3 = Sensitive App MFA. Once used in a CA policy, changing a context ID will break the policy silently. |
Step 2 — Create the Conditional Access Policy
The CA policy is what enforces the compliance requirement. It watches for authentication attempts that carry the context ID from Step 1 and grants access only if the device is marked compliant by Intune.
Script: New-AVDConditionalAccessPolicy.ps1
What the script does
- Connects to Microsoft Graph with Policy.ReadWrite.ConditionalAccess and Group.Read.All
- Validates the authentication context from Step 1 exists and is published
- Resolves Entra group display names to Object IDs automatically — no manual GUID lookup
- Builds the policy body targeting the auth context (not a cloud app)
- Defaults to enabledForReportingButNotEnforced — safe for initial testing
- Detects duplicate policy names and warns before creating
Key CA policy structure
$policyBody = @{
displayName = $PolicyName
state = $PolicyState
conditions = @{
applications = @{
includeAuthenticationContextClassReferences = @($ContextId)
}
}
grantControls = @{
operator = "OR"
builtInControls = @("compliantDevice")
}
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $policyBody
Usage
.\New-AVDConditionalAccessPolicy.ps1 `
-TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-PolicyName "AVD - Require Compliant Device for Redirection" `
-ContextId "c1" `
-TargetGroupName "AVD-Users" `
-ExcludeGroupName "CA-BreakGlass-Exclusion" `
-PolicyState "enabledForReportingButNotEnforced"
|
Report-only mode — start here The -PolicyState parameter defaults to enabledForReportingButNotEnforced. In this mode, the policy evaluates but does not enforce. Sign-in logs show what WOULD have been blocked. Review Entra > Monitoring > Sign-in logs for at least 48 hours before switching to enabled. Always include a break-glass group in ExcludeGroupName to prevent admin lockout. |
Step 3 — Configure Host Pool RDP Properties
The final step writes the dynamic context mapping into the host pool’s customRdpProperty string. This is what tells the AVD gateway to trigger the CA evaluation using the auth context when a user connects and attempts a redirection.
Script: Set-AVDHostPoolRdpAuthContext.ps1
RDP property format
The dynamic context RDP properties follow this format:
# Dynamic context RDP property format
redirectclipboard:dynamicContext:c1:
redirectdrives:dynamicContext:c1:
redirectprinters:dynamicContext:c1:
usbdevicestoredirect:dynamicContext:c1:
What the script does
- Fetches the current customRdpProperty string from the host pool
- Backs it up to a timestamped .txt file before touching anything
- Parses the existing RDP string into a hashtable — never overwrites unrelated RDP properties
- Removes conflicting static properties (e.g. redirectclipboard:i:1) that would conflict with dynamic mode
- Adds or updates only the targeted redirection types
- Detects if no changes are needed and exits cleanly
- Supports -WhatIf to preview changes without applying
Usage
# All four redirections
.\Set-AVDHostPoolRdpAuthContext.ps1 `
-SubscriptionId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-ResourceGroupName "rg-avd-prod" `
-HostPoolName "hp-avd-prod-01" `
-ContextId "c1"
# Selective redirections only
.\Set-AVDHostPoolRdpAuthContext.ps1 `
-SubscriptionId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" `
-ResourceGroupName "rg-avd-prod" `
-HostPoolName "hp-avd-prod-01" `
-ContextId "c1" `
-Redirections Clipboard, Drive
# Preview changes without applying
.\Set-AVDHostPoolRdpAuthContext.ps1 ... -WhatIf
|
Conflict handling If the host pool already has redirectclipboard:i:1 or redirectdrives:i:0 set, the script automatically removes these before adding the dynamic context version. Static and dynamic context properties for the same redirection type cannot coexist — the last one wins in the RDP evaluation, which is undefined behaviour. |
Orchestrator — Run All Steps from One Command
Rather than running three scripts independently and managing dependencies between them, the orchestrator drives all three steps from a single JSON parameter file. It handles module checks, connections, step dependencies, and prints a final pass/fail summary.
Script: Invoke-AVDContextBasedRedirections.ps1
Parameter file — avd-cbr-params.json
{
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"SubscriptionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AuthContext": {
"ContextId": "c1",
"DisplayName": "AVD Compliant Device",
"Description": "Requires compliant device for redirection"
},
"ConditionalAccessPolicy": {
"PolicyName": "AVD - Require Compliant Device for Redirection",
"TargetGroupName": "AVD-Users",
"ExcludeGroupName": "CA-BreakGlass-Exclusion",
"PolicyState": "enabledForReportingButNotEnforced"
},
"HostPool": {
"ResourceGroupName": "rg-avd-prod",
"HostPoolName": "hp-avd-prod-01",
"Redirections": [ "Clipboard", "Drive", "Printer", "USB" ]
}
}
Orchestrator features
|
Feature |
Behaviour |
|
Pre-flight confirmation |
Prints a full summary and prompts y/n before any changes |
|
Step dependency logic |
Step 1 failure stops execution. Step 2 failure warns but Step 3 still runs. |
|
Selective re-run |
Use -Steps 3 to re-run a single step without touching the others |
|
Idempotent-safe |
Re-running on a fully configured tenant makes zero changes |
|
-WhatIf support |
Preview all three steps without modifying anything |
|
Final summary table |
Always printed — shows ✔ Success / – Skipped / ✘ Failed per step |
Orchestrator usage
# Full run — all three steps
.\Invoke-AVDContextBasedRedirections.ps1
# Custom parameter file
.\Invoke-AVDContextBasedRedirections.ps1 -ParameterFile ".\prod-params.json"
# Preview all changes (no modifications applied)
.\Invoke-AVDContextBasedRedirections.ps1 -WhatIf
# Retry only Step 3 after a failure
.\Invoke-AVDContextBasedRedirections.ps1 -Steps 3
Validation — Testing Your Configuration
After all three steps complete, validate behaviour from both a compliant and a non-compliant device. This cannot be automated — it requires a live AVD session.
|
Test scenario |
Expected result |
Where to check |
|
Connect from Intune-compliant device |
Clipboard / drive / printer available |
AVD session — try copy-paste |
|
Connect from non-compliant / BYOD |
Redirections blocked / greyed out |
AVD session — try copy-paste |
|
Check CA policy evaluation |
Policy shows in sign-in log details |
Entra > Monitoring > Sign-in logs |
|
Verify host pool RDP string |
customRdpProperty contains dynamicContext entries |
Script Inventory
|
Script |
Covers |
Primary module |
|
New-AVDAuthenticationContext.ps1 |
Step 1 |
Microsoft.Graph.Identity.SignIns |
|
New-AVDConditionalAccessPolicy.ps1 |
Step 2 |
Microsoft.Graph.Identity.SignIns, .Groups |
|
Set-AVDHostPoolRdpAuthContext.ps1 |
Step 3 |
Az.DesktopVirtualization |
|
Invoke-AVDContextBasedRedirections.ps1 |
Steps 1–3 |
All of the above |
|
avd-cbr-params.json |
Config |
Parameter file for orchestrator |
Known Limitations (Preview)
|
Preview feature — important caveats Context-Based Redirections is in Public Preview as of June 2026. The dynamic RDP property syntax (dynamicContext) is not yet fully documented publicly. Always validate the RDP string the Azure Portal writes after a manual save, then replicate it. Preview features may change syntax or behaviour before GA — test in a non-production host pool first. Sign-in log analysis via Graph API is the best automated approach to validate CA policy hits. |
Feature in Preview — verify before production use