When Azure says “no” to +1000 vCPUs, QuotaGrabber says “sure, how about +50… and +50… and +50…”
An interactive script that incrementally requests Azure VM-family quota
increases in small chunks. Built for cases where Azure rejects single large
jumps (e.g. +1000 vCPUs) and someone has been chunking the requests by hand
through the portal.
Two equivalent implementations are provided — pick your favorite:
| Implementation | Best for | |
|---|---|---|
| 🟦 | PowerShell — Invoke-QuotaGrabber.ps1 |
Windows, no runtime beyond az |
| 🐍 | Python — quota_grabber.py |
Cross-platform, Python 3.8+, no pip installs |
Same prompts. Same API calls. Same behavior. Same progress bar. 💯
Subscription ▸ Production - Contoso (xxxxxxxx-....)
Region ▸ East US (eastus)
VM family ▸ Standard DSv3 Family (current 100/100)
Target ▸ 600
Chunk ▸ 50 every 5 min → ~10 requests
Plan: 100 -> 600 in steps of 50 every 5 min, ~10 requests. Proceed? [y/N] y
[########################................] 60% start=100 current=400 target=600 step#6 chunk=50
Press Ctrl+C any time to stop. The last printed current value is the live limit at that moment.
flowchart TD
A([Start]) --> B[Pick subscription]
B --> C[Pick region]
C --> D[Pick VM family<br/>shows live current/limit]
D --> E[Enter target + chunk + interval]
E --> F{Confirm plan?}
F -- no --> Z([Abort — nothing sent])
F -- yes --> G[PUT quota += chunk]
G --> H[Poll quotaRequest<br/>until terminal state]
H --> I[Canonical GET<br/>read live limit]
I --> J{current >= target?}
J -- no --> K[Sleep interval] --> G
J -- yes --> Y([Done ✅])
H -.->|Failed: ContactSupport| X([Stop — open support ticket])
- Azure CLI (
az) onPATH— verify withaz --version - Logged in (
az login) — both scripts will log you in if needed - Permissions to submit quota requests (Contributor or Quota Request Operator)
- PowerShell 5.1+ / 7+ or Python 3.8+
PowerShell
cd C:\temp\internal\QuotaGrabber
./Invoke-QuotaGrabber.ps1Python
# Windows
cd C:\temp\internal\QuotaGrabber
python .\quota_grabber.py# macOS / Linux
cd /path/to/QuotaGrabber
python3 ./quota_grabber.py- Subscription – pick from every subscription
azcan see. Type a number, or any substring to filter (name or ID). - Region – physical Azure regions only (no logical/edge). Filter by display name (
East US) or short name (eastus). - VM family – calls
az vm list-usagefor the region and shows only entries ending inFamily. Each row shows(current X/Y)so you see live usage and live limit while selecting. Filter by display name or family code. - Target NEW quota limit – must be greater than the current limit.
- Chunk size per request – default 50. Each iteration asks Azure to raise the limit by this many units (capped at the target).
- Minutes between requests – default 5.
- Confirmation – plan summary +
y/N. Anything buty/yesaborts before any request is sent.
- PUT
…/Microsoft.Quota/quotas/{familyCode}?api-version=2023-02-01with body{ properties: { limit: { limitObjectType: LimitValue, value: N }, name: { value: familyCode }, resourceType: standard } }. - Read the quotaRequest id from the
202response and pollMicrosoft.Quota/quotaRequests/{id}untilprovisioningStatereachesSucceeded/Failed/Canceled(or 5-min timeout). - Re-read the canonical
Microsoft.Quota/quotas/{family}GET (with brief retry to clear eventual-consistency flicker) as the source of truth. - Update the progress bar.
- Sleep the interval, then repeat until
current >= targetor Ctrl+C.
Failed+ContactSupport→ the script stops immediately. Azure's self-service path rejected the request; further attempts just rack up identical rejections. Open a Microsoft Support ticket (Quota → Compute).Failed(other reason) → continues, but trusts the post-step canonical read. If the limit didn't advance you get a red WARNING and a shortened sleep before retry.- Async poll timeout (rare) → keeps going; the next canonical read decides.
- Always trusts the live
az vm list-usagereading after each request. - A non-zero exit from a single
az restcall is logged, not fatal — many quota workflows return informational output while queued. - The target ceiling is honored: the last chunk is trimmed so we never overshoot.
- Starting, current, and target limits are all printed at the end for a clean record.
| Provider | Microsoft.Quota |
| Api-version | 2023-02-01 |
| Resource name | VM-family code from az vm list-usage |
Examples: standardDSv3Family, standardNCADSA100v4Family, standardEv5Family.
Family codes are taken verbatim from the name.value field so you don't need to hand-translate display names.
-
If Azure rejects 1000-unit jumps but accepts smaller ones, start with chunk 50 / interval 5 min. If several go through cleanly, re-run with chunk 100 to halve wall-clock time.
-
For families that go to manual review, 15–30 min intervals reduce duplicate pending tickets. The script is safe to Ctrl+C and resume — re-running picks up the new live limit and continues.
-
Want a full log?
# PowerShell Start-Transcript C:\temp\internal\QuotaGrabber\run-$(Get-Date -f yyyyMMdd-HHmm).log ./Invoke-QuotaGrabber.ps1 Stop-Transcript
# Python python .\quota_grabber.py *>&1 | Tee-Object -FilePath ".\run-$(Get-Date -f yyyyMMdd-HHmm).log"
| Symptom | Likely cause / fix |
|---|---|
az login prompt appears |
Expected on first run if you weren't logged in. |
| "No VM-family quotas returned" | Region typo or no quota visible — check az vm list-usage -l <region>. |
AuthorizationFailed from az rest |
Caller lacks quota permission on the subscription. |
| Limit not advancing | Request is in manual review — script keeps polling until Ctrl+C; check the portal "Quota requests" view. |
| Family doesn't appear | Run az vm list-usage -l <region> -o table and confirm the family is returned for that region. |
Built for real-world Azure quota grinding. 🪣 Safe to interrupt · Safe to resume · No overshoot