Skip to content

askaresh/avd_terraform

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Azure Virtual Desktop Terraform Configuration

This directory contains a modular Terraform configuration that deploys Azure Virtual Desktop (AVD) environments supporting multiple deployment patterns with enterprise-grade monitoring, scaling, and dashboard capabilities.

🏆 Enterprise-Grade Features:

  • Microsoft Cloud Adoption Framework naming standards
  • Comprehensive monitoring with Log Analytics
  • Automatic scaling plans for cost optimization (40-70% savings)
  • Custom dashboards for operational insights
  • Cost management with alerts and budget tracking

🚀 Supported Deployment Types

This configuration supports four distinct AVD deployment patterns:

Deployment Type Description Use Cases Resource Sharing Naming Suffix
pooled_desktop Traditional shared desktop environment Call centers, task workers, training labs Multiple users per VM desktop
personal_desktop Dedicated 1:1 desktop assignments Developers, power users, persistent workloads One user per VM personal
pooled_remoteapp Shared published applications Line-of-business apps, legacy applications Multiple users per VM apps
personal_remoteapp Dedicated application access Sensitive apps, compliance requirements One user per VM personalapps

📊 Enterprise Features

1. Scaling Plans - Cost Optimization

  • Automatic scaling based on usage patterns
  • Environment-specific schedules (dev vs prod)
  • Cost savings of 40-70% for pooled deployments
  • Smart scaling only for pooled deployments (desktop & RemoteApp)
  • Enterprise-grade architecture: Uses built-in "Desktop Virtualization Power On Off Contributor" role with subscription-level scope
  • Azure Portal compatibility: Separate host pool association resource ensures reliable portal integration
  • Best practices: Random UUID for role assignments, lifecycle management for stability

2. Monitoring & Observability

  • Log Analytics workspace with comprehensive logging
  • Diagnostic settings for all AVD resources
  • Performance metrics for session hosts
  • Configurable retention (30-730 days)

3. Custom Dashboards

  • Real-time insights for AVD environments
  • Key metrics display (sessions, performance, costs)
  • Quick navigation to Azure resources
  • Environment-specific views

4. Cost Management

  • Daily cost alerts with configurable thresholds
  • Budget tracking with dynamic monthly start dates (auto-calculated from current month)
  • Budget notifications at 90% and 100% thresholds
  • Cost optimization recommendations
  • Spending insights and trends

Microsoft-Compliant Resource Naming

All resources follow Microsoft Cloud Adoption Framework naming standards with deployment-specific suffixes:

Resource Type Pattern Examples
Host Pool vdpool-{prefix}-{environment}-{suffix} vdpool-avd-dev-desktop, vdpool-avd-prod-apps
Application Group vdag-{prefix}-{environment}-{suffix} vdag-avd-dev-personal, vdag-avd-prod-personalapps
Workspace vdws-{prefix}-{environment} vdws-avd-dev, vdws-avd-prod
Subnet snet-{prefix}-{environment} snet-avd-dev, snet-avd-prod
Virtual Network vnet-{prefix}-{environment} vnet-avd-dev, vnet-avd-prod
Network Security Group nsg-{prefix}-{environment} nsg-avd-dev, nsg-avd-prod

Architecture

This Terraform configuration deploys a complete Azure Virtual Desktop environment with dynamic configuration based on the selected deployment type:

