How to create a Windows 10 VM in Azure with Terraform

I’m a strong believer in systems and infrastructure as code. But, I don’t feel strongly about which is the best cloud service. That is why I love Hashicorp’s Terraform product.
Terraform is an infrastructure automation tool that is cloud agnostic(usable with AWS, Azure, VMware, Open Stack,etc…) and uses simple configuration files to build and maintain servers, services, networks and more! Even the most basic Terraform configurations are highly useful for quickly building and destroying cloud resources for “on demand” type jobs.
My employer is in the process of migrating systems to Azure. Specifically I’m creating templates for clusters of Linux machines that run QA jobs. The jobs are spawned by a single Windows client. However setting up a Windows 10 VM is much harder than you would imagine considering Azure is a Microsoft cloud service! For example, Terraform doesn’t check for invalid hostnames or ‘user password’, values that are to short. Instead your Windows 10 VM will simply fail at the very end. If you enable boot logging you will get a black screen with OOBE error.
This tutorial assumes you have basic knowledge of,(and installed) Terraform. If you don’t please run through the Hashicorp tutorial before continuing. Additionally this article assumes you have a valid Azure account. You can sign up for a free trial in minutes, but requires a credit card. $200 of free credits the first 30 days!
Goals of this Post:
- Use Azure CLI to select a Windows 10 image
- Terraform configuration of Azure Resource Group
- Terraform configuration of Network & public IP Andress
- Terraform configuration of Windows 10 VM
Install Azure CLI for Linux
Lets start by logging into Azure. In order to launch Terraform in Azure you must install the Azure CLI. Execute ‘az login’ while a web browser is open. A tab will take you the Azure login. Once you login you can execute Terraform configurations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[matt@mattcom1 Desktop]$ az login Note, we have launched a browser for you to login. For old experience with device code, use "az login --use-device-code" [6957:7000:0203/142918.081852:ERROR:browser_gpu_channel_host_factory.cc(121)] Failed to launch GPU process. Created new window in existing browser session. You have logged in. Now let us find all the subscriptions to which you have access... [ { "cloudName": "AzureCloud", "id": "ee7914d8-4cf3-4941-86ef-00f027d66085", "isDefault": true, "name": "Free Trial", "state": "Enabled", "tenantId": "8d269bfd-9d06-4d84-96ac-7b00edcd0fcc", "user": { "name": "savelono@gmail.com", "type": "user" } } ] [matt@mattcom1 Desktop]$ |
Obtain a valid Windows image: Offer, SKU,Publisher & version
The toughest part is identifying a valid ‘Offer/Pub/SKU’ for Windows 10. the Microsoft store and Azure web portal do not seem to list the specific values we need to automate the builds.
The obvious thing to do is use the Azure CLI to find the values for the Offer, Publisher, and SKU for Windows 10. However using Microsoft as publisher shows no results for Windows 10, but list over 1280 other images!
1 2 3 4 5 6 7 |
[matt@mattcom1 az_windows10]$ az vm image list --all --output table --publisher Microsoft | wc -l 1230 [matt@mattcom1 az_windows10]$ |

