Getting started
This page takes you from zero to a rendered capacity dashboard.
Prerequisites
| Requirement | Notes |
|---|---|
| PowerShell 5.1+ or PowerShell 7+ | The toolkit targets the Windows PowerShell 5.1 floor; PS7 works too. |
Azure CLI (az) |
Logged in to the target tenant. Device-code login works fine for guest access. |
resource-graph az extension |
Used by AKS / footprint scans. Auto-installed on first use. |
| Reader role on the target subscriptions | Enough for everything below except the two exceptions in the next table. |
Access requirements
| Capability | Minimum role | Notes |
|---|---|---|
| SKU restriction / zonal enablement scan | Reader | Microsoft.Compute/skus is a subscription-level read |
| Zone (logical→physical) mapping | Reader | per-subscription locations read |
| Quota / usage | Reader | az vm list-usage |
| AKS inventory (Resource Graph) | Reader | needs the resource-graph az extension (auto-installed) |
| Capacity reservation inventory | Reader | ARM read of Microsoft.Compute/capacityReservationGroups; shared groups need Reader on the owning scope |
| AKS scale-headroom check | Reader | joins Resource Graph (node pools) + Microsoft.Compute/skus + az vm list-usage — all subscription reads |
| Network quota (regional usages) | Reader | Microsoft.Network/locations/{loc}/usages (via az network list-usages) |
| App Service quota (regional + per-plan usages) | Reader | Resource Graph (plans) + Microsoft.Web/locations/{loc}/usages + Microsoft.Web/serverfarms/{name}/usages |
| Storage quota (account count + disk inventory) | Reader | az storage account show-usage + (optional) Resource Graph disk sum |
| PaaS quota (Azure SQL + Cosmos DB) | Reader | Microsoft.Sql/locations/{loc}/usages + servers/{name}/usages; Cosmos databaseAccounts + (optional) SQL-API throughput reads |
| Subscription / RG structural limits | Reader | Resource Graph counts + az tag list + (optional) az deployment sub list / az role assignment list, all compared to documented Learn constants |
| Activity-log error scan | Reader | for watching reconciles / allocation errors |
| Region footprint / multi-region compare | Reader | Resource Graph + per-region skus read |
| Quota group (shared pool) read | Management-group Reader | subscription Reader is not enough |
| Spot placement score (allocation-likelihood signal) | Compute Recommendations Role + Reader | read-only API (placementScores/generate/action — no mutations); Reader alone is not enough |
| Quota group provisioning (opt-in write) | GroupQuota Request Operator (MG) + Quota Request Operator / Contributor (subs) | only for Deploy-QuotaGroups.ps1; see the quota-groups guide |
| SKU / regional enablement changes | Not covered | requires an Azure support request to the capacity team |
kubectl / node / pod inspection |
Cluster User / Admin | Reader cannot pull cluster credentials |
This toolkit is read-only by default. The analysis scripts never mutate a resource — every write is a local file under
output/. The one exception is the opt-inDeploy-QuotaGroups.ps1rollout tool, which provisions quota groups and requires the elevated roles above; it supports-WhatIfand is never invoked by the scans or dashboard. The enablement-request generator only drafts the support ticket text; filing it is a manual step.
Install
Clone or download the repository, then run scripts from the repo root:
git clone <repo-url> capacity-toolkit
cd capacity-toolkit
No build step — these are plain PowerShell scripts that dot-source scripts/Common.ps1.
Step 1 — Sign in
az login --tenant <TENANT_ID>
# Confirm you're in the right place:
az account show --query "{tenant:tenantId, user:user.name}" -o table
Step 2 — Discover what’s actually in use (recommended)
Instead of guessing which SKUs to check, discover what’s actually deployed. This writes a
capacity-config.json (location, SKUs, families, subscriptions) that the rest of the toolkit
consumes.
# Omit -SubscriptionCsv to scan every subscription you can see.
.\scripts\Get-UsedSkus.ps1 -Location norwayeast [-SubscriptionCsv .\output\my-subs.csv]
Optional sub-list CSV format (Name is just a label):
Name,SubId
Prod-Sub-01,00000000-0000-0000-0000-000000000001
Test-Sub-01,00000000-0000-0000-0000-000000000002
Step 3 — Run the combined report + dashboard
# Uses the discovered SKUs / families / subscriptions:
.\scripts\New-CapacityReport.ps1 -ConfigPath .\output\capacity-config.json `
-SecondaryRegion swedencentral `
-IncludeAks -IncludeZonal -IncludeCatalogue -IncludeInventory -IncludeQuotaGroups `
-Dashboard -EnablementRequest
Or specify everything explicitly (defaults to a B/D/E sample if you pass neither config nor SKUs):
.\scripts\New-CapacityReport.ps1 -Location norwayeast `
-SubscriptionCsv .\output\my-subs.csv `
-IncludeAks -IncludeInventory -IncludeQuotaGroups -Dashboard -EnablementRequest `
-SecondaryRegion swedencentral -EvaluateRegions swedencentral,westeurope
Step 4 — Open the dashboard
Open output\capacity-dashboard-<date>.html in any browser. It is self-contained (all styling
inlined) and works offline. See the Dashboard guide for how to read each tab.
What you get in output/
| File | When | Contents |
|---|---|---|
combined-capacity-report-<region>-<date>.csv |
always | one row per subscription, all signals joined |
combined-capacity-report-<region>-<date>.md |
always | paste-ready executive summary + per-sub table |
capacity-dashboard-<date>.html |
-Dashboard |
self-contained visual dashboard |
enablement-request-<region>-<date>.md |
-EnablementRequest |
drafted support ticket |
resource-inventory-<date>.csv |
-IncludeInventory |
complete resource overview |
quota-groups-… / quota-group-members-… / quota-group-plan-… |
-IncludeQuotaGroups |
existing pools + modelled pooled design |
region-footprint-… / region-sku-comparison-… / region-quota-comparison-… |
-EvaluateRegions |
multi-region comparison |
sku-enablement-…, zone-mappings-…, quota-usage-…, aks-inventory-… |
as scanned | the individual scan CSVs |
Config file (
capacity-config.json). Produced byGet-UsedSkus.ps1, consumed byNew-CapacityReport.ps1 -ConfigPath. Hand-edit freely — explicit-Skus/-Families/-SubscriptionIdsparameters always override the file. It is not limited to B/D/E; discovery fills it from VMs, VM Scale Sets and AKS node pools, so it adapts to any tenant’s footprint.
Next: read the Concepts so the numbers mean what you think they mean — especially quota ≠ capacity.