graph TB
    subgraph "Azure Subscription"
        subgraph "Resource Group"
            subgraph "Azure Virtual Desktop Service"
                WS["Workspace<br/>vdws-{prefix}-{env}"]
                WSAG["Workspace↔AppGroup<br/>Association"]
                AG["Application Group<br/>vdag-{prefix}-{env}-{suffix}<br/>(Dynamic Type)"]
                HP["Host Pool<br/>vdpool-{prefix}-{env}-{suffix}<br/>(Dynamic Config)"]
                REG["Registration Info<br/>(Token for DSC join)"]
            end

            subgraph "Networking"
                VNET["Virtual Network<br/>vnet-{prefix}-{env}"]
                SUBNET["Subnet<br/>snet-{prefix}-{env}"]
                NSG["Network Security Group<br/>nsg-{prefix}-{env}"]
                NSGA["NSG↔Subnet Association"]
            end

            subgraph "Session Hosts"
                VM1["Session Host VM 1<br/>vm-{prefix}-{env}-01<br/>(Windows 11 + M365)"]
                VM2["Session Host VM 2<br/>vm-{prefix}-{env}-02<br/>(Optional)"]
                VM3["Session Host VM N<br/>vm-{prefix}-{env}-0N<br/>(Scalable)"]

                NIC1["NIC 1<br/>nic-{prefix}-{env}-01"]
                NIC2["NIC 2<br/>nic-{prefix}-{env}-02"]
                NIC3["NIC N<br/>nic-{prefix}-{env}-0N"]

                EXT1["VM Extensions:<br/>- DSC (AVD Agent Registration)<br/>- AADLoginForWindows<br/>- GuestAttestation"]
                EXT2["VM Extensions:<br/>- DSC (AVD Agent Registration)<br/>- AADLoginForWindows<br/>- GuestAttestation"]
                EXT3["VM Extensions:<br/>- DSC (AVD Agent Registration)<br/>- AADLoginForWindows<br/>- GuestAttestation"]
            end

            subgraph "Monitoring & Cost (Optional)"
                LAW["Log Analytics<br/>law-{prefix}-{env}"]
                DIAGHP["Diagnostic Setting<br/>(Host Pool → LAW)"]
                DIAGVM["Diagnostic Setting<br/>(Session Hosts → LAW)"]
                DASH["Dashboard<br/>dashboard-{prefix}-{env}"]
                ACGROUP["Action Group<br/>ag-cost-{prefix}-{env}"]
                BUDGET["Cost Budget<br/>budget-{prefix}-{env}"]
                AUTOSHUTDOWN["Auto-Shutdown Schedule<br/>(18:00 daily per VM)"]
            end

            subgraph "Scaling (Pooled Only)"
                SP["Scaling Plan<br/>scaling-{prefix}-{env}"]
                ASSOC["Scaling Plan ↔<br/>Host Pool Association"]
                SPROLE["Role Assignment<br/>Desktop Virtualization<br/>Power On Off Contributor"]
            end
        end

        subgraph "Azure Active Directory"
            USERS["Users / Groups<br/>(security_principal_object_ids)"]
            ROLES["RBAC Roles:<br/>- Desktop Virtualization User<br/>- Virtual Machine User Login"]
        end

        subgraph "AVD Client Access"
            WEBCLIENT["Web Client<br/>(rdweb.wvd.microsoft.com)"]
            NATIVECLIENT["Native Clients<br/>(Windows / Mac / iOS / Android)"]
        end
    end

    %% AVD Service relationships
    WS --> WSAG --> AG --> HP
    HP --> REG

    %% Networking
    SUBNET --> VNET
    NSGA --> SUBNET
    NSGA --> NSG

    %% Session Hosts
    HP --> VM1 & VM2 & VM3
    REG --> EXT1 & EXT2 & EXT3
    VM1 --> NIC1 --> SUBNET
    VM2 --> NIC2 --> SUBNET
    VM3 --> NIC3 --> SUBNET
    VM1 --> EXT1
    VM2 --> EXT2
    VM3 --> EXT3

    %% Monitoring
    HP --> DIAGHP --> LAW
    VM1 & VM2 & VM3 --> DIAGVM --> LAW
    LAW --> DASH
    HP --> DASH
    VM1 & VM2 & VM3 --> AUTOSHUTDOWN
    BUDGET --> ACGROUP

    %% Scaling (pooled only, optional)
    SPROLE --> SP
    SP --> ASSOC --> HP

    %% RBAC
    USERS --> ROLES
    ROLES -.-> AG
    ROLES -.-> VM1 & VM2 & VM3

    %% Client access
    USERS --> WEBCLIENT & NATIVECLIENT
    WEBCLIENT & NATIVECLIENT --> WS

    %% Styling
    classDef avdService fill:#e1f5fe,stroke:#0288d1
    classDef networking fill:#f3e5f5,stroke:#7b1fa2
    classDef compute fill:#e8f5e8,stroke:#388e3c
    classDef security fill:#fff3e0,stroke:#f57c00
    classDef client fill:#fce4ec,stroke:#c62828
    classDef monitoring fill:#fff8e1,stroke:#f9a825
    classDef scaling fill:#e8eaf6,stroke:#3949ab
    classDef assoc fill:#f5f5f5,stroke:#9e9e9e

    class WS,AG,HP,REG,WSAG avdService
    class VNET,SUBNET,NSG,NSGA networking
    class VM1,VM2,VM3,NIC1,NIC2,NIC3,EXT1,EXT2,EXT3 compute
    class USERS,ROLES security
    class WEBCLIENT,NATIVECLIENT client
    class LAW,DIAGHP,DIAGVM,DASH,ACGROUP,BUDGET,AUTOSHUTDOWN monitoring
    class SP,ASSOC,SPROLE scaling
