In the past, I have written blog posts on creating the Azure Virtual Desktop (AVD) solution using PowerShell. In this blog post series, I will demonstrate how to create the AVD Host Pool, Application Group and Workspace using Terraform. Terraform is an open-source infrastructure as code (IaC) software tool that enables you to safely and predictably create, change, and improve infrastructure. Terraform can be used to manage infrastructure on various cloud providers, including Azure.
We are going to create the following three types of configurations using Terraform:
- Azure Virtual Desktop – Personal Desktop (1×1)
- Azure Virtual Desktop – Pooled Desktop (Multi-Session Full Desktop Experience)
- Azure Virtual Desktop – Remote App (Multi-Session Application aka Published Apps)
Note – We are creating the Personal Desktop in this post, and the other desktop/app types will be created in the subsequent post. In this post, I will showcase the creation of service principal and secret. In the next part, we shall move straight onto the Terraform code. Referring to part 1 in the series will be essential if you are doing the basics.

- Pre-requisites
- Terraform Service Principal and Secret (Azure AD – App Registrations)
- Terraform – Authenticating via Service Principal & Client Secret
- Terraform Folder Structure
- Configure AVD – Personal Desktop Pool – Providers.tf
- Configure AVD – Personal Desktop Pool – main.tf
- Configure AVD – Personal Desktop Pool – variables.tf
- Configure AVD – Personal Desktop Pool – output.tf
- Intialize Terraform – AVD – Personal Desktop Pool
- Create Terraform Execution Plan – AVD – Personal Desktop Pool
- Apply Terraform Execution Plan – AVD – Personal Desktop Pool
- Validate the Output in Azure Portal
- Clean-up the above resources (Optional)
- Quick Start Links
Pre-requisites
Following are the pre-requisites before you begin
- An Azure subscription
- The Terraform CLI
- The Azure CLI
- Permissions within the Azure Subscription for using Terraform

Terraform Service Principal and Secret (Azure AD – App Registrations)
Let’s pre-create the application ID and client secret we will use to connect and leverage the Terraform code in VScode.
- Connect to Azure Portal and go to Azure Active Directory
- Click on App Registrations and select – New Registration
- Give the App a Name – Terraform

- You will get two important information created for later use within Terraform
- Application ID
- Tenant ID

- Now let’s grant this App Terraform Permission. Click on Add a permission and select MS Graph and search for AppRoleAssignment.ReadWrite.All and select read/write permissions and Add Permissions
- Select Grant admin consent for domain

- We are using client secret so now lets enable that. Click on Certificates & Secrets – Client Secrets and select New client secret\
- Give it a name (Terra-secret) and expiry date (12 months)
- Copy the Secret Value

Terraform – Authenticating via Service Principal & Client Secret
In the above step, we created the Service Principal and Client secret. We will use it before running any Terraform code in PowerShell (Ensure to run as administrator). We will execute and store the credentials as environment variables. If we do this via the environment variable, we don’t have to store the below information within the providers.tf file. In a future blog post, there are better ways to keep the below details, and I hope to showcase them:
# PowerShell
$env:ARM_CLIENT_ID = "9e453b62-0000-0000-0000-00000006e1ac"
$env:ARM_CLIENT_SECRET = "Z318Q~00000000000000000000000000000000_"
$env:ARM_TENANT_ID = "a02e602c-0000-000-0000-0e0000008bba61"
$env:ARM_SUBSCRIPTION_ID = "7b051460-00000-00000-00000-000000ecb1"
- Azure Subscription ID – Azure Portal Subscription copy the ID.
- Client ID – From the above step, you will have the details
- Client Secret – From the above step, you will have the details
- Tenant ID – While creating the Enterprise Apps in Azure AD, you will have the details
Terraform Folder Structure
The following is the folder structure for the Terraform code:

