Learning Terraform > Deploying WVD

Learning Terraform Series
01. Deploying WVD [This Post]
02. Remote State
03. WVD-as-a-Module

I’ve heard Terraform mentioned numerous times in various tech circles over the past year but always chose to give it a wide birth, I knew it was the latest tool in the growing Infrastructure as Code space but as my own coding experience had never spanned outside of the Windows command line and PowerShell the idea of learning what I incorrectly assumed would be a wildly ARM like beast of a language conjured up memories of the time I accidently walked into the wrong lecture hall at Teesside University in the early 2000’s and sat through a mind-blowing and somewhat scaring lecture on C# when I should have been a few doors down learning the ins-and-outs of TCP/IP.

Anyway, cut to the modern day and the through dark art of YouTube algorithms I’m presented with a video by the highly respected John Savill on ‘Using Terraform with Azure’ which instantly dispels all my fears – Terraform was not the wildly ARM like beast I thought it was, in fact it was the opposite.

Sidebar: Around the same time I saw tweets from Neil McLoughlin and Jen Sheerin both sharing experiences with learning Terraform.  Neil recommended a great book which I went on to buy for myself (Terraform: Up & Running: Writing Infrastructure as Code by Yevgeniy Brikman) and Jen shared a great article detailing how she had used Terraform to deploy WVD, just as I went on to do, of which this post centres around so thanks to both.

So, what is Terraform and why is worth your time?

Actually, before delving into that let me just set the scene and explain the concept of Infrastructure as Code for those just starting their journey, as understanding this is key to understanding Terraform.

Since the dawn of modern IT there have been sysadmins deploying servers, storage and networks (commonly referred to as infrastructure in sysadmin parlance) in data centres around the world, this was often slow, expensive and prone to errors and configuration drift, that is, deploying 2 servers with the same application identically is pretty straight forward, however, multiply that by 2000 and you’re sure to end up with differing configurations and all the pain and sleepless nights that comes with it.

Spring forward in time and throw in the virtualisation revolution which rearchitected the servers, storage and networks we use to deploy as physical devices in cold data centres, abstracting their dependency on physical hardware and refactoring them to be purely “software-defined” thus opened the gates and spawning the concept of Infrastructure as Code, that is, being able to define and provision a full infrastructure architecture based purely on lines of code, and not only that, adding the ability to quickly and easily identify and remediate configuration drift.

So, looping back to the original question of what is Terraform?

Terraform is an open-source tool developed by HashiCorp that allows you to provision Infrastructure as Code, and it is very good at it.

Provisioning versus Configuration Management

A quick note on the subtle differences between provisioning and configuration management tools and why they work best when combined.

Terraform is a provisioning tool, it is used to provision the infrastructure such as the servers you would need to host an application, strictly speaking it does not deploy the application. I say strictly speaking as Terraform can deploy custom server images which contain pre-installed applications but that it just semantics.

Products like Chef, Puppet and Ansible are configuration management tools, they install and manage software on existing servers, they don’t provision the servers themselves.

So, easy to grasp why companies will often combine the a provisioning tool such as Terraform with a configuration management tool such as Chef, Puppet or Ansible to give them end to end control of the infrastructure and application stacks.

Terraform 101 – Deploying WVD

I wont delve any deeper into Terraform as a coding language in this post as to be honest I’m still very much a beginner and I recommend you grab the book I mentioned earlier as well as watching John’s video above, that said, as I get more proficient I will start sharing more tips and tricks but for now, what follows in this article should be seen as a 101, a Hello World for Terraform.

This below scripts will deploy a single WVD hostpool of the pooled variant, create and associate RemoteApp and Desktop application groups and finally create and associate a WVD Workspace.

What it won’t do as yet, and where I’m hoping to take this, is deploy WVD Session Hosts (ideally from a Shared Image Gallery) and manage user assignment.

Following Terraform standards there are two scripts, a main.tf which contains the Terraform code for the resources to be deployed and a variables.tf which contains all the referenced variables.

I’ve written this so that the main.tf should remain pretty much untouched and all values such as resource names are referenced from the variables.tf file.

Update: This code is also available on my GitHub, here.


