Deploy-BulkBudgets.ps1
Deploy cost budgets to all subscriptions in a management group with per-subscription tag-based amount configuration.
Overview
This PowerShell script uses Azure Resource Graph to discover all subscriptions in a management group, then deploys a Microsoft.Consumption/budgets resource to each. Each subscription can carry a different budget amount via its BudgetAmount tag, so a single bulk run respects per-subscription spending limits without manual intervention.
Key capabilities
- Management group targeting: Discover and deploy to all subscriptions in a hierarchy
- Tag-based amounts: Reads
BudgetAmounttag from each subscription for per-subscription limits - What-if mode: Preview deployment scope without making changes
- Force mode: Skip confirmation for automation and CI/CD pipelines
- Quiet mode: Suppress output for cleaner pipeline logs
When to use this script
- Applying cost governance across a management group at once
- Onboarding a new management group to budget monitoring
- Refreshing budgets after fiscal year changes
- Environments with 10+ subscriptions requiring consistent budget coverage
Prerequisites
# Install Azure PowerShell modules
Install-Module -Name Az -Force -AllowClobber
Install-Module -Name Az.ResourceGraph -Force -AllowClobber
# Authenticate to Azure
Connect-AzAccount
# Verify management group access
Get-AzManagementGroup | Select-Object Name, DisplayName
Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
| ManagementGroup | String | Management group to query for subscriptions | Required |
| ContactEmails | String[] | Email addresses for notifications | Required |
| Amount | Decimal | Budget amount (overrides all subscription tags) | Per-sub tag or $10 |
| BudgetName | String | Name of the budget resource | SubscriptionBudget |
| TimeGrain | String | Reset period: Monthly, Quarterly, or Annually | Monthly |
| StartDate | String | Budget start date (YYYY-MM-DD) | 1st of next month |
| EndDate | String | Budget end date (YYYY-MM-DD) | 1 year from start |
| ContactRoles | String[] | Azure roles to notify | Owner, Contributor |
| FirstThreshold | Int | First notification threshold % | 50 |
| SecondThreshold | Int | Second notification threshold % | 75 |
| ThirdThreshold | Int | Third notification threshold % | 90 |
| ForecastedThreshold | Int | Forecasted cost threshold % | 100 |
| Force | Switch | Skip confirmation prompt | False |
| Quiet | Switch | Suppress verbose output | False |
| WhatIf | Switch | Preview without deploying | False |
Usage examples
Deploy to all subscriptions in a management group
.\Deploy-BulkBudgets.ps1 `
-ManagementGroup "ALZ" `
-ContactEmails "admin@company.com"
Override amount for all subscriptions
.\Deploy-BulkBudgets.ps1 `
-ManagementGroup "ALZ" `
-ContactEmails "admin@company.com" `
-Amount 5000
What-if preview
.\Deploy-BulkBudgets.ps1 `
-ManagementGroup "Production" `
-ContactEmails "finops@company.com" `
-WhatIf
Automated deployment
.\Deploy-BulkBudgets.ps1 `
-ManagementGroup "ALZ" `
-ContactEmails "finops@company.com","alerts@company.com" `
-Force -Quiet
Production management group with custom thresholds
.\Deploy-BulkBudgets.ps1 `
-ManagementGroup "Production" `
-ContactEmails "finops@company.com","alerts@company.com" `
-FirstThreshold 70 `
-SecondThreshold 85 `
-ThirdThreshold 95 `
-ForecastedThreshold 100
Tag-based amount configuration
Set the BudgetAmount tag on individual subscriptions before running bulk deployment to control per-subscription limits:
# Tag a dev subscription with a low budget
Update-AzTag `
-ResourceId "/subscriptions/<dev-sub-id>" `
-Tag @{BudgetAmount = "50"} `
-Operation Merge
# Tag a production subscription with a higher budget
Update-AzTag `
-ResourceId "/subscriptions/<prod-sub-id>" `
-Tag @{BudgetAmount = "10000"} `
-Operation Merge
When -Amount is provided at the command line, it overrides all subscription tags.
Deployment process
- Management group query: Uses Resource Graph to discover all enabled subscriptions
- Confirmation prompt: Shows subscription count and asks for confirmation (unless
-Force) - Sequential deployment: Deploys to each subscription with progress output
- Summary report: Shows success and failure counts at completion
Troubleshooting
Management group not found
# List available management groups
Get-AzManagementGroup | Format-Table Name, DisplayName
# Verify exact name (case-sensitive)
Get-AzManagementGroup -GroupName "YOUR-MG-NAME"
Resource Graph module missing
Install-Module -Name Az.ResourceGraph -Force -AllowClobber
No subscriptions found
# Test the Resource Graph query directly
Search-AzGraph `
-Query "resourcecontainers | where type == 'microsoft.resources/subscriptions'" `
-ManagementGroup "YOUR-MG"
Authentication errors
Clear-AzContext -Force
Connect-AzAccount -Tenant 'your-tenant-id'
Script source
Related scripts
- Deploy-Budget.ps1 - Single subscription budget deployment
- Deploy-BulkALZ.ps1 - Bulk anomaly alert deployment pattern