Loading

Key Components

Component Purpose Name Pattern Conditional
Resource Group Container for all AVD resources rg-{prefix}-{environment} Always
Virtual Network Isolated network for session hosts vnet-{prefix}-{environment} Always
Subnet Session host network segment snet-{prefix}-{environment} Always
Network Security Group Subnet traffic control nsg-{prefix}-{environment} Always
Host Pool Manages session host capacity and load balancing vdpool-{prefix}-{environment}-{suffix} Always
Registration Info Short-lived token used by DSC to join session hosts (child of Host Pool) Always
Application Group Defines published desktops or RemoteApp applications vdag-{prefix}-{environment}-{suffix} Always
Workspace User-facing portal aggregating app groups vdws-{prefix}-{environment} Always
Published Applications Specific apps for RemoteApp deployments (child of App Group) RemoteApp types only
Session Host VMs Windows 11 VMs running user sessions vm-{prefix}-{environment}-{nn} Always
VM Extensions DSC Agent Registration, AAD Login, Guest Attestation (per VM) Always
RBAC Assignments Desktop Virtualization User + VM User Login roles (role assignments) Always
Log Analytics Workspace Centralised monitoring and diagnostics law-{prefix}-{environment} enable_monitoring = true
Diagnostic Settings Routes Host Pool and VM metrics to Log Analytics (per resource) enable_monitoring = true
Scaling Plan Automatic cost optimization for pooled deployments scaling-{prefix}-{environment} enable_scaling_plans = true + pooled types
Scaling Plan ↔ Host Pool Association Links scaling plan to host pool (separate resource for portal compatibility) (association resource) enable_scaling_plans = true + pooled types
Scaling Plan Role Assignment "Desktop Virtualization Power On Off Contributor" at subscription scope (UUID role assignment) enable_scaling_plans = true + pooled types
Action Group Email notification target for cost alerts ag-cost-{prefix}-{environment} enable_cost_alerts = true
Cost Budget Monthly spend tracking with 90%/100% alert thresholds budget-{prefix}-{environment} enable_cost_alerts = true
Auto-Shutdown Schedule Stops VMs at 18:00 daily to reduce off-hours costs (per VM) enable_cost_alerts = true
Dashboard Operational insights in Azure Portal dashboard-{prefix}-{environment} enable_dashboards = true

✅ All names follow Microsoft Cloud Adoption Framework standards

Deployment Type Configuration Matrix

The configuration automatically adjusts based on the deployment_type variable:

Setting pooled_desktop personal_desktop pooled_remoteapp personal_remoteapp
Host Pool Type Pooled Personal Pooled Personal
App Group Type Desktop Desktop RemoteApp RemoteApp
Load Balancer BreadthFirst/DepthFirst N/A BreadthFirst/DepthFirst N/A
Max Sessions User-defined 1 (automatic) User-defined 1 (automatic)
Start VM on Connect false true false true
Requires Apps No No Yes Yes
Supports Scaling Yes No Yes No