Azure Virtual Desktop Personal Pool – Create a directory in which the below Terraform code will be published (providers.tf, main.tf, variables.tf and output.tf)
+---Config-AVD-Personal-Desktop
| | main.tf
| | output.tf
| | providers.tf
| | variables.tf
Note – I am not demonstrating how to install Terraform as it’s dead simple, and the information is available everywhere.
Configure AVD – Personal Desktop Pool – Providers.tf
Create a file named providers.tf and insert the following code. (We are using the AzureRM and AzureAD providers)
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.49.0"
}
azuread = {
source = "hashicorp/azuread"
}
}
}
provider "azurerm" {
features {}
}
Configure AVD – Personal Desktop Pool – main.tf
Create a file named main.tf and insert the following code. Let me explain what we are attempting to accomplish here: (Note I have # commented the lines with additional info)
- Create a Resource Group
- Create a Workspace
- Create a Host Pool
- Create a Desktop Application Group (DAG)
- Associate Workspace and DAG
- Assign Azure AD Group to the Desktop Application Group (DAG)
- Assign Azure AD Group to the Resource Group for RBAC for the Session Host (Virtual Machine User Login)
# Resource group name is output when execution plan is applied.
resource "azurerm_resource_group" "rg" {
name = var.rg_name
location = var.resource_group_location
tags = var.tags
}
# Create AVD workspace
resource "azurerm_virtual_desktop_workspace" "workspace" {
name = var.workspace
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
friendly_name = "${var.prefix} Workspace"
description = "${var.prefix} Workspace"
tags = var.tags
}
# Create AVD host pool
resource "azurerm_virtual_desktop_host_pool" "hostpool" {
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
name = var.hostpool
friendly_name = var.hostpool
validate_environment = true #[true false]
start_vm_on_connect = true
custom_rdp_properties = "targetisaadjoined:i:1;drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;enablerdsaadauth:i:1;"
description = "${var.prefix} HostPool"
type = "Personal" #[Pooled or Personal]
personal_desktop_assignment_type = "Automatic"
load_balancer_type = "Persistent"
tags = var.tags
scheduled_agent_updates {
enabled = true
timezone = "AUS Eastern Standard Time" # Update this value with your desired timezone
schedule {
day_of_week = "Saturday"
hour_of_day = 1 #[1 here means 1:00 am]
}
}
}
resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationinfo" {
hostpool_id = azurerm_virtual_desktop_host_pool.hostpool.id
expiration_date = var.rfc3339
}
# Create AVD DAG
resource "azurerm_virtual_desktop_application_group" "dag" {
resource_group_name = azurerm_resource_group.rg.name
host_pool_id = azurerm_virtual_desktop_host_pool.hostpool.id
location = azurerm_resource_group.rg.location
type = "Desktop"
name = var.app_group_name
friendly_name = "Desktop AppGroup"
description = "${var.prefix} AVD application group"
depends_on = [azurerm_virtual_desktop_host_pool.hostpool, azurerm_virtual_desktop_workspace.workspace]
tags = var.tags
}
# Associate Workspace and DAG
resource "azurerm_virtual_desktop_workspace_application_group_association" "ws-dag" {
application_group_id = azurerm_virtual_desktop_application_group.dag.id
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
}
# Assign AAD Group to the Desktop Application Group (DAG)
resource "azurerm_role_assignment" "AVDGroupDesktopAssignment" {
scope = azurerm_virtual_desktop_application_group.dag.id
role_definition_name = "Desktop Virtualization User"
principal_id = data.azuread_group.AVDGroup.object_id
}
# Assign AAD Group to the Resource Group for RBAC for the Session Host
resource "azurerm_role_assignment" "RBACAssignment" {
scope = azurerm_resource_group.rg.id
role_definition_name = "Virtual Machine User Login"
principal_id = data.azuread_group.AVDGroup.object_id
}
Configure AVD – Personal Desktop Pool – variables.tf
Create a file named variables.tf and insert the following code. I have followed a naming convention that includes the following:
- AE – Australia East
- Environment – PROD or DEV
- Instance – 01
- RG – Resource Group
- WS – Workspace
- DAG – Desktop Application Group
variable "resource_group_location" {
default = "australiaeast"
description = "Location of the resource group - Australia East"
}
variable "rg_name" {
type = string
default = "AE-DEV-AVD-01-RG"
description = "Name of the Resource group in which to deploy service objects"
}
variable "workspace" {
type = string
description = "Name of the Azure Virtual Desktop workspace"
default = "AE-DEV-AVD-01-WS"
}
variable "hostpool" {
type = string
description = "Name of the Azure Virtual Desktop host pool"
default = "AE-DEV-AVD-01-PE-D-HP"
}
variable "app_group_name" {
description = "Name of the Azure Virtual Desktop application group"
type = string
default = "AE-DEV-AVD-01-DAG"
}
variable "rfc3339" {
type = string
default = "2023-05-20T12:43:13Z" #Update this value with a future date
description = "Registration token expiration"
}
variable "prefix" {
type = string
default = "AE-DEV-AVD-01-HP-"
description = "Prefix of the name of the AVD machine(s)"
}
variable "tags" {
type = map(string)
default = {
Environment = "Dev"
Department = "IT"
Location = "AustraliaEast"
ServiceClass = "DEV"
Workload = "Host Pool 01"
}
}
data "azuread_client_config" "AzureAD" {}
data "azuread_group" "AVDGroup" {
display_name = "Win365-Users"
}
Configure AVD – Personal Desktop Pool – output.tf
Create a file named output.tf and insert the following code. This will showcase in the console what is getting deployed as output.
output "azure_virtual_desktop_compute_resource_group" {
description = "Name of the Resource group in which to deploy session host"
value = azurerm_resource_group.rg.name
}
output "azure_virtual_desktop_host_pool" {
description = "Name of the Azure Virtual Desktop host pool"
value = azurerm_virtual_desktop_host_pool.hostpool.name
}
output "azurerm_virtual_desktop_application_group" {
description = "Name of the Azure Virtual Desktop DAG"
value = azurerm_virtual_desktop_application_group.dag.name
}
output "azurerm_virtual_desktop_workspace" {
description = "Name of the Azure Virtual Desktop workspace"
value = azurerm_virtual_desktop_workspace.workspace.name
}
output "location" {
description = "The Azure region"
value = azurerm_resource_group.rg.location
}
data "azuread_group" "aad_group" {
display_name = "Win365-Users"
}
output "AVD_user_groupname" {
description = "Azure Active Directory Group for AVD users"
value = data.azuread_group.aad_group.display_name
}
Intialize Terraform – AVD – Personal Desktop Pool
Run the following command to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources.
terraform init -upgrade

Create Terraform Execution Plan – AVD – Personal Desktop Pool
Run the following command to create an execution plan.
terraform plan -out mainavdpersonal.tfplan


Apply Terraform Execution Plan – AVD – Personal Desktop Pool
Run the following command to apply the execution plan to your cloud infrastructure.
terraform apply mainavdpersonal.tfplan

Validate the Output in Azure Portal
Go to the Azure portal, Select Azure Virtual Desktop and Select Host pools, Application Group and Workspace created using Terraform.



Clean-up the above resources (Optional)
If you want to delete all the above resources then you can use the following commands to destroy. Run terraform plan and specify the destroy flag.
terraform plan -destroy -out mainavdpersonal.destroy.tfplan

Run terraform apply to apply the execution plan.(Destroy)
terraform apply mainavdpersonal.destroy.tfplan

Quick Start Links
The intention here is to get you quickly started with Terraform on Azure Virtual Desktop Solution:
Description | Links |
Setting up your computer to get started with Terrafor using Powershell | Install Terraform on Windows with Azure PowerShell |
AVD Configure Azure Virtual Desktop | https://learn.microsoft.com/en-us/azure/developer/terraform/configure-azure-virtual-desktop |
Terraform Learning | https://youtube.com/playlist?list=PLLc2nQDXYMHowSZ4Lkq2jnZ0gsJL3ArAw |
I hope you will find this helpful information for getting started with Terraform to deploy the Azure Virtual Desktop – Personal Desktop Pool. Please let me know if I have missed any steps or details, and I will be happy to update the post.
Thanks,
Aresh Sarkari
4 Responses to “Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Personal Desktop (Part 1)”