Azure cost management

How to export cost by service and resource group in Azure

Export cost by service and resource group with Azure PowerShell, group Cost analysis in the Azure portal, or run Altivane's Azure Cost by Service and Azure Cost by Resource Group reports.

By the Published

To export cost by service and resource group in Azure, query Cost Management for each subscription with the cost grouped by ServiceName and ResourceGroup, and save the rows. The figures are estimates until the invoice is issued, and new usage usually takes 8 to 24 hours to appear, or up to 72 hours for pay-as-you-go subscriptions.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of this month's cost by service and resource group on 1 row, across your enabled subscriptions.
Admin centreA chart and table of 1 subscription's cost, grouped 1 way at a time.
AltivaneRecommended for monthly cost reviews, with this month and last month side by side in a workbook.

Before you start

Use an account with the Reader or Cost Management Reader role on each subscription: both can read Cost analysis and the Cost Management query API. For a subscription bought through a Cloud Solution Provider, the partner must turn on the cost visibility policy before the subscription's users can see costs. A new subscription can take up to 48 hours before Cost Management works.

Know what the figures cover. Costs are estimated until an invoice is generated, don't include credits, and can be rerated until the invoice closes; support costs aren't included. Azure limits how often the query can be called and answers 429 Too Many Requests when it is called too fast. The example sends a query that only reads, exports a CSV and changes nothing. The script's finally block disconnects the account and clears its saved Azure contexts.

Option 1

Export cost by service and resource group with PowerShell

Install the module once. The script asks Cost Management for each enabled subscription's actual cost this month so far, grouped by service and resource group, and saves 1 row for each pair.

PowerShell
Install-Module -Name Az.Accounts -Repository PSGallery -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
$body = @{
    type = 'ActualCost'
    timeframe = 'MonthToDate'
    dataset = @{
        granularity = 'None'
        aggregation = @{ totalCost = @{ name = 'PreTaxCost'; function = 'Sum' } }
        grouping = @(
            @{ type = 'Dimension'; name = 'ServiceName' }
            @{ type = 'Dimension'; name = 'ResourceGroup' }
        )
    }
} | ConvertTo-Json -Depth 5
Connect-AzAccount -ErrorAction Stop
try {
    $subscriptions = @(Get-AzSubscription | Where-Object State -eq 'Enabled')
    $rows = [System.Collections.Generic.List[object]]::new()
    foreach ($sub in $subscriptions) {
        $path = "/subscriptions/$($sub.Id)/providers/Microsoft.CostManagement/query" +
            '?api-version=2025-03-01'
        $answer = Invoke-AzRestMethod -Path $path -Method POST -Payload $body
        if ($answer.StatusCode -ne 200) {
            Write-Warning "$($sub.Name) not read: HTTP $($answer.StatusCode)."
            continue
        }
        $result = ($answer.Content | ConvertFrom-Json).properties
        if ($result.nextLink) { Write-Warning "$($sub.Name) has more rows than 1 page." }
        $names = @($result.columns | ForEach-Object name)
        foreach ($row in $result.rows) {
            $cell = @{}
            for ($i = 0; $i -lt $names.Count; $i++) { $cell[$names[$i]] = $row[$i] }
            $rows.Add([pscustomobject]@{
                Subscription = $sub.Name
                Service = $cell['ServiceName']
                ResourceGroup = $cell['ResourceGroup']
                Cost = [math]::Round([double]$cell['PreTaxCost'], 2)
                Currency = $cell['Currency']
            })
        }
    }
    if ($rows.Count -eq 0) {
        Write-Output 'No cost was returned for this month.'
    } else {
        $rows | Sort-Object Subscription, @{ Expression = 'Cost'; Descending = $true } |
            Export-Csv -Path './azure-cost.csv' -NoTypeInformation -Encoding utf8
        Write-Output "$($rows.Count) rows saved to azure-cost.csv."
    }
} finally {
    Disconnect-AzAccount | Out-Null
}

The CSV holds the subscription, service, resource group, cost and currency, the largest cost first in each subscription. Each subscription is in its own billing currency, so don't add currencies together. For last month, set timeframe to Custom and add a timePeriod with from and to set to its first and last day; some kinds of subscription refuse TheLastMonth. For 1 split only, remove 1 of the 2 groupings. The script reads the columns from Azure's answer rather than assuming their order, and names any subscription it couldn't read or whose answer ran over 1 page, so a gap never looks like zero cost.

Option 2

Group costs in Cost analysis in the Azure portal

  1. Sign in to the Azure portal with an account that can read the subscription's costs.
  2. Choose Cost Management + Billing > Cost Management > Cost analysis, then use the Scope pill to choose the subscription.
  3. Choose Group by > Service name, then switch to the table view and set the granularity to None, so every service is listed rather than the top 10 and Others.
  4. Choose Download and pick Excel or CSV for a snapshot of the table.
  5. Choose Group by > Resource group name and download again for the split by resource group.

The download is a snapshot and isn't updated. Cost analysis groups by 1 property at a time in these views, so for service and resource group on 1 row, or several subscriptions in 1 file, use PowerShell or Altivane.

Common questions

Why don't the figures match the invoice?

Until the invoice is issued, Cost Management shows estimates that leave out credits and can change as charges are rerated. Support costs aren't included. Compare a closed month with its invoice instead of the current one.

Why did the query fail with error 429?

Azure throttled the request because too many cost queries were sent in a short time. Wait for the time Azure gives in its reply, then run the script again, or query fewer subscriptions in each run.

How do I find subscriptions with no budget?

A budget alerts you when costs pass a threshold you set. See how to find subscriptions without a budget in Azure.

Microsoft references

Technical references checked on 6 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us