Snippet

Create a planning config template

A complete PowerShell script that writes a sanitized JSON planning config with placeholder scope, labels, and app split rules.

powershellOct 6, 2026MIT

AI-generated, human-reviewed: the first draft was generated by an AI agent; I fact-checked, tested, and edited it. AI use policy

What it does#

Writes a JSON configuration template for a generic Azure consumption planning run. It keeps scope, labels, and optional app split rules outside the planning engine, so the engine can stay reusable.

You need#

  • PowerShell 7.6.2 or newer
  • No Azure modules
  • Replace placeholder values such as <tenant-id>, <management-group-id>, <subscription-id-1>, and <owner-name> before using the config with real Azure data

Where it goes#

Save it as New-SyntheticPlanningConfig.ps1. Run it from the folder where you want to create your starter config.

New-SyntheticPlanningConfig.ps1
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 Sarang Datye
#Requires -Version 7.4
[CmdletBinding()]
param(
    [string]$OutputPath = (Join-Path (Get-Location) 'planning.synthetic.json')
)

$configuration = [ordered]@{
    TenantId          = '<tenant-id>'
    ManagementGroupId = '<management-group-id>'
    OutputFolder      = '<output-folder>'
    VersionPrefix     = 'Azure-Consumption-Planning'
    StartMonth        = '2026-01'
    SeedMetadata      = [ordered]@{
        '<subscription-id-1>' = [ordered]@{
            N = 'Platform Services'
            A = 'Core Platform'
            L = '<owner-name>'
            E = 'Prod'
        }
        '<subscription-id-2>' = [ordered]@{
            N = 'Analytics Sandbox'
            A = 'Analytics Lab'
            L = '<owner-name>'
            E = 'Dev'
        }
    }
    SubscriptionSplits = [ordered]@{
        '<subscription-id-1>' = [ordered]@{
            Portfolio = 'Core Platform'
            Slices    = @(
                [ordered]@{
                    Slug  = 'api'
                    App   = 'API Service'
                    Env   = 'Prod'
                    Lead  = '<owner-name>'
                    Match = @('rg-api-prod-*', '*-api-*')
                }
            )
            Remainder = [ordered]@{
                App  = 'Shared Platform'
                Env  = 'Prod'
                Lead = '<owner-name>'
            }
        }
    }
}

foreach ($required in 'TenantId', 'ManagementGroupId', 'VersionPrefix', 'StartMonth') {
    if (-not $configuration[$required]) {
        throw "Missing required config value: $required"
    }
}

$json = $configuration | ConvertTo-Json -Depth 10
$json | Set-Content -Path $OutputPath -Encoding utf8NoBOM

$roundTrip = Get-Content -Path $OutputPath -Raw | ConvertFrom-Json
if (-not $roundTrip.TenantId -or -not $roundTrip.ManagementGroupId) {
    throw 'The generated config did not round-trip through JSON parsing.'
}

Write-Output "Wrote planning config template to $OutputPath"

Check that it works#

Run:

powershell
pwsh -NoProfile -File ./New-SyntheticPlanningConfig.ps1 -OutputPath ./planning.synthetic.json
pwsh -NoProfile -Command "Get-Content ./planning.synthetic.json -Raw | ConvertFrom-Json | Select-Object TenantId, ManagementGroupId"

You should see the placeholder tenant and management group values. Replace placeholders before connecting this config to a real planning run.