Find VMs without the benefit
Azure Resource Graph (portal, no install)
Search the portal for "Resource Graph Explorer", paste this query and select "Run query". It lists every Windows VM in all the subscriptions you can read that isn't using Azure Hybrid Benefit.
resources
| where type =~ 'microsoft.compute/virtualmachines'
| where properties.storageProfile.osDisk.osType =~ 'Windows'
| extend licenseType = tostring(properties.licenseType)
| where licenseType !in ('Windows_Server', 'Windows_Client')
| project name, resourceGroup, subscriptionId, location,
size = tostring(properties.hardwareProfile.vmSize),
powerState = tostring(properties.extended.instanceView.powerState.code)
| order by subscriptionId asc, resourceGroup asc, name asc
Windows 10 and 11 VMs appear here too. They use the Windows_Client licence type, not Windows_Server, so leave them out. VMs in uniform scale sets don't appear; see scale sets.
Export them for the calculator (PowerShell)
This saves the running Windows VMs without the benefit, from every subscription you can see, as a CSV the calculator imports. It shows what switching them over would save and how many two-core licence packs you need.
$rows = foreach ($sub in Get-AzSubscription | Where-Object State -eq 'Enabled') {
Set-AzContext -Subscription $sub.Id | Out-Null
Get-AzVM -Status | Where-Object {
$_.StorageProfile.OsDisk.OsType -eq 'Windows' -and
$_.LicenseType -notin 'Windows_Server', 'Windows_Client' -and
$_.PowerState -eq 'VM running'
} | ForEach-Object {
[pscustomobject]@{
'NAME' = $_.Name
'SUBSCRIPTION' = $sub.Name
'RESOURCE GROUP' = $_.ResourceGroupName
'LOCATION' = $_.Location
'OPERATING SYSTEM' = 'Windows'
'STATUS' = 'Running'
'SIZE' = $_.HardwareProfile.VmSize
}
}
}
$rows | Export-Csv -Path .\vms-without-ahb.csv -NoTypeInformation
"$(@($rows).Count) VMs saved to vms-without-ahb.csv"
Needs the Az PowerShell module and Connect-AzAccount, or run it in Azure Cloud Shell. Then choose "Import portal CSV" on the calculator.
Before you switch it on
- No restart, no downtime
- Changing the licence type only changes a billing flag on the VM. It doesn't restart and service isn't interrupted.
- Savings start from the change
- You don't wait for a new billing period: the lower rate applies to usage after you save the change. Time before that isn't credited back.
- You need enough licences first
- Azure doesn't check. Turning the benefit on is your declaration that you have Windows Server licences with Software Assurance or a subscription to cover each VM: at least 8 cores per VM, bought in packs of 2. See eligibility.
- Permissions
- You need write access to the VM (
Microsoft.Compute/virtualMachines/write), for example the Virtual Machine Contributor or Contributor role. - Windows Server only
- This page covers the
Windows_Serverlicence type. Windows 10 and 11 useWindows_Client, SQL Server is set through the SQL IaaS Agent extension, and Red Hat and SUSE have their own licence types. - Dev/Test subscriptions
- Dev/Test subscriptions (Enterprise Dev/Test, Pay-As-You-Go Dev/Test and Azure Plan for DevTest) already bill Windows VMs at the Linux rate, so the benefit saves nothing there.
- Your own images
- VMs built from Marketplace images and from images you uploaded can both use the benefit. For your own images, set the licence type when you create the VM or change it afterwards as shown below.
Turn it on for one VM
Azure Portal
- Navigate to your Virtual Machine in the Azure Portal
- Select "Operating system" in the VM's menu
- Set "Azure Hybrid Benefit" to "Enable"
- If asked, confirm you have an eligible Windows Server licence with Software Assurance or a subscription
- Click "Save" to apply changes
PowerShell
$vm = Get-AzVM -ResourceGroupName "myResourceGroup" -Name "myVM"
$vm.LicenseType = "Windows_Server"
Update-AzVM -ResourceGroupName "myResourceGroup" -VM $vm
Replace "myResourceGroup" and "myVM" with your actual resource group and VM names.
Azure CLI
az vm update --resource-group myResourceGroup --name myVM --set licenseType=Windows_Server
Replace "myResourceGroup" and "myVM" with your actual resource group and VM names.
Turn it on for many VMs
PowerShell, with a dry run
Run it once as it is to list the VMs it would change. When the list is right, set $DryRun = $false and run it again.
$DryRun = $true
$ResourceGroup = 'myResourceGroup' # set to $null for every resource group in the subscription
$vms = if ($ResourceGroup) { Get-AzVM -ResourceGroupName $ResourceGroup } else { Get-AzVM }
$targets = $vms | Where-Object {
$_.StorageProfile.OsDisk.OsType -eq 'Windows' -and
$_.LicenseType -notin 'Windows_Server', 'Windows_Client'
}
foreach ($target in $targets) {
if ($DryRun) { "Would enable: $($target.ResourceGroupName)/$($target.Name)"; continue }
$vm = Get-AzVM -ResourceGroupName $target.ResourceGroupName -Name $target.Name
$vm.LicenseType = 'Windows_Server'
Update-AzVM -ResourceGroupName $vm.ResourceGroupName -VM $vm | Out-Null
"Enabled: $($vm.ResourceGroupName)/$($vm.Name)"
}
Works on the current subscription. Switch with Set-AzContext -Subscription "name or ID".
Azure CLI
List the VMs first and check the file, then update them all in one command.
az vm list --query "[?storageProfile.osDisk.osType=='Windows' && licenseType!='Windows_Server' && licenseType!='Windows_Client'].id" -o tsv > vms.txt
cat vms.txt
az vm update --ids $(cat vms.txt) --set licenseType=Windows_Server
Bash syntax, as used in Azure Cloud Shell. Add --resource-group myResourceGroup to the first command to limit it to one resource group. If vms.txt is empty there's nothing to change, so skip the last command.
Virtual machine scale sets
Setting the licence type on a scale set changes its model. Instances that already exist keep paying the Windows charge until they're brought up to date with that model.
- Uniform, automatic or rolling upgrade policy: instances are updated for you.
- Uniform, manual upgrade policy: you have to upgrade the instances yourself (the last command in each example below). Changing the licence type alone doesn't need a restart, but upgrading applies every pending change to the model. If something else is waiting, such as a new image, instances may restart, so check first.
- Flexible orchestration: the model only applies to new instances. Existing instances are ordinary VMs, so the scripts above find and update them.
Azure CLI
az vmss update --resource-group myResourceGroup --name myScaleSet --set virtualMachineProfile.licenseType=Windows_Server
az vmss update-instances --resource-group myResourceGroup --name myScaleSet --instance-ids "*"
PowerShell
$vmss = Get-AzVmss -ResourceGroupName "myResourceGroup" -VMScaleSetName "myScaleSet"
$vmss.VirtualMachineProfile.LicenseType = "Windows_Server"
Update-AzVmss -ResourceGroupName "myResourceGroup" -VMScaleSetName "myScaleSet" -VirtualMachineScaleSet $vmss
$ids = (Get-AzVmssVM -ResourceGroupName "myResourceGroup" -VMScaleSetName "myScaleSet").InstanceId
Update-AzVmssInstance -ResourceGroupName "myResourceGroup" -VMScaleSetName "myScaleSet" -InstanceId $ids
Check it worked
- Check VM properties in Azure Portal to confirm "Azure Hybrid Benefit" is enabled. From the command line, the VM's licence type should show as
Windows_Server. - For many VMs at once, add the "OS licensing benefit" column to the portal's Virtual machines list
- Review your Azure bill to verify reduced costs
- Monitor usage in Azure Cost Management
- Keep your own record of which licences are assigned to which Azure VMs
Azure does not check that you own enough licences. Turning the benefit on is your declaration that you do, so your licence records are what you'll rely on in an audit.
List every Windows VM and its licence type
az vm list --query "[?storageProfile.osDisk.osType=='Windows'].{Name:name, ResourceGroup:resourceGroup, LicenseType:licenseType}" -o table
A blank or None licence type means the VM is still paying the Windows charge. Running the Resource Graph query again should now return nothing, apart from any Windows 10 or 11 VMs.
Turn it off
If you move licences back on-premises or to other VMs, set the licence type back to None. The VM goes back to pay-as-you-go Windows pricing, again with no restart.
az vm update --resource-group myResourceGroup --name myVM --set licenseType=None
$vm = Get-AzVM -ResourceGroupName "myResourceGroup" -Name "myVM"
$vm.LicenseType = "None"
Update-AzVM -ResourceGroupName "myResourceGroup" -VM $vm
In the portal, open the VM's "Operating system" page, set Azure Hybrid Benefit to "Disable" and save.
Not sure it's worth it?
Import your VM list into the calculator to see what you'd save and when the licences pay for themselves. For large or complicated estates, consulting can help plan the rollout and check your licensing.