Windows 10 Image Series – Part 3.1 – Deploy test VM

In this series I am going to show you how build a Windows 10 Image via Azure Pipelines and DevOps without 3rd party tooling, welcome to part 3.1!

This is a blog which describes how you can deploy a VM from your newly created Shared Image Gallery Image via Bicep.

Prerequisites

Part 1, 2 & 3 of this series needs to be completed. These are the links:

1. Windows 10 Image Series – Part 1 (Creating the Windows VM Pipeline)

2. Windows 10 Image Series – Part 2 (Artifacts & Application Installation)

3. Windows 10 Image Series – Part 3 (Shared Image Gallery)

Therefore, the prerequisites from part 1 are also required for this part. So:

Firstly, I am assuming that you have knowledge of Azure DevOps. These are the parts that already need be setup:

In addition, you need the Azure CLI module to run the Bicep template as the example. You can download it here.

Furthermore, I would advise you to use Powershell 7, link.

Lastly, you will need the bicep module, link.

Checkout/Skip to other parts:

0. Windows 10 Image Series – Part 0 (Preparing Azure/Azure DevOps)

1. Windows 10 Image Series – Part 1 (Creating the Windows VM Pipeline)

2. Windows 10 Image Series – Part 2 (Artifacts & Application Installation)

3. Windows 10 Image Series – Part 3 (Shared Image Gallery)

4. Windows 10 Image Series – Part 4 (SessionHost Deployment from Image)

5. Windows 10 Image Series – Part 5 (Convert the Image Build pipeline to YAML)

6. Windows 10 Image Series – Part 6 (Deploy Sessionhosts with Bicep and YAML)

Creating a test VM from the Shared Image Gallery

Firstly, you need to save this code as a .Bicep file:

//General Parameters
param location string = 'Westeurope'
param virtualMachineName string = 'Windows-TestVM'
param osDiskType string = 'Premium_LRS'
param virtualMachineSize string = 'Standard_B4ms'
param adminUsername string = 'TestVMAdmin'
//Gallery Parameters
param galleryResourceGroup string = 'RG_WE_SharedImageGallery'
param galleryName string = 'WVDImageGallery'
param galleryImageDefinitionName string = 'Windows10WVDImage'
//Virtual Network Parameters
param vnetResourceGroup string = ''
param vnetName string = ''
param subnetName string = ''

@secure()
param adminPassword string
param patchMode string = 'manual'
param enableHotpatching bool = false

var imageReference = resourceId(galleryResourceGroup,'Microsoft.Compute/galleries/images/versions', '${galleryName}', '${galleryImageDefinitionName}','latest')
var subnetId = resourceId(vnetResourceGroup,'Microsoft.Network/virtualNetworks/subnets','${vnetName}','${subnetName}')
var virtualMachineComputerName = virtualMachineName
var NicName = '${virtualMachineName}-NIC'


resource NIC_Resource 'Microsoft.Network/networkInterfaces@2018-10-01' = {
  name: NicName
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: subnetId
          }
          privateIPAllocationMethod: 'Dynamic'
        }
      }
    ]
  }
  dependsOn: []
}

resource VM_Resource 'Microsoft.Compute/virtualMachines@2021-03-01' = {
  name: virtualMachineName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: virtualMachineSize
    }
    storageProfile: {
      osDisk: {
        createOption: 'FromImage'
        managedDisk: {
          storageAccountType: osDiskType
        }
      }
      imageReference: {
        id: imageReference
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: NIC_Resource.id
        }
      ]
    }
    osProfile: {
      computerName: virtualMachineComputerName
      adminUsername: adminUsername
      adminPassword: adminPassword
      windowsConfiguration: {
        enableAutomaticUpdates: false
        provisionVMAgent: true
        patchSettings: {
          enableHotpatching: enableHotpatching
          patchMode: patchMode
        }
      }
    }
    licenseType: 'Windows_Client'
  }
  dependsOn: [
    NIC_Resource
  ]
}

After that, you have the option to add the following parameters as default values:

Windows 10 Image Series – Part 3.1 - Networking Default values bicep

I set default values for my testing environment. You can also add these parameters at deployment. I will show this in the example.

After that, you need to log to Azure CLI. Use this command:

az login

Optional: If you have multiple subscriptions please select your subscription in Azure CLI with the following command:

az account set --subscription subscription-id

Create a resource group to deploy your test VM in:

az group create --location location --name resourcegroupname

Lastly, deploy the bicep template to create the VM.

az deployment group create `
    --resource-group resource-group-name `
    --template-file path-to-template `
    --parameters parameters

Example deployment

I have logged and select my appropriate subscription and I now show you the process of creating the resource group and deploying the bicep template.

Firstly, create the resource group:

Windows 10 Image Series – Part 3.1 - Deploy Resource Group

After that, deploy the bicep template:

As a result, the Azure Portal states that the bicep template is being deployed:

Optional: If you want to set the network parameters when running the bicep template. Please use the following example:

az deployment group create `
    --resource-group resource-group-name `
    --template-file path-to-template `
    --parameters adminPassword='Password' vnetResourceGroup='ResourceGroupName' vnetName='VNETNAME' subnetName='SUBNETNAME'

And that concludes Windows 10 Image Series – Part 3.1. Please check out the other parts also:

0. Windows 10 Image Series – Part 0 (Preparing Azure/Azure DevOps)

1. Windows 10 Image Series – Part 1 (Creating the Windows VM Pipeline)

2. Windows 10 Image Series – Part 2 (Artifacts & Application Installation)

3. Windows 10 Image Series – Part 3 (Shared Image Gallery)

4. Windows 10 Image Series – Part 4 (SessionHost Deployment from Image)

5. Windows 10 Image Series – Part 5 (Convert the Image Build pipeline to YAML)

6. Windows 10 Image Series – Part 6 (Deploy Sessionhosts with Bicep and YAML)