Stop the Guesswork: How to Find Azure VM SKUs That Actually Work
One of the common frustrations in managing Azure resources is encountering errors when provisioning virtual machines (VMs) due to unavailable SKUs. Azure’s console might redirect you to a page that supposedly helps resolve the issue by using the Azure CLI to query SKUs in your region. However, the results can be overwhelming and misleading, as they include SKUs that may not be accessible to your subscription. This lack of clarity can lead to wasted time and frustration, especially when you are working on a tight deadline or trying to scale your infrastructure.
When you run into this error the console will route you to a page that tries to help you use the CLI to lookup SKUs in your region. Unfortunately, this query returns all SKUs in region even the ones you don’t have access to.
After encountering this issue myself, I decided to dive deeper into the Azure CLI documentation to find a better solution. My investigation led me to the az vm list-skus command, which allows users to query VM SKUs in a specified region. At first glance, this command appeared promising, but the default output still included SKUs restricted for my subscription or region. This was not the precise and actionable information I needed. Fortunately, Azure CLI provides a parameter called –query, which leverages JMESPath to filter and refine command outputs.
If you are unfamiliar with JMESPath, it is a JSON querying language designed to filter and manipulate JSON-like data structures. The official JMESPath website even offers an interactive sandbox that lets you experiment with queries on sample JSON data. To begin, I copied some sample output from the az vm list-skus command and pasted it into the JMESPath experiment tool. This allowed me to quickly iterate and refine my query syntax, testing filters until I achieved the desired results.
The Azure CLI documentation has a link to the official JMESPath website. This is actually a pretty useful site as it has an experimentation pag right on the homepage.
Plug in this data as this will give you a sample of what comes back when you execute az vm list-skus. I removed the value of the capabilities block for brevity. If you run the az vm list-skus command with output set to json you should be able to produce a larger list to help you experiment with your JMESPath queries.
[
{
"apiVersions": null,
"capabilities": [],
"capacity": null,
"costs": null,
"family": "StandardNVADSA10v5Family",
"kind": null,
"locationInfo": [
{
"location": "WestUS3",
"zoneDetails": [
{
"Name": [
"3",
"2",
"1"
],
"capabilities": [
{
"name": "UltraSSDAvailable",
"value": "True"
}
],
"name": null
}
],
"zones": [
"3",
"2",
"1"
]
}
],
"locations": [
"WestUS3"
],
"name": "Standard_NV36adms_A10_v5",
"resourceType": "virtualMachines",
"restrictions": [],
"size": "NV36adms_A10_v5",
"tier": "Standard"
},
{
"apiVersions": null,
"capabilities": [],
"capacity": null,
"costs": null,
"family": "StandardNVADSA10v5Family",
"kind": null,
"locationInfo": [
{
"location": "WestUS3",
"zoneDetails": [
{
"Name": [
"3",
"2",
"1"
],
"capabilities": [
{
"name": "UltraSSDAvailable",
"value": "True"
}
],
"name": null
}
],
"zones": [
"3",
"2",
"1"
]
}
],
"locations": [
"WestUS3"
],
"name": "Standard_NV36ads_A10_v5",
"resourceType": "virtualMachines",
"restrictions": [],
"size": "NV36ads_A10_v5",
"tier": "Standard"
}
]
The breakthrough came from an article by Neil Peterson, where he demonstrated using JMESPath filters with another Azure CLI command, az container list. His filtering example:
az container list --query "[?contains(name, 'mycontainer2')]" --output table
While his example wasn’t directly applicable to my issue, it sparked an idea: I could craft a JMESPath query to exclude restricted SKUs from my results. After a bit of experimentation, I discovered the right syntax. I ultimately settled on this command:
az vm list-skus --location westus3 \
--query '[?resourceType==`virtualMachines` && restrictions == `[]`]' \
--output table
This query does two key things: it filters the results to include only VM SKUs with a resourceType of virtualMachines, and it excludes any SKUs with restrictions. The final output is concise, actionable, and includes only the SKUs available to my subscription in the specified region. For example, the command returns results like these:
ResourceType Name Tier Size Family
--------------- ------------------------- -------- ---------------- --------------------------------
virtualMachines Standard_D11_v2_Promo Standard D11_v2_Promo standardDv2PromoFamily
virtualMachines Standard_D12_v2_Promo Standard D12_v2_Promo standardDv2PromoFamily
virtualMachines Standard_M12ds_v3 Standard M12ds_v3 standardMDSMediumMemoryv3Family
virtualMachines Standard_NV72ads_A10_v5 Standard NV72ads_A10_v5 StandardNVADSA10v5Family
This clean output lets you quickly identify which VM sizes are available for deployment, saving you the hassle of trial and error or sifting through irrelevant data.
Using this approach not only resolves the immediate problem but also demonstrates the power of JMESPath filters for any Azure CLI command. By filtering and tailoring outputs to your needs, you can significantly streamline your Azure management workflows. If you’re new to JMESPath, I highly recommend experimenting with its capabilities — it’s a game changer for anyone working with JSON data.
In conclusion, while Azure’s default tools for querying VM SKUs can be overly broad and unhelpful, combining az vm list-skus with JMESPath queries empowers you to cut through the noise and focus on actionable results. Whether you’re deploying new resources, scaling existing ones, or troubleshooting provisioning issues, this method ensures you’ll spend less time fumbling with unavailable options and more time building the solutions you need.