Where is Windows 10? Searching ‘Microsoft’ as the publisher produces 100’s of results. Try,
‘MicrosoftWindowsDesktop’
After some Googling I managed to find the command that list their current Windows 10 offerings:
1 2 3 4 5 6 7 8 9 10 11 12 |
[matt@mattcom1 Desktop]$ az vm image list --all --output table --publisher MicrosoftWindowsDesktop Offer Publisher Sku Urn Version ---------- ----------------------- -------- -------------------------------------------------------- ------------ Windows-10 MicrosoftWindowsDesktop RS3-Pro MicrosoftWindowsDesktop:Windows-10:RS3-Pro:16299.904.65 16299.904.65 Windows-10 MicrosoftWindowsDesktop RS3-ProN MicrosoftWindowsDesktop:Windows-10:RS3-ProN:16299.904.65 16299.904.65 Windows-10 MicrosoftWindowsDesktop rs4-pro MicrosoftWindowsDesktop:Windows-10:rs4-pro:17134.523.65 17134.523.65 Windows-10 MicrosoftWindowsDesktop rs4-pron MicrosoftWindowsDesktop:Windows-10:rs4-pron:17134.523.65 17134.523.65 Windows-10 MicrosoftWindowsDesktop rs5-pro MicrosoftWindowsDesktop:Windows-10:rs5-pro:17763.253.65 17763.253.65 |
Pick the version of Windows you want. Add the information to your Terraform configuration file in the storage_image_reference { } of your Windows 10 VM Terraform configuration.
excerpt from az_windows10.tf:
storage_image_reference {
publisher = “MicrosoftWindowsDesktop”
offer = “Windows-10”
sku = “rs5-pro”
version = “17763.253.65”
}
Below is a complete working example for a Windows 10 configuration in Azure! If you run into trouble reference my system below. Good luck! Oh, and if you are not sure what to do next remember to run through that Terraform tutorial!
az_windows10.tf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
#====================================== # PROVIDER #===================================== provider "azurerm" { subscription_id ="ef9914d8-4cf3-1221-86ef-00f027d66085" } #====================================== # Azure RESOURCE GRPS #====================================== resource "azurerm_resource_group" "savelonocomRG" { name = "savelonocomRG" location = "West US" tags = { CreatedBy = "Matt", Purpose = "testing" } } #===================================== # NETWORK #===================================== resource "azurerm_virtual_network" "lononet" { name = "testnet" resource_group_name = "${azurerm_resource_group.savelonocomRG.name}" location = "West US" address_space = ["10.1.10.0/24"] } #--- Subnet ---- resource "azurerm_subnet" "internal" { name = "lonosubnet" resource_group_name = "${azurerm_resource_group.savelonocomRG.name}" virtual_network_name = "${azurerm_virtual_network.lononet.name}" address_prefix = "10.1.10.0/24" } #--- Public IP Address --- resource "azurerm_public_ip" "WinPublicIP" { name = "WinPublicIP" location = "West US" resource_group_name = "${azurerm_resource_group.savelonocomRG.name}" allocation_method = "Static" } #--- NIC resource "azurerm_network_interface" "WindowsNIC" { name = "interface0" location = "${azurerm_resource_group.savelonocomRG.location}" resource_group_name = "${azurerm_resource_group.savelonocomRG.name}" ip_configuration { name = "QADHCP" subnet_id = "${azurerm_subnet.internal.id}" private_ip_address_allocation = "Dynamic" public_ip_address_id = "${azurerm_public_ip.WinPublicIP.id}" } } #================================= # NODES #================================= ## Windows reference system ## resource "azurerm_virtual_machine" "win10autoclient" { name = "Win10" location = "West US" resource_group_name = "${azurerm_resource_group.savelonocomRG.name}" network_interface_ids = ["${azurerm_network_interface.WindowsNIC.id}"] vm_size = "Standard_B1ms" delete_os_disk_on_termination = "True" #--- Base OS Image --- storage_image_reference { publisher = "MicrosoftWindowsDesktop" offer = "Windows-10" sku = "rs5-pro" version = "17763.253.65" } #--- Disk Storage Type storage_os_disk { name = "disk1" caching = "ReadWrite" create_option = "FromImage" managed_disk_type = "Standard_LRS" os_type = "Windows" } #--- Define password + hostname --- os_profile { computer_name = "Windows10" admin_username = "matt" admin_password = "Password2019" } #--- os_profile_windows_config { enable_automatic_upgrades = true provision_vm_agent = true } #-- Windows VM Diagnostics boot_diagnostics { enabled = true storage_uri = "https://terrafomwinlogs.blob.core.windows.net/" } #--- VM Tags tags { CreatedBy = "Matt", Purpose = "Windows Automation Client" } #--- Post Install Provisioning --- } |
No Comments »
RSS feed for comments on this post. TrackBack URL