Pre-configured Deployment Options

Quick Deployment Matrix

Environment Deployment Type File Use Case Resulting Host Pool Name
Development Pooled Desktop dev-pooled-desktop.tfvars Testing, training, call centers vdpool-avd-dev-desktop
Development Personal Desktop dev-personal-desktop.tfvars Developer workstations vdpool-avd-dev-personal
Development Pooled RemoteApp dev-pooled-remoteapp.tfvars App testing, legacy apps vdpool-avd-dev-apps
Production Personal RemoteApp prod-personal-remoteapp.tfvars Executive/compliance apps vdpool-avd-prod-personalapps

Enhanced Deployment Options (with Monitoring & Scaling)

Environment Deployment Type File Features Use Case
Production Pooled RemoteApp + Monitoring prod-pooled-remoteapp-with-monitoring.tfvars Monitoring, Scaling, Dashboards Production apps with insights
Development Pooled Desktop + Enhanced Scaling dev-pooled-desktop-enhanced-scaling.tfvars Built-in role with subscription scope, Advanced schedules, User notifications, Auto-shutdown Development with full cost optimization

Scaling Plan Behavior

Development Environment (Default)

  • Weekdays: Ramp-up 08:00, Peak 09:00-17:00, Ramp-down 17:00, Off-peak 18:00+
    • Minimum hosts: 20% during ramp-up/peak, 20% during ramp-down
  • Weekends: Ramp-up 09:00, Peak 10:00-16:00, Ramp-down 16:00, Off-peak 17:00+
    • Minimum hosts: 10% during ramp-up/peak, 10% during ramp-down
  • Aggressive scaling for maximum cost savings

Production Environment (Default)

  • Weekdays: Ramp-up 07:00, Peak 08:00-18:00, Ramp-down 18:00, Off-peak 19:00+
    • Minimum hosts: 30% during ramp-up/peak, 30% during ramp-down
  • Weekends: Ramp-up 08:00, Peak 09:00-17:00, Ramp-down 17:00, Off-peak 18:00+
    • Minimum hosts: 20% during ramp-up/peak, 20% during ramp-down
  • Conservative scaling for reliability

Note: Schedules are fully customizable via scaling_plan_schedules variable. Enhanced scaling deployments may have different schedules.

Monitoring Capabilities

Log Analytics Workspace

  • Host Pool Logs: Connection, error, management, and registration events
  • Session Host Metrics: CPU, memory, disk, and performance data
  • Custom Queries: Pre-built queries for common AVD scenarios
  • Retention Options: 30, 60, 90, 120, 180, 365, or 730 days

Dashboard Features

  • Session Metrics: Real-time session data
  • Performance: Resource utilization
  • Cost Analysis: Spending insights
  • Health Status: System health overview
  • Events & Alerts: Recent activity

Contents

The configuration is broken into logical files:

File Purpose
providers.tf Specifies the required provider versions and configures AzureRM, AzureAD, Random, and AzAPI providers. Subscription ID is read from the ARM_SUBSCRIPTION_ID environment variable.
variables.tf Declares all variables that can be customised for an environment. Most defaults come from the supplied ARM template.
main.tf Contains resource definitions for the resource group, network, host pool, application group, workspace, role assignments, NICs, virtual machines, VM extensions, monitoring, scaling, auto-shutdown, and dashboards.
outputs.tf Exposes key information about the deployment (resource group, host pool name, monitoring insights, etc.).
templates/dashboard.tpl Custom Azure dashboard template for operational insights.
set-auth.ps1 Authentication helper script — reads .env and sets ARM_* environment variables for the current PowerShell session. Run once before any Terraform commands.
.env.example Template showing the required credential variables. Copy to .env and populate with real values.
.env Your local credentials file (never committed — excluded by .gitignore).

To deploy this configuration you typically create a variable file such as dev.tfvars or prod.tfvars and pass it explicitly with -var-file. See the Using multiple environments section below for guidance.

Important — do not use the .auto.tfvars extension. Terraform automatically loads every *.auto.tfvars file in the directory simultaneously (alphabetically). Because this repository contains multiple environment configs, using .auto.tfvars causes all of them to merge — with the last file loaded winning on any conflicting variable (e.g. a prod file with admin_password = "" silently overriding a dev file's password). Always use plain .tfvars and pass the file explicitly with -var-file.

Prerequisites

  • Terraform 1.2 or later and the required providers (all managed by providers.tf):
    • azurerm — Azure Resource Manager
    • azuread — Azure Active Directory
    • random — UUID generation for role assignments
    • azapi — Session host cleanup during destroy
  • An Azure subscription with the Virtual Desktop service enabled.
  • An Azure Service Principal with Contributor access to the target subscription.
  • A .env credentials file (copied from .env.example) with the Service Principal credentials — see the Authentication Setup section for full instructions.
  • Object IDs for users, groups or service principals that require access to the published desktops. These IDs are supplied via the security_principal_object_ids variable.

Deploying

Quick Start

  1. Clone the repository and navigate to the project directory
  2. Create your credentials file
    Copy-Item .env.example .env
    # Edit .env and fill in your ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID
  3. Load credentials into your PowerShell session (repeat each time you open a new terminal)
    .\set-auth.ps1
  4. Choose your deployment type by selecting the appropriate .tfvars file or creating a custom one
  5. Deploy using Terraform

For detailed authentication setup, Service Principal creation steps, and multi-machine guidance see deployment-guide.md — Authentication Setup.

Deployment Type Examples

The repository includes pre-configured examples for each deployment pattern:

Pooled Desktop (Traditional AVD)

.\set-auth.ps1
terraform init
terraform plan -var-file=dev-pooled-desktop.tfvars
terraform apply -var-file=dev-pooled-desktop.tfvars

Personal Desktop (Dedicated VMs)

.\set-auth.ps1
terraform init
terraform plan -var-file=dev-personal-desktop.tfvars
terraform apply -var-file=dev-personal-desktop.tfvars

RemoteApp (Published Applications)

.\set-auth.ps1
terraform init
terraform plan -var-file=dev-pooled-remoteapp.tfvars
terraform apply -var-file=dev-pooled-remoteapp.tfvars

Production RemoteApp (Dedicated App Access)

.\set-auth.ps1
terraform init
terraform plan -var-file=prod-personal-remoteapp.tfvars
terraform apply -var-file=prod-personal-remoteapp.tfvars

Development with Enhanced Scaling & Monitoring

.\set-auth.ps1
terraform init
terraform plan -var-file=dev-pooled-desktop-enhanced-scaling.tfvars
terraform apply -var-file=dev-pooled-desktop-enhanced-scaling.tfvars

Custom Configuration

Create your own .tfvars file with the required settings:

# Custom deployment configuration
deployment_type = "pooled_desktop"  # Choose deployment pattern
environment     = "prod"
prefix          = "company"

# Network configuration
vnet_address_space     = ["10.0.0.0/24"]
subnet_address_prefix  = "10.0.0.0/24"

# Deployment-specific settings
session_host_count = 5
max_session_limit  = 6
load_balancer_type = "DepthFirst"  # For pooled types only

# Monitoring and scaling (optional)
enable_monitoring = true
enable_scaling_plans = true
enable_cost_alerts = true
enable_dashboards = true
monitoring_retention_days = 30
cost_alert_threshold = 100

# Security
security_principal_object_ids = [
  "user-or-group-object-id-1",
  "user-or-group-object-id-2"
]
admin_password = "SecurePassword123!"

# For RemoteApp deployments, define published applications
published_applications = [
  {
    name                    = "excel"
    display_name           = "Microsoft Excel"
    description            = "Spreadsheet Application"
    path                   = "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE"
    command_line_arguments = ""
    command_line_setting   = "Allow"
    show_in_portal         = true
  }
]

Multiple environments (dev/test/prod)

Azure best practices recommend organising resources by environment and using a consistent naming strategy. To support this, the configuration exposes an environment variable that is appended to all resource names. Each environment should be deployed into its own resource group and (ideally) its own subscription to simplify governance and cost management.

To deploy multiple environments:

  1. Create one variable file per environment. For example:

    dev.tfvars

    environment                   = "dev"
    location                      = "australiaeast"
    security_principal_object_ids = ["00000000-0000-0000-0000-000000000000"]
    admin_password                = "P@ssword123!"
    enable_monitoring             = true
    enable_scaling_plans          = true
    tags = {
      owner = "dev-team"
    }

    prod.tfvars

    environment                   = "prod"
    location                      = "australiaeast"
    security_principal_object_ids = ["11111111-1111-1111-1111-111111111111"]
    admin_password                = "AnotherSecureP@ssw0rd!"
    vm_size                       = "Standard_D8ds_v4"
    max_session_limit             = 4
    enable_monitoring             = true
    enable_scaling_plans          = true
    enable_cost_alerts            = true
    tags = {
      owner       = "prod-team"
      cost_center = "AVD01"
    }
  2. Use Terraform workspaces or run Terraform in separate directories to maintain independent state files for each environment:

    terraform init -upgrade
    terraform workspace new dev
    terraform workspace new prod
    terraform workspace select dev
    terraform apply -var-file=dev.tfvars
    terraform workspace select prod
    terraform apply -var-file=prod.tfvars
  3. Review and adjust variable values such as VM sizes, number of hosts (session_host_count), network ranges and tags to suit each environment's requirements.

Best practices

The following recommendations are drawn from the Azure Cloud Adoption Framework and the AVD documentation:

  • Plan your capacity and region placement. The resource organisation guidance warns that deploying more than 5,000 VMs in a single region can create performance bottlenecks; organisations with large deployments should use multiple subscriptions and regions.

  • Keep AVD resources in a single region. Host pools, workspaces, session hosts and their network should live in the same Azure region to minimise latency. Avoid mixing session hosts from different regions within a host pool.

  • Separate service objects from compute. The Cloud Adoption Framework recommends placing AVD service objects (host pools, application groups, workspaces) in a dedicated resource group and the session host VMs in a separate resource group. This configuration simplifies lifecycle management and role assignments. In this example code, a single resource group is used for simplicity; consider splitting the configuration into modules if your organisation requires stricter separation.

  • Adopt a consistent naming and tagging strategy. Azure recommends defining naming conventions early; names should include business and operational details, such as workload, environment and region. Tags support cost management, automation and documentation.

  • Use role‑based access control (RBAC). Assign the Desktop Virtualization User role on the application group and the Virtual Machine User Login role on the session host resource group to grant users access. The ARM‑based template uses the same roles; this Terraform configuration applies them using the object IDs supplied via security_principal_object_ids.

  • Rotate registration tokens regularly. The AVD host pool registration token expires after two hours in this configuration. If you wish to keep the token valid indefinitely, set type = "Permanent" and expiration_date far in the future. Keep the token secret—Terraform stores it in state.

  • Use remote state and apply locks. When deploying to shared environments (such as production), store your Terraform state in Azure Storage and enable state locking to avoid concurrent modifications. For example, configure the backend as:

    terraform {
      backend "azurerm" {
        resource_group_name  = "tfstate-rg"
        storage_account_name = "tfstateacct"
        container_name       = "tfstate"
        key                  = "avd-${var.environment}.tfstate"
      }
    }
  • Enable monitoring for all environments. Use the monitoring features to gain operational insights and optimize costs.

  • Use scaling plans for pooled deployments. Enable automatic scaling for pooled desktop and RemoteApp deployments to reduce costs by 40-70%.

  • Set up cost alerts for production. Configure cost thresholds and alerts to prevent budget overruns.

Differences from the ARM template

The original ARM template created a single session host and nested deployments for the network, control plane and session hosts. This Terraform configuration:

  • Uses native Terraform resources to create the virtual network, subnet and NSG. The NSG is intentionally empty to match the ARM template's empty securityRules array.
  • Creates the host pool, application group and workspace with similar properties (pooled type, BreadthFirst load balancing and desktop preferred application group).
  • Generates registration information directly on the host pool and exposes the token via azurerm_virtual_desktop_host_pool_registration_info.avd.token. In the ARM template the token is retrieved via listRegistrationTokens; in Terraform it is available as an attribute and used by the Microsoft DSC extension for reliable AVD agent installation and registration.
  • Leverages count to create multiple NICs, VMs and extensions when session_host_count > 1. The ARM template deploys one VM; you can adjust session_host_count to any number your subscription quota allows.
  • Uses Microsoft's official DSC configuration approach for session host registration, following the same proven method used in Microsoft's ARM templates and documentation.
  • Adds comprehensive monitoring and scaling capabilities not present in the original ARM template.

Session Host Registration Approach

This configuration uses Microsoft's official DSC (Desired State Configuration) approach for registering session hosts with the host pool, following Microsoft's documented best practices:

DSC-Based Approach (Current Implementation):

resource "azurerm_virtual_machine_extension" "avd_dsc" {
  name                       = "Microsoft.Powershell.DSC"
  publisher                  = "Microsoft.Powershell"
  type                       = "DSC"
  type_handler_version       = "2.73"
  
  settings = <<-SETTINGS
    {
      "modulesUrl": "${var.configuration_zip_file}",
      "configurationFunction": "Configuration.ps1\\AddSessionHost",
      "properties": {
        "HostPoolName": "${azurerm_virtual_desktop_host_pool.avd.name}",
        "aadJoin": true
      }
    }
SETTINGS

  protected_settings = <<PROTECTED_SETTINGS
  {
    "properties": {
      "registrationInfoToken": "${local.registration_token}"
    }
  }
PROTECTED_SETTINGS
}

Benefits of DSC Approach:

  • Microsoft-supported method - Official recommended approach
  • Proven reliability - Used in Microsoft's own templates and documentation
  • Secure token handling - Registration token passed via protected settings
  • Automated configuration - Handles full AVD agent installation and registration
  • Azure AD join support - Built-in support for domain-less environments
  • Error resilience - Robust retry mechanisms for network issues

Testing the configuration

This configuration has been tested with Terraform 1.6 and version 4.38.1 of the Azurerm provider. It deploys successfully to an Azure subscription with permissions to create resource groups, networking, Azure Virtual Desktop resources and virtual machines. After deployment, you can verify the results by navigating to Azure Virtual Desktop → Host pools in the Azure portal; the session host should appear in the host pool's Session hosts blade.

Cleaning up

To remove all resources created by this configuration, run:

.\set-auth.ps1
terraform destroy -var-file=dev-pooled-desktop.tfvars

You will be prompted to confirm the destruction. Destroying the resources will remove the host pool, session hosts, network and resource group.

Important: If VMs are stopped (due to scaling plans or auto-shutdown), you may encounter extension deletion errors. To avoid this:

  1. Start VMs before destroy (recommended):

    .\set-auth.ps1
    az vm start --resource-group rg-avd-dev --name vm-avd-dev-01 --no-wait
    az vm start --resource-group rg-avd-dev --name vm-avd-dev-02 --no-wait
    Start-Sleep -Seconds 60  # Wait for VMs to reach running state
    terraform destroy -var-file=dev-pooled-desktop.tfvars
  2. Or delete the resource group directly (bypasses extension errors entirely):

    az group delete --name rg-avd-dev --yes --no-wait

    This automatically cleans up all resources including extensions.

See the deployment guide for detailed troubleshooting steps.

Key Variables

Variable Purpose Default Notes
deployment_type AVD deployment pattern "pooled_desktop" New: Determines naming suffix and configuration (pooled_desktop, personal_desktop, pooled_remoteapp, personal_remoteapp)
environment Environment identifier (dev/test/prod) "dev" Appended to all resource names following Microsoft standards
prefix Project/organization prefix "avd" Used in all resource names (vdpool-{prefix}-{environment}-{suffix})
session_host_count Number of session host VMs to deploy 1 Scales the entire VM infrastructure
security_principal_object_ids Azure AD object IDs for desktop access [] Required: Must be populated before deployment
admin_password Local admin password for session hosts - Required: Must meet Azure complexity requirements
published_applications Applications for RemoteApp deployments [] Required for RemoteApp: List of applications to publish
load_balancer_type Load balancing algorithm for pooled types "BreadthFirst" New: BreadthFirst or DepthFirst (ignored for personal types)
personal_desktop_assignment_type Assignment for personal desktops "Automatic" New: Automatic or Direct user assignment
registration_token_expiration_hours Hours until registration token expires 2 Longer for dev (8h), shorter for prod (1-2h)
vm_size Azure VM size for session hosts "Standard_D4ds_v4" Choose based on user workload requirements
max_session_limit Max concurrent sessions per host 2 Balance user experience vs. cost (automatically set to 1 for personal types)
enable_monitoring Enable Log Analytics monitoring false New: Enables comprehensive monitoring
enable_scaling_plans Enable automatic scaling false New: Cost optimization for pooled deployments
enable_cost_alerts Enable cost monitoring alerts false New: Budget tracking and notifications
enable_dashboards Enable custom dashboards false New: Operational insights dashboard
monitoring_retention_days Log Analytics retention period 30 New: Choose from 30, 60, 90, 120, 180, 365, 730 days
cost_alert_threshold Daily cost threshold for alerts 100 New: Set based on expected daily costs
dashboard_refresh_interval Dashboard refresh interval (minutes) 15 New: Choose from 5, 15, 30, 60 minutes

Terraform Outputs

New: Microsoft-Compliant Naming Information

The configuration now provides detailed naming information via the naming_convention output:

terraform output naming_convention

Example output:

{
  "app_group_pattern" = "vdag-avd-dev-desktop"
  "deployment_suffix" = "desktop"
  "follows_standards" = "Microsoft Cloud Adoption Framework"
  "host_pool_pattern" = "vdpool-avd-dev-desktop"
  "subnet_pattern" = "snet-avd-dev"
  "workspace_pattern" = "vdws-avd-dev"
}

Monitoring and Scaling Outputs

# Check monitoring configuration
terraform output monitoring_insights

# Get quick access links
terraform output quick_links

# Monitor specific resources
terraform output log_analytics_workspace_name
terraform output scaling_plan_name
terraform output dashboard_name

# Check scaling plan configuration details
terraform output scaling_plan_host_pool_association_id
terraform output scaling_plan_role_assignment_id

Other Key Outputs

Output Description Example Value
host_pool_name Microsoft-compliant host pool name vdpool-avd-dev-desktop
application_group_name Microsoft-compliant application group name vdag-avd-dev-desktop
workspace_name Microsoft-compliant workspace name vdws-avd-dev
deployment_config Complete configuration details for the deployment Configuration object with all settings
published_applications List of published apps (RemoteApp only) Array of application details
session_host_names Names of deployed session host VMs ["vm-avd-dev-01", "vm-avd-dev-02"]
scaling_plan_host_pool_association_id ID of the scaling plan-host pool association Resource ID string
scaling_plan_role_assignment_id ID of the scaling plan role assignment Resource ID string

Support and Documentation

For detailed deployment instructions, troubleshooting, and advanced configuration options, see:

Contributing

This configuration follows Microsoft best practices and Azure Cloud Adoption Framework guidelines. When contributing:

  1. Maintain Microsoft-compliant naming for all resources
  2. Follow the existing code structure and patterns
  3. Add comprehensive documentation for new features
  4. Test with multiple deployment types before submitting
  5. Update example configurations for new features

🏆 Enterprise-Ready: This configuration provides production-ready AVD deployments with comprehensive monitoring, scaling, and cost optimization capabilities while maintaining Microsoft Cloud Adoption Framework compliance.

About

Azure Virtual Desktop and Terraform. Everything you need in a single repo!

Resources

Stars

12 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors