In the previous blog post we look at creating the Personal Desktop (1×1 mapping) and Pooled Desktop (1 x Many) using Terraform Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Personal Desktop (Part 1) | AskAresh and Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Pooled Desktop (Part 2). In this blog post series I am going to demonstrate how to create the AVD Host Pool, Application Group and Workspace using Terraform for Pooled Remote App aka Published Applications (1xMany)
We are going to create the following three types of configurations using Terraform:
- Azure Virtual Desktop – Personal Desktop (1×1) – Part 1
- Azure Virtual Desktop – Pooled Desktop (Multi-Session Full Desktop Experience) – Part 2
- Azure Virtual Desktop – Remote App (Multi-Session Application aka Published Apps) – Part 3
Note – We are creating the Pooled RemoteApp in this post and in the subsequent post the other types were. In this post In this post I will not show case the creation of service principal and secret please refer for the Part 1 for that activity.

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 – Authenticating via Service Principal & Client Secret
Before running any Terraform code the following powershell (Make sure run as administrator) we will execute and store the credentials as enviornment variables. If we do this via the environment variable we dont have to store the below information within the providers.tf file. In the future blog post there are better way to store 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 Subcription ID – Azure Portal Subcription 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 ADD you will have the details
Terraform Folder Structure
The following is the folder structure for the terrraform code:

Azure Virtual Desktop Pooled RemoteApp – Create a directory in which the below Terraform code will be published (providers.tf, main.tf, variables.tf and output.tf)
+---Config-AVD-Pooled-RemoteApp
| | main.tf
| | output.tf
| | providers.tf
| | variables.tf
Configure AVD – Pooled RemoteApp – Providers.tf
Create a file named providers.tf and insert the following code:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.49.0"
}
azuread = {
source = "hashicorp/azuread"
}
}
}
provider "azurerm" {
features {}
}
Configure AVD – Pooled RemoteApp – main.tf
Create a file named main.tf and insert the following code. Let me explain what all we are attempting to accomplish here:
- Create a Resource Group
- Create a Workspace
- Create a Host Pool
- Create a Remote Application Group (RAG)
- Associate Workspace and RAG
- Assign Azure AD Group to the Desktop Application Group (RAG)
- 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 = "Pooled" #[Pooled or Personal]
preferred_app_group_type = "RailApplications" #[Desktop or RailApplications]
maximum_sessions_allowed = 5 #[Tweak based on your vm tshirt size]
load_balancer_type = "DepthFirst" #[BreadthFirst or DepthFirst]
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 RAG
resource "azurerm_virtual_desktop_application_group" "rag" {
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 = "RemoteApp"
name = var.app_group_name
friendly_name = "RemoteApp AppGroup"
description = "${var.prefix} AVD RemoteApp 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.rag.id
workspace_id = azurerm_virtual_desktop_workspace.workspace.id
}
# Assign AAD Group to the Remote Application Group (RAG)
resource "azurerm_role_assignment" "AVDGroupRemoteAppAssignment" {
scope = azurerm_virtual_desktop_application_group.rag.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
}
Note – The individual applications are not published yet. They can be published once you have the session host created. After which, using Terraform, the individual applications can be published too. The exe path of apps needs to be mapped within the operating system. I plan to create a separate blog post on session host creation via Terraform.
Configure AVD – Pooled RemoteApp – variables.tf
Create a file named variables.tf and insert the following code:
variable "resource_group_location" {
default = "australiaeast"
description = "Location of the resource group - Australia East"
}
variable "rg_name" {
type = string
default = "AE-DEV-AVD-01-PO-A-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-PO-A-HP"
}
variable "app_group_name" {
description = "Name of the Azure Virtual Desktop application group"
type = string
default = "AE-DEV-AVD-01-RAG"
}
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 HostPools"
}
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 – Pooled RemoteApp – output.tf
Create a file named output.tf and insert the following code. This will showcase in the console what is getting deployed in form of a 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.rag.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 – Pooled RemoteApp
Run terraform init to initialize the Terraform deployment. This command downloads the Azure provider required to manage your Azure resources. (Its pulling the AzureRM and AzureAD)
terraform init -upgrade

Create Terraform Execution Plan – AVD – Pooled RemoteApp
Run terraform plan to create an execution plan.
terraform plan -out mainavdremoteapp.tfplan


Apply Terraform Execution Plan – AVD – Pooled RemoteApp
Run terraform apply to apply the execution plan to your cloud infrastructure.
terraform apply mainavdremoteapp.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 mainavdremoteapp.destroy.tfplan

Run terraform apply to apply the execution plan.
terraform apply mainavdremoteapp.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 – Pooled Remote App. Please let me know if I have missed any steps or details, and I will be happy to update the post.
Thanks,
Aresh Sarkari
One Response to “Azure Virtual Desktop – Terraform – Create a Host Pool, Desktop Application Group and Workspace for Pooled Remote App aka Published Applications (Part 3)”