Troubleshooting
Solutions for common issues encountered during deployment and operation.
Connection troubleshooting
flowchart TD
A["Cannot connect to desktop"] --> B{"Workspace visible<br/>in Windows App?"}
B -->|No| C["Assign Desktop<br/>Virtualization User role"]
B -->|Yes| D{"Error on launch?"}
D -->|Account prevented| E["Assign VM User Login<br/>or Administrator Login role"]
D -->|Timeout| F{"VM running?"}
F -->|No| G["Start-AvdOccasional.ps1"]
F -->|Yes| H["Run Test-AvdSessionHost.ps1"]
C --> I["Wait 5-10 min,<br/>sign out and back in"]
E --> I
Deployment troubleshooting
flowchart TD
A["Deployment failed"] --> B{"Quota error?"}
B -->|Yes| C["Try different region<br/>or request quota increase"]
B -->|No| D{"Permission error?"}
D -->|Yes| E["Verify Contributor role<br/>on subscription"]
D -->|No| F{"Validation error?"}
F -->|Yes| G["az bicep build<br/>+ validate parameters.json"]
F -->|No| H["Run Deploy with -Verbose<br/>and check activity log"]
Deployment Issues
Error: “The subscription does not have quota”
Symptoms: Deployment fails with quota-related error message.
Causes:
- Chosen region has resource quotas reached.
- Subscription-level limits hit (e.g., maximum VMs).
- Resource provider not registered.
Solutions:
- Try a different region:
# List supported regions
az provider show --namespace Microsoft.Compute `
--query "resourceTypes[?resourceType=='virtualMachines'].locations" -o table
# Update parameters.json
"location": { "value": "northeurope" }
# Retry deployment
.\scripts\Deploy-AvdOccasional.ps1Request quota increase:
- Go to Azure Portal
- Navigate to Quotas (search bar)
- Select Compute and your region
- Click quota item and select “+ New Quota Request”
- Request increase for D2s_v5 VMs (or B2s for light workload)
Register required resource providers:
az provider register --namespace Microsoft.Compute
az provider register --namespace Microsoft.Network
az provider register --namespace Microsoft.DesktopVirtualizationError: “InvalidTemplateDeployment” or “ValidationError”
Symptoms: Deployment fails at validation stage with cryptic error message.
Causes:
- Malformed parameters.json.
- Bicep syntax error.
- Missing or invalid parameter value.
- Region doesn’t support required resources.
Solutions:
- Validate template locally:
az deployment group validate `
--resource-group avd-occasional-rg `
--template-file infra/main.bicep `
--parameters @infra/parameters.json `
-o json | ConvertFrom-Json | .errors- Check for Bicep lint errors:
az bicep build infra/main.bicep- Verify parameters.json syntax:
# Check for JSON errors
$params = Get-Content infra/parameters.json -Raw | ConvertFrom-Json- Check that all resources are available in your region:
az provider list --query "[?registrationState=='Registered'].namespace" -o tsvError: “User does not have permissions”
Symptoms: Deployment fails with “Insufficient permissions” or “Unauthorized” error.
Causes:
- Azure account doesn’t have Contributor role on subscription.
- Service Principal lacks required permissions.
- Insufficient permission for role assignments.
Solutions:
- Verify your role:
az role assignment list --assignee (az account show --query user.name -o tsv)Output should include Contributor or Owner role.
If insufficient permissions, request access:
- Contact your subscription owner/administrator
- Ask for Contributor role assignment on the subscription (not resource group)
- Verify via above command after access granted
If using Service Principal, ensure it has required permissions:
# List permissions
az role assignment list --assignee <service-principal-id>Error: “The template contains invalid syntax”
Symptoms: Bicep build or deployment fails with syntax error.
Causes:
- Bicep code has typos or invalid constructs.
- Parameter file malformed JSON.
- PowerShell script has syntax errors.
Solutions:
- Re-clone repository to get latest correct version:
rm -Recurse avd-occasional # Remove local copy
git clone https://github.com/markheydon/avd-occasional.git
cd avd-occasional- Run Bicep lint to identify issues:
# Lint all Bicep files
Get-ChildItem -Recurse -Filter "*.bicep" | ForEach-Object {
az bicep build $_.FullName
}- Manually inspect
parameters.jsonfor malformed JSON:- Check for trailing commas
- Ensure all braces and brackets are balanced
- Verify string values are quoted with double quotes
Diagnosis with Test-AvdSessionHost
The Test-AvdSessionHost.ps1 script provides automated diagnostics for session host issues. Run it first when troubleshooting connectivity problems:
# Auto-discover and diagnose
.\scripts\Test-AvdSessionHost.ps1The script checks:
- VM power state (running/deallocated).
- VM extensions (AADLoginForWindows, DSC).
- Session host status in AVD host pool (Available/Unavailable).
- Entra ID RDP properties (authentication configuration).
- AVD agent heartbeat (last reported time).
Review the Recommendations section in script output for next steps. Then consult the relevant troubleshooting section below for detailed solutions.
Error: DSC extension fails or session host does not register
Symptoms: Deployment succeeds but the session host never appears in the host pool, or the DSC extension reports failure.
Causes:
- Outdated
artifactsLocationURL inparameters.json. - Network connectivity issues preventing DSC artifact download.
- Registration token expired before DSC ran.
Solutions:
- Check the DSC extension status in Azure Portal (VM → Extensions).
- Verify the
artifactsLocationvalue ininfra/parameters.json— see AVD DSC Artifact URL for how to update it. - Confirm outbound connectivity (public IP on NIC, NSG allows required egress).
- Redeploy or re-run the DSC extension after updating the artifact URL.
Connection Issues
Error: “Workspace not available in Windows App”
Symptoms: User signs into Windows App but sees no workspaces available.
Causes:
- Desktop Virtualization User role not assigned.
- Role assignment not yet propagated.
- User not assigned to correct Application Group.
- Workspace not configured correctly.
Solutions:
Run diagnostics first:
.\scripts\Test-AvdSessionHost.ps1If session host status is “Available”, role assignment may be the issue. Otherwise, see the script output for other problems.
Verify role assignment exists:
$appGroupId = (az resource list --resource-group avd-occasional-rg `
--resource-type "Microsoft.DesktopVirtualization/applicationGroups" `
--query '[0].id' -o tsv)
az role assignment list --scope $appGroupId --query "[].{Principal:principalName, Role:roleDefinitionName}" -o table- If role missing, assign it:
$userId = (az ad signed-in-user show --query id -o tsv)
az role assignment create `
--role "Desktop Virtualization User" `
--assignee $userId `
--scope $appGroupIdWait 5–10 minutes for role to propagate in Azure AD.
Sign out of Windows App completely, then sign back in.
Verify Desktop Application Group exists and is linked to Workspace:
az desktopvirtualization applicationgroup list `
--resource-group avd-occasional-rg `
--query "[].{Name:name, Type:applicationType, WorkspaceName:workspaceName}" -o tableError: “Your account is configured to prevent you from using this device”
Symptoms: User successfully connects to Windows App and sees workspace, but gets error when launching desktop.
Causes:
- Virtual Machine User Login role not assigned to user.
- Role not yet propagated.
- Session host VM is stopped or not running.
Solutions:
Run diagnostics first:
.\scripts\Test-AvdSessionHost.ps1If session host status is “Available”, review the output:
- If Power State is “VM deallocated”, start VMs with
.\scripts\Start-AvdOccasional.ps1 - If extensions show errors, redeploy with
.\scripts\Deploy-AvdOccasional.ps1 - If Entra ID auth is missing, check RDP properties and redeploy
- If heartbeat is old, restart the VM
If session host is not Available, continue below.
- If Power State is “VM deallocated”, start VMs with
Verify Virtual Machine User Login role is assigned:
$userId = (az ad signed-in-user show --query id -o tsv)
$vmIds = @(az vm list --resource-group avd-occasional-rg --query '[].id' -o tsv)
foreach ($vmId in $vmIds) {
$roles = @(az role assignment list --scope $vmId --assignee $userId `
--query "[].roleDefinitionName" -o tsv)
if ($roles) {
Write-Host "VM $(Split-Path $vmId -Leaf): $($roles -join ', ')"
} else {
Write-Host "VM $(Split-Path $vmId -Leaf): NO ROLES ASSIGNED"
}
}- If role missing, assign it:
$userId = (az ad signed-in-user show --query id -o tsv)
$vmIds = @(az vm list --resource-group avd-occasional-rg --query '[].id' -o tsv)
foreach ($vmId in $vmIds) {
az role assignment create `
--role "Virtual Machine User Login" `
--assignee $userId `
--scope $vmId
}Wait 5–10 minutes for roles to propagate.
Verify VMs are running:
az vm list --resource-group avd-occasional-rg `
--query "[].{Name:name, PowerState:powerState}" -o tableIf stopped, start them:
.\scripts\Start-AvdOccasional.ps1 -WaitForStartupError: Cannot Connect to Session Host (Network Timeout)
Symptoms: Connection attempt times out or fails with network unreachable error.
Causes:
- VM is stopped or deallocated
- Network Security Group blocking traffic
- Azure Virtual Desktop service temporarily unavailable
- Local firewall blocking Windows App
Solutions:
- Verify VM is running:
az vm list --resource-group avd-occasional-rg `
--query "[].{Name:name, PowerState:powerState, ProvisioningState:provisioningState}" -o tableStart if needed:
.\scripts\Start-AvdOccasional.ps1 -WaitForStartup- Check Network Security Group rules:
$nsgId = (az resource list --resource-group avd-occasional-rg `
--resource-type "Microsoft.Network/networkSecurityGroups" `
--query '[0].id' -o tsv)
az network nsg rule list --resource-group avd-occasional-rg `
--nsg-name (Split-Path $nsgId -Leaf) -o tableNSG should allow outbound traffic. If all rules are “Deny”, access is blocked.
Verify local network connectivity:
- Temporarily disable personal firewall or VPN
- Try connecting from a different network (e.g., mobile hotspot)
- Check if ISP blocks Azure Virtual Desktop traffic
Wait a few minutes and try again (Azure Virtual Desktop service may be refreshing).
VM & Post-Deployment Issues
VMs Not Appearing or Stuck in “Creating” State
Symptoms: Deployment appears to complete, but VMs don’t show in resource list or remain stuck in Provisioning state.
Quick Check: Run diagnostics:
.\scripts\Test-AvdSessionHost.ps1Review output for extension status and session host registration status.
Causes:
- Deployment still in progress (check actual status).
- Deployment failed silently.
- Resource group query filtered wrong type.
- VM extension failed.
Solutions:
Check VM and extension status via diagnostics:
.\scripts\Test-AvdSessionHost.ps1If extensions show failed status, see recommendations in the output.
Check actual deployment status:
# Get latest deployment
$deployment = (az deployment group list --resource-group avd-occasional-rg `
--query '[-1]' | ConvertFrom-Json)
Write-Host "Deployment: $($deployment.name)"
Write-Host "State: $($deployment.properties.provisioningState)"
Write-Host "Timestamp: $($deployment.properties.timestamp)"
# View detailed error (if failed)
if ($deployment.properties.provisioningState -ne 'Succeeded') {
$deployment.properties.error | ConvertTo-Json
}- Check VM extension status (Custom Script installation):
$vmExtensions = @(az vm extension list --resource-group avd-occasional-rg `
--vm-name (az vm list --resource-group avd-occasional-rg --query '[0].name' -o tsv) `
--query "[].{Name:name, ProvisioningState:provisioningState, TypeHandlerVersion:typeHandlerVersion}")
$vmExtensions | ConvertTo-JsonIf extension failed, re-run:
.\scripts\Deploy-AvdOccasional.ps1 -WhatIf- Rerun deployment (idempotent safe):
.\scripts\Deploy-AvdOccasional.ps1High Unexpected Costs
Symptoms: Azure bill significantly higher than £94–126/month (active) or £2–3/month (deallocated).
Causes:
- VMs still running (should deallocate after use)
- Data egress charges (large file downloads/uploads)
- Public IPs not being deleted during stop
- Other resources left running (databases, etc.)
Solutions:
- Check VM power states:
az vm list --resource-group avd-occasional-rg `
--query "[].{Name:name, PowerState:powerState}" -o tableIf running, stop them:
.\scripts\Stop-AvdOccasional.ps1- Verify Public IPs are deleted when VMs stopped:
# Check if Public IPs exist (should be empty when VMs stopped)
az network public-ip list --resource-group avd-occasional-rg `
--query "[].{Name:name, IpAddress:ipAddress}" -o tableNote: Public IPs are automatically managed by Start/Stop scripts. If IPs remain after stopping, check script executed successfully.
Monitor data egress:
- Go to Azure Cost Management (Portal)
- Filter by charge type, resource group
- Identify which resources generate data costs
- Reduce file transfers or move data within Azure region
Review for unexpected resources:
# List all resources by type
az resource list --resource-group avd-occasional-rg `
--query "[].{Name:name, Type:type, CostRelevant:type}" -o tableDelete any resources created accidentally (databases, additional storage, etc.):
# Example: Delete unexpected database
az resource delete --resource-group avd-occasional-rg --name <resource-name> --resource-type <type>Script & Automation Issues
PowerShell Execution Policy Error
Symptoms: Script fails with “cannot be loaded because running scripts is disabled on this system”.
Causes: PowerShell execution policy blocks script execution.
Solutions:
- Check current policy:
Get-ExecutionPolicy- Temporarily allow scripts for current user/session:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser- Run script:
.\scripts\Deploy-AvdOccasional.ps1- (Optional) Revert execution policy:
Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUserScript Parameter Not Recognised
Symptoms: Running script with -Parameter value results in “Parameter not found” error.
Causes:
- Typo in parameter name
- PowerShell doesn’t recognise parameter
- Script version mismatch
Solutions:
- Check available parameters:
Get-Help .\scripts\Deploy-AvdOccasional.ps1 -Parameter *Verify that you’re using a valid parameter name and spelling, matching what
Get-Helpshows:- Example parameter:
-AdminPassword - PowerShell parameter names are case-insensitive, so
-AdminPasswordand-adminPasswordare treated the same.
- Example parameter:
Re-clone repository in case script is outdated:
git clone https://github.com/markheydon/avd-occasional.gitGeneral Debugging
Enable Detailed Logging
For deployments, add -Verbose flag:
.\scripts\Deploy-AvdOccasional.ps1 -VerboseFor Azure CLI commands:
az deployment group create ... --debugCheck Azure Activity Log
# Show recent Azure activities
az monitor activity-log list --max-events 20 `
--query "[].{Time:eventTimestamp, EventName:eventName, Status:status, Message:description}" -o tableCollect Diagnostics
# Export all resource details for debugging
az resource list --resource-group avd-occasional-rg -o json > resources.json
# Export deployment details
az deployment group show --resource-group avd-occasional-rg --name main -o json > deployment.jsonContact Support
If you cannot resolve the issue:
Gather diagnostics:
- Output of:
az account show - Output of:
az resource list --resource-group avd-occasional-rg - Recent error messages (copy full text)
- Steps already tried
- Output of:
Report issue on GitHub Issues
Next: PowerShell Scripts Reference
Last Updated: July 2026