Build Custom Images Azure Image Builder

Azure Image Builder is a new service that’s now in public preview. With it you can build custom images for your Azure environment and in particular Windows Virtual Desktop. This post wills how you how to build your own custom images starting with enabling Azure Image Builder.

Enable Azure Image Builder

First, because its in public preview you need to register the features.

Register-AzProviderFeature -ProviderNamespace Microsoft.VirtualMachineImages -FeatureName VirtualMachineTemplatePreview

Register-AzResourceProvider -ProviderNamespace Microsoft.VirtualMachineImages
Register-AzResourceProvider -ProviderNamespace Microsoft.Storage

Run at least the first two, Storage should already be registered. But you can check all three by running these commands.

Get-AzProviderFeature -ProviderNamespace Microsoft.VirtualMachineImages -FeatureName VirtualMachineTemplatePreview

Get-AzResourceProvider -ProviderNamespace Microsoft.VirtualMachineImages | Select-Object RegistrationState
Get-AzResourceProvider -ProviderNamespace Microsoft.Storage | Select-Object RegistrationState

It will take about ten minutes to register. However, you also need the Azure Active Directory registered application Azure Virtual Machine Image Builder. You don’t have to do anything else to get this, but it will take at least 4+ hours before it shows up.

Custom Images Azure Image Builder

In both subscriptions I have enabled Azure Image Builder in it took 4 or more hours before this registered application was available. And the Application ID is always the same.

Assigning IAM and Managed Identity

While you’re waiting on the Azure Virtual Machine Image Builder to show up, you need to create a Managed Identity. In May Microsoft changed the way the APIs work. Where you used to be able to use this service with a service principle, they now require a Managed Identity. You can read more about it here. I’ll also be copying over the relevant powershell to create the identity.

To create the Managed Identity:

## Add AZ PS module to support AzUserAssignedIdentity
Install-Module -Name Az.ManagedServiceIdentity

# create identity
New-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $idenityName

$timeInt=$(get-date -UFormat "%s")
$imageRoleDefName="Azure Image Builder Image Def"+$timeInt

# get the user-identity properties
$idenityNameResourceId=$(Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $idenityName).Id
$idenityNamePrincipalId=$(Get-AzUserAssignedIdentity -ResourceGroupName $imageResourceGroup -Name $idenityName).PrincipalId

# assign permissions for identity to distribute images
This command will download and update the template with the parameters specified earlier.
$aibRoleImageCreationPath = "aibRoleImageCreation.json"

# download config
Invoke-WebRequest -Uri $aibRoleImageCreationUrl -OutFile $aibRoleImageCreationPath -UseBasicParsing

# update role definition template
((Get-Content -path $aibRoleImageCreationPath -Raw) -replace '<subscriptionID>',$subscriptionID) | Set-Content -Path $aibRoleImageCreationPath
((Get-Content -path $aibRoleImageCreationPath -Raw) -replace '<rgName>', $imageResourceGroup) | Set-Content -Path $aibRoleImageCreationPath

## randomize the role definition name to make it unique for this example
((Get-Content -path $aibRoleImageCreationPath -Raw) -replace 'Azure Image Builder Service Image Creation Role', $imageRoleDefName) | Set-Content -Path $aibRoleImageCreationPath

# create role definition
New-AzRoleDefinition -InputFile  ./aibRoleImageCreation.json

# grant role definition to image builder service principal
New-AzRoleAssignment -ObjectId $idenityNamePrincipalId -RoleDefinitionName $imageRoleDefName -Scope "/subscriptions/$subscriptionID/resourceGroups/$imageResourceGroup"

You may have to manually update the template to replace with your Subscription ID and Resource Group, I found the powershell didn’t always work.

You’ll need to confirm that the AIBIdentity has been added to your Resource Group. In case you can’t get the powershell working, basically it needs contributor rights to the Resource Group.

Finally, your AIBIdentity account needs to be a member of the Storage Blob Data Reader group. You can do this with PowerShell of course. However, I want to show this in the Azure Portal. The only way I have found to find this role is to go to your Subscription -> IAM -> Add Role Assignment. It doesn’t show up if you’re in the Resource Group of if you go to the Managed Identity itself to add a role assignment.

Once you have the Azure Virtual Machine Image Builder registered application, you can run the below powershell against any resource groups where you’ll be distributing your image. As I mentioned above the Application ID is always the same, so the only portion you need to change from this code is your Resource Group.

New-AzRoleAssignment -RoleDefinitionName "Contributor" -ApplicationId "cf32a0cc-373c-47c9-9156-0db11f6a6dfc" -ResourceGroupName "MVP_ImageBuilder"

ARM Template

Again, because Azure Image Builder is in preview, everything has to be done through ARM Templates, powershell or azure CLI. If you’re reading this and you found an ARM template from before May 26th, you will need to add this snip to it. This adds the AIB identity we created in the previous step.

   "identity": {
        "type": "UserAssigned",
                "userAssignedIdentities": {
                "<imgBuilderId>": {}

Full ARM example here


To deploy our Image Definition we’ll use New-AzResourceGroupDeployment

New-AzResourceGroupDeployment -ResourceGroupName MVP_ImageBuilder -TemplateFile .\aib.json -OutVariable output

Running this does not actually create the definition, it creates an Azure Resource object that contains the template on how to build the image.

You’ll need that object name to run the image definition to create the image and to check on its status.

$Build = $output.outputs["imageTemplateName"].Value

To create our image we’ll use Invoke-AzResourceAction

Invoke-AzResourceAction -ResourceGroupName MVP_ImageBuilder -ResourceType Microsoft.VirtualMachineImages/imageTemplates -ResourceName $build -Action Run

To get the status we can run Get-AzResource

(Get-AzResource -ResourceGroupName MVP_ImageBuilder -ResourceType Microsoft.VirtualMachineImages/imageTemplates -Name $Build).Properties.lastRunStatus

If your build fails for some reason, and when you start doing custom software installs, it likely will. You can add message to the end of the last command.

(Get-AzResource -ResourceGroupName MVP_ImageBuilder -ResourceType Microsoft.VirtualMachineImages/imageTemplates -Name $build).Properties.lastRunStatus.message

You can also check the Azure Activity log for errors. In once instance I was getting a very weird error that the Resource did not exist, which was confusing to say the least. Once I checked the activity logs for the Image Template resource and build, the Azure Image Builder process uses Key Vault and in our clients subscription the Key Vault provider had not been registered. Once I registered it the process worked after that.

As you keep checking the status, once you get to distributing you are home free. You’ll find your image in your Resource Group and it will now show up under My Images in the Azure Portal when deploying a new VM. This is a nice new way to build custom images with Azure Image Builder and deploy them with WVD or whatever you ruse case may be.

Thanks to Roel Everink for putting out posts and templates.

About the Author Billy York

Hi, I’m Billy York. I’m a Cloud and Datacenter Management MVP, specializing in monitoring and automation. I'm the director of managed solutions and automation for Wintellisys

1 comment

Comments are closed