A PowerShell 7 script that reports Azure VM SKU availability, zone restrictions, and family quota for a given subscription and region. It is built for capacity investigations — quickly answering "can I deploy this VM size here, and if not, why?"
For every virtualMachines SKU offered in the target region, the script combines two
Azure data sources:
Get-AzComputeResourceSku— which zones a SKU is offered in and any subscription restrictions (region-level or zone-level).Get-AzVMUsage— the current usage and limit (quota) for each VM family.
It then produces, per SKU, a clear verdict (Available / Partial / Unavailable),
the usable vs. offered zones, the reason for any restriction, and the family quota.
- PowerShell 7.0+ (enforced via
#Requires -Version 7.0). - The Az PowerShell module (
Az.Accounts,Az.Compute). - An authenticated Azure session (
Connect-AzAccount) with read access to the target subscription.
| Parameter | Description |
|---|---|
-SubscriptionId |
Subscription to analyse, by id. Mutually exclusive with -SubscriptionName. |
-SubscriptionName |
Subscription to analyse, by display name. Mutually exclusive with -SubscriptionId. |
-Region |
Azure region/location to analyse (e.g. westeurope). Required. |
-Family |
Optional VM SKU family filter. Supports wildcards (e.g. standardDSv3Family, *Dsv5*). |
-ListFamilies |
Lists the distinct SKU family ids in the region (with an example SKU each) and exits. Honours -Family. |
Exactly one of -SubscriptionId / -SubscriptionName must be supplied.
Analyse a whole region by subscription id:
.\get-capacity.ps1 -SubscriptionId <guid> -Region westeuropeAnalyse by subscription display name:
.\get-capacity.ps1 -SubscriptionName "My Subscription" -Region westeuropeDiscover the family names available in a region (to find the value for -Family):
.\get-capacity.ps1 -SubscriptionId <guid> -Region westeurope -ListFamiliesLimit the analysis to one family (wildcards supported):
.\get-capacity.ps1 -SubscriptionId <guid> -Region westeurope -Family *Dsv5*Family hints:
Dv5isstandardDv5Family,Dsv5isstandardDSv5Family. Use-ListFamiliesif unsure of the exact id.
The on-screen table is a compact view with these columns:
| Column | Meaning |
|---|---|
Family |
The VM SKU family id. |
SKU |
The VM size (sorted numerically within a family, e.g. D2 before D16). |
Quota |
used/limit (remaining left) for the family in the region. |
Availability |
Available, Partial (some zones usable), or Unavailable. |
Zones |
Usable vs. offered zones, e.g. 1 usable (offered: 1,2,3) or none usable (offered: 2). |
Detail |
A concise reason for any restriction (region block, restricted zones, reason codes, etc.). |
Two distinct zone sets are involved and the output keeps them separate:
- Offered zones come from the SKU's
LocationInfo— the zones where Azure offers the SKU in that region. - Restricted zones come from the subscription restriction (
RestrictionInfo.Zones) — a subscription-wide list that may include zones the SKU isn't even offered in.
A SKU is Unavailable when the region is blocked outright, or when every offered zone
is restricted (even if other restricted zones aren't relevant). 0/0 (0 left) quota
means the family has no quota assigned.
The script emits rich PSCustomObjects; the table only shows a subset. Capture the
output for the complete breakdown (including SupportedZones, AvailableZones,
RestrictedZones, RestrictedRegions, QuotaAssigned, QuotaUsed, QuotaRemaining):
$report = .\get-capacity.ps1 -SubscriptionId <guid> -Region westeurope
$report | Export-Csv capacity.csv -NoTypeInformation
$report | Format-List # per-SKU detail- The script sets
Set-StrictMode -Version Latestand$ErrorActionPreference = 'Stop', so it fails fast on the first error (e.g. an invalid subscription or region). - Quota matching uses an O(1) hashtable keyed on the family id rather than a per-SKU scan of the usage list.
ForEach-Object -Parallelwas evaluated but intentionally not used: the per-SKU work is microsecond-level in-memory string handling, so runtime is dominated by the two Azure REST calls, not the loop.