Microsoft offers a plethora of options for exporting usage out of Azure. You can then slice and dice the raw data and generate some reports. What happens if I don’t need to do all of that? What if I just like the out-of-the-box report that is presented in the Azure portal? I can either save this report and share it via a URL, or I can download it as a PNG and share that.
The former is pretty straight-forward, but how can I automatically download the PNG and send that out?

This diagram has a nice area chart, aggregated costs of each service, locations, and enrollment accounts. You can change the scope to a specific subscription or set the root management group to get all your subscription costs. This is exactly what I would want as a quick 1-page summary.
If you look at the ribbon bar, you can see “Download” and the option to download it as a PNG.

Looking at our network calls in the dev tools, you can see a call to the publish API, then another URL is returned that we call to actually download the PNG. This is exactly how the portal is generating your PNG for you to download and save.

https://management.azure.com/providers/Microsoft.Management/managementGroups/<tenantId>/providers/Microsoft.CostManagement/publish?api-version=2021-04-01-preview
Looking at the payload, it is sending the following
{
"properties": {
"format": [
1
],
"validityDuration": 1,
"properties": {
"currency": null,
"dateRange": "ThisMonth",
"query": {
"type": "ActualCost",
"dataSet": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "Cost",
"function": "Sum"
},
"totalCostUSD": {
"name": "CostUSD",
"function": "Sum"
}
},
"sorting": [
{
"direction": "ascending",
"name": "UsageDate"
}
]
},
"timeframe": "None"
},
"chart": "Area",
"accumulated": "true",
"pivots": [
{
"type": "Dimension",
"name": "ServiceName"
},
{
"type": "Dimension",
"name": "ResourceLocation"
},
{
"type": "Dimension",
"name": "Subscription"
}
],
"scope": "providers/Microsoft.Management/managementGroups/<tenantId>",
"kpis": [
{
"type": "Forecast",
"enabled": true
}
],
"displayName": "AccumulatedCosts"
}
}
}
All we need to do now is craft up the PowerShell.
$azContext = Get-AzContext
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId)
$authHeader = @{
'Content-Type'='application/json'
'Authorization'='Bearer ' + $token.AccessToken
}
$body = @"
{
"properties": {
"format": [
1
],
"validityDuration": 1,
"properties": {
"currency": null,
"dateRange": "ThisMonth",
"query": {
"type": "ActualCost",
"dataSet": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "Cost",
"function": "Sum"
},
"totalCostUSD": {
"name": "CostUSD",
"function": "Sum"
}
},
"sorting": [
{
"direction": "ascending",
"name": "UsageDate"
}
]
},
"timeframe": "None"
},
"chart": "Area",
"accumulated": "true",
"pivots": [
{
"type": "Dimension",
"name": "ServiceName"
},
{
"type": "Dimension",
"name": "ResourceLocation"
},
{
"type": "Dimension",
"name": "Subscription"
}
],
"scope": "providers/Microsoft.Management/managementGroups/<tenantId>",
"kpis": [
{
"type": "Forecast",
"enabled": true
}
],
"displayName": "AccumulatedCosts"
}
}
}
"@
#copy the URL from your dev tools. Depending on your account type EA, MCA, Pay as you go, etc, this will be different for the URL.
$restUri = "https://management.azure.com/providers/Microsoft.Management/managementGroups/<tenantId>/providers/Microsoft.CostManagement/publish?api-version=2021-04-01-preview"
$response = Invoke-RestMethod -Uri $restUri -Method Post -Headers $authHeader -body $body
Now that the PNG is being generated, the API will return a URL where to actually download the PNG when ready. We can get that URL from the response object as it is a synchronous call.
$response.properties.url
$date=(get-date).tostring('MM-dd-yyyy')
invoke-restmethod -uri $response.properties.url -outfile "c:\temp\YearToDate-$($date).png"
We now have two options for sharing our report. We can generate a private URL that the user must view, or we can generate the PNG and do whatever we want with it. You can easily use the Azure portal to build the report you want then view the JSON body to submit in your payload!