Deploy-Budget.ps1
Deploy a cost budget to a single Azure subscription with tag-based amount configuration and configurable notification thresholds.
Overview
This PowerShell script deploys a Microsoft.Consumption/budgets resource to an Azure subscription. Budget amounts can be set via explicit parameter or read from a BudgetAmount subscription tag, letting different subscriptions carry different spending limits without modifying the script.
Key capabilities
- Tag-based amounts: Reads
BudgetAmounttag from the subscription to set per-subscription limits - Interactive selection: Prompts for subscription when no ID is provided
- Threshold configuration: Configures actual and forecasted notification thresholds
- What-if mode: Preview deployment without making changes
- Force mode: Skip confirmation for automation scenarios
When to use this script
- Deploying a budget to a single subscription
- Testing budget configuration before bulk deployment
- Onboarding a new subscription to cost governance
- CI/CD pipeline integration for subscription-level budgets
Budget amount priority
The script resolves the budget amount in this order:
-Amountparameter — explicit value takes precedenceBudgetAmountsubscription tag — tag-based per-subscription configuration- Default — falls back to $10/month
Prerequisites
# Install Azure PowerShell module
Install-Module -Name Az -Repository PSGallery -Force
# Authenticate to Azure
Connect-AzAccount
# Verify subscription access
Get-AzSubscription | Select-Object Name, Id, State
Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
| SubscriptionId | String | Target subscription GUID | Interactive selection |
| ContactEmails | String[] | Email addresses for notifications | Required |
| Amount | Decimal | Budget amount (overrides tag) | 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
Interactive subscription selection
.\Deploy-Budget.ps1 -ContactEmails "admin@company.com"
Specific subscription
.\Deploy-Budget.ps1 `
-SubscriptionId "12345678-1234-1234-1234-123456789012" `
-ContactEmails "admin@company.com"
Override budget amount
.\Deploy-Budget.ps1 `
-SubscriptionId "12345678-1234-1234-1234-123456789012" `
-ContactEmails "finops@company.com" `
-Amount 5000
What-if preview
.\Deploy-Budget.ps1 `
-ContactEmails "admin@company.com" `
-WhatIf
Automated deployment (no prompts)
.\Deploy-Budget.ps1 `
-SubscriptionId "12345678-1234-1234-1234-123456789012" `
-ContactEmails "admin@company.com" `
-Force -Quiet
Setting the BudgetAmount tag
Set the BudgetAmount tag on a subscription to control its per-subscription limit without changing script parameters:
# PowerShell
Update-AzTag -ResourceId "/subscriptions/<subscription-id>" `
-Tag @{BudgetAmount = "500"} `
-Operation Merge
# Azure CLI
az tag update \
--resource-id "/subscriptions/<subscription-id>" \
--operation merge \
--tags BudgetAmount=500
Notification thresholds
By default, notifications are sent at these percentages of the configured budget amount:
| Threshold | Type | Default |
|---|---|---|
| First | Actual | 50% |
| Second | Actual | 75% |
| Third | Actual | 90% |
| Forecasted | Forecasted | 100% |
All four thresholds are configurable via parameters. Actual thresholds trigger when actual spend crosses the percentage; the forecasted threshold triggers when projected spend is expected to cross it.
Troubleshooting
Subscription not found
# List accessible subscriptions
Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object Name, Id
Budget already exists
The script uses New-AzConsumptionBudget with upsert behavior. Re-running against the same subscription updates the existing budget rather than creating a duplicate.
Authentication errors
# Re-authenticate
Clear-AzContext -Force
Connect-AzAccount -Tenant 'your-tenant-id'
Script source
Related scripts
- Deploy-BulkBudgets.ps1 - Bulk budget deployment across a management group
- Deploy-AnomalyAlert.ps1 - Deploy anomaly alerts to individual subscriptions