Get AzureRM Terraforn Provider
 provider "azurerm" {
   version = "2.31.1" #Required for WVD
   features {}
 Create Resource Group - This will host all subsequent deployed resources
 resource "azurerm_resource_group" "default" {
   name     = var.rgname
   location = var.region
 Create "Pooled" WVD Host Pool
 resource "azurerm_virtual_desktop_host_pool" "pooleddepthfirst" {
   location            = var.region
   resource_group_name = azurerm_resource_group.default.name
 name                     = var.pooledhpname
   friendly_name            = var.pooledhpfriendlyname
   description              = var.pooledhpdescription
   type                     = "Pooled"
   maximum_sessions_allowed = 50
   load_balancer_type       = "DepthFirst"
 Create RemoteApp Application Group
 resource "azurerm_virtual_desktop_application_group" "pooledremoteapp" {
   name                = var.pooledhpremoteappname
   location            = var.region
   resource_group_name = azurerm_resource_group.default.name
 type          = "RemoteApp"
   host_pool_id  = azurerm_virtual_desktop_host_pool.pooleddepthfirst.id
   friendly_name = var.pooledhpremoteappfriendlyname
   description   = var.pooledhpremoteappdescription
 Create Desktop Application Group
 resource "azurerm_virtual_desktop_application_group" "pooleddesktopapp" {
   name                = var.pooledhpdesktopappname
   location            = var.region
   resource_group_name = azurerm_resource_group.default.name
 type          = "Desktop"
   host_pool_id  = azurerm_virtual_desktop_host_pool.pooleddepthfirst.id
   friendly_name = var.pooledhpdesktopappfriendlyname
   description   = var.pooledhpdesktopappdescription
 Create Workspace
 resource "azurerm_virtual_desktop_workspace" "workspace" {
   name                = var.workspace
   location            = var.region
   resource_group_name = azurerm_resource_group.default.name
 friendly_name = var.workspacefriendlyname
   description   = var.workspacedesc
 Associate RemoteApp Application Group with Workspace
 resource "azurerm_virtual_desktop_workspace_application_group_association" "workspaceremoteapp" {
   workspace_id         = azurerm_virtual_desktop_workspace.workspace.id
   application_group_id = azurerm_virtual_desktop_application_group.pooledremoteapp.id
 Associate Desktop Application Group with Workspace
 resource "azurerm_virtual_desktop_workspace_application_group_association" "workspacedesktop" {
   workspace_id         = azurerm_virtual_desktop_workspace.workspace.id
   application_group_id = azurerm_virtual_desktop_application_group.pooleddesktopapp.id


variable "rgname" {
  description = "Resource Group Name"
  default     = "VFF-WUS-RG-TFWVD"

variable "region" {
  description = "Region"
  default     = "West US 2"

variable "pooledhpname" {
  description = "Pooled Host Pool Name"
  default     = "VFF-WUS-TF-Pooled"

variable "pooledhpfriendlyname" {
  description = "Pooled Host Pool Friendly Name"
  default     = "VFF Pooled Host Pool"

variable "pooledhpdescription" {
  description = "Pooled Host Pool Description"
  default     = "VFF Pooled Host Pool"

variable "pooledhpremoteappname" {
  description = "Pooled Host Pool RemoteApp App Group Name"
  default     = "VFF-WUS-TF-Pooled-RA"

variable "pooledhpremoteappfriendlyname" {
  description = "Pooled Host Pool RemoteApp App Group Friendly Name"
  default     = "VFF Pooled Host Pool Remote Apps"

variable "pooledhpremoteappdescription" {
  description = "Pooled Host Pool RemoteApp App Group Description"
  default     = "VFF Pooled Host Pool Remote Apps"

variable "pooledhpdesktopappname" {
  description = "Pooled Host Pool Desktop App Group Friendly Name"
  default     = "VFF-WUS-TF-Pooled-DT"

variable "pooledhpdesktopappfriendlyname" {
  description = "Pooled Host Pool Desktop App Group Friendly Name"
  default     = "VFF Pooled Host Pool Remote Apps"

variable "pooledhpdesktopappdescription" {
  description = "Pooled Host Pool Desktop App Group Description"
  default     = "VFF Pooled Host Pool Remote Apps"

variable "workspace" {
  description = "WVD Workspace Name"
  default     = "VFF-Terraform-Workspace"

variable "workspacefriendlyname" {
  description = "WVD Workspace Friendly Name"
  default     = "VFF-Terraform-Workspace"

variable "workspacedesc" {
  description = "WVD Workspace Description"
  default     = "VFF-Terraform-Workspace"

If you’re intending to run this code yourself you’ll need to prepare your environment, again following the instructions in John’s video above, that is, download and copy the Terraform executable to your local device, install the AZ PowerShell module and connect to your Azure account.

I’d also recommend VSCode as a code editor if you’re not already using it.

Once all of this is in place you can run the below commands to initialise, plan and apply Terraform, then sit back and watch it go!

terraform fmt  #make my files formatted correctly and will fix all tf files in this folder

terraform init
terraform plan
terraform apply -auto-approve

What you will end up with should look like the below:

If you have any questions or queries please get in touch on Twitter


4 thoughts on “Learning Terraform > Deploying WVD”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s