Most commitment problems are not pricing problems. They are visibility problems.

If you only look at the recommendation blade, you can miss the operational story: which teams still have on-demand spend, which commitments are being consumed well, and which unused hours are quietly turning into waste. Azure exports give you the raw evidence. The trick is choosing the right export, at the right scope, and reading actual and amortized data for what they are supposed to tell you.

At a glance

  • Use actual cost exports to see what you were billed and to spot on-demand spend that still deserves discounting.

  • Use amortized cost exports to attribute reservation and savings plan value back to resources and to measure unused commitment.

  • Use reservation recommendation exports to surface RI candidates at the billing scope.

  • Use actual cost exports to shortlist savings plan candidates, then validate the final commitment with the savings plan recommendation experience or API, because the official recommendation engine works from hourly usage.

Start with the right scope and the right export set

Do not start at the management group scope if your goal is commitment analysis. Management group exports are useful for broad usage views, but they do not include purchases, and they do not support amortized cost. That means they cannot show a reservation or savings plan waste. If you need rate optimization evidence, use a billing scope first, then use a subscription or resource group scope only when you need a tighter operational lens.

For this workflow, keep it simple: create actual cost, amortized cost, and reservation recommendation exports. That trio gives you bill truth, chargeback truth, and RI opportunity data in one repeatable pipeline.

Dataset

Use it for

Best scope

Watch-outs

Actual cost

Bill reconciliation, on-demand spend analysis, and purchase visibility

Billing scope or subscription

Covered usage can show zero EffectivePrice in actual cost. Good for invoices, not chargeback.

Amortized cost

Commitment consumption, internal chargeback, unused reservation and savings plan cost

Billing scope, subscription, or resource group

Do not use it to reconcile directly to the invoice.

Reservation recommendations

Surface RI candidates quickly

Billing account / billing profile

Recommendations already account for existing reservations and savings plans.

FOCUS (optional)

One combined schema for downstream analytics

Billing scope, subscription, or resource group

Management group scope is not supported for FOCUS exports.

Management group gotcha

Management group exports support only usage charges. Purchases such as reservations and savings plans are not exported there, and amortized cost is not supported. If you stay at management group scope, your waste analysis will be incomplete by design.

Configure exports so the files are useful later

For a first pass, choose CSV. It is easier to inspect, easier to diff, and easier to feed into a starter script. Improved exports can also write parquet, but CSV is the faster operational path when you are proving out the workflow.

Schedule the exports daily. Azure runs exports on UTC schedules; the exact run time can vary, and data is typically available within four hours after a run starts. Also, remember that exports are partitioned by default. Treat the manifest and all part files as one dataset, not as optional extras.

1.        Create an actual cost export for the billing scope or subscription that owns the commitment decisions.

2.        Create an amortized cost export for the same scope so you can see the consumed benefit value and the unused commitment.

3.        Create a reservation recommendations export at the billing account or billing profile scope.

4.        Store all three in the same storage account, but in separate folders so downstream parsing stays clean.

5.        Backfill at least the last full 30 days. If you are doing seasonal or bursty workloads, backfill 60 days as well.

Find RI candidates from exports without fooling yourself

Reservation recommendations are the fastest way to surface likely RI candidates. Azure calculates them from hourly usage over 7, 30, and 60-day look-back windows and recommends the quantity that maximizes savings. The recommendation engine also accounts for existing reservations and savings plans, which keeps you from double-counting already discounted usage.

That said, do not buy from the recommendation export alone. Use the actual cost export as your proof file. Before you treat a recommendation as buy-ready, answer four questions:

  • Is the workload still on-demand today, or did the team already change it after the recommendation was generated?

  • Is the VM family, region, and operating model stable enough to survive a one-year or three-year commitment?

  • Did you right-size first, or are you about to commit to an oversized estate?

  • Is there a real owner for the subscription, resource group, or workload receiving the commitment?

Fast qualification matrix

Signal in actual export

What it usually means

Action

Same service, same region, same resource type showing steady daily spend

Stable floor exists

Strong RI candidate

Daily spend stays high, but instance sizes or families move around

Usage is real but shape changes

Prefer Savings Plan shortlist

Spend already dropped after rightsizing or shutdown activity

Recommendation is stale

Re-run analysis before committing

No clear owner or no stable tagging

Chargeback and accountability are weak

Fix ownership before purchase

Use the actual cost exports to build a Savings Plan shortlist

This is where operators often overreach. Cost and usage details exports are daily-grain data, while savings plan recommendations are built from hourly pay-as-you-go usage and costs. That matters because savings plans are hourly commitments. Daily exports are still useful, but they are best for shortlist building and operational validation, not for the final hourly commitment number.

A solid shortlist usually looks like this:

  • On-demand spend appears on most days in the last 30 to 60 days.

  • The workload mix is flexible across sizes, regions, or services, which makes reservations too rigid.

  • The same team or platform lane keeps consuming enough eligible spend to justify a commitment.

  • The shortlist survives a rightsizing review.

Use the export to prove there is a repeatable pay-as-you-go floor. Then take the final sizing into the savings plan purchase experience, Azure Advisor, or the Benefit Recommendations API. Microsoft documents that savings plan recommendations are simulated from hourly on-demand usage and keep only candidates that produce net savings.

Reservation or Savings Plan?

Pattern

Better fit

Why

Bias check

Stable VM or database footprint with little change

Reservation

Specific commitment usually gives stronger savings

Confirm you already right-sized

Changing shapes, mixed families, or cross-service eligible spend

Savings Plan

Spend-based commitment tolerates movement

Do not size it from daily export alone

Steady base plus variable burst

Layer both

Reserve the floor and cover flexible remainder with Savings Plan

Start from the clean baseline

Measure commitment waste from amortized exports

Amortized data is the file that tells the operational truth about commitment usage. In actual cost, covered usage can show an EffectivePrice of zero because the purchase charge is carried elsewhere. In amortized cost, the same covered usage gets a prorated share of the reservation or savings plan cost, which makes chargeback and benefit tracking possible.

To measure waste, filter the amortized export by charge type:

·        Reservations: ChargeType = UnusedReservation

·        Savings plans: ChargeType = UnusedSavingPlan

Sum the cost column you standardize on in your own reporting layer. For EA that is often Cost. For MCA it is commonly CostInBillingCurrency after normalization. The point is consistency, not column loyalty. For reservations, keep ProductOrderId in your model so you can tie purchase records and usage records back to the same order.

Metric

Practical formula

Reservation waste $

Sum cost where ChargeType = UnusedReservation

Savings Plan waste $

Sum cost where ChargeType = UnusedSavingPlan

Waste rate %

Unused cost ÷ (unused cost + consumed amortized cost)

Top offenders

Group by ProductOrderId, BenefitName, subscription, resource group, or owner tag

Starter script pack preview

These examples assume CSV exports. They are meant to get you moving fast, not to replace a finished FinOps warehouse. The first script imports every CSV partition in a folder. The second measures unused commitment. The third builds a rough Savings Plan shortlist from actual cost data.

Script 1: Import all export partitions

function Import-CostExportCsv {
    param(
        [Parameter(Mandatory)] [string]$FolderPath
    )

    $files = Get-ChildItem -Path $FolderPath -Filter "*.csv" -File -Recurse |
        Where-Object { $_.Name -notmatch "manifest" }

    if (-not $files) { throw "No CSV files found under $FolderPath" }

    $rows = foreach ($file in $files) {
        Import-Csv $file.FullName
    }

    return $rows
}

Script 2: Summarize unused commitment from amortized exports

$amortized = Import-CostExportCsv -FolderPath ".\exports\amortized"

$costColumn = @("CostInBillingCurrency", "Cost", "PreTaxCost") |
    Where-Object { $amortized[0].PSObject.Properties.Name -contains $_ } |
    Select-Object -First 1

$waste = $amortized |
    Where-Object { $_.ChargeType -in @("UnusedReservation", "UnusedSavingPlan") } |
    Group-Object ChargeType, ProductOrderId, BenefitName |
    ForEach-Object {
        [pscustomobject]@{
            ChargeType   = $_.Group[0].ChargeType
            ProductOrder = $_.Group[0].ProductOrderId
            BenefitName  = $_.Group[0].BenefitName
            WasteAmount  = ($_.Group | Measure-Object -Property $costColumn -Sum).Sum
            Days         = ($_.Group | Select-Object -ExpandProperty Date | Sort-Object -Unique).Count
        }
    } |
    Sort-Object WasteAmount -Descending

$waste | Format-Table -AutoSize

Script 3: Build a rough Savings Plan shortlist from actual cost exports

$actual = Import-CostExportCsv -FolderPath ".\exports\actual"

$costColumn = @("CostInBillingCurrency", "Cost", "PreTaxCost") |
    Where-Object { $actual[0].PSObject.Properties.Name -contains $_ } |
    Select-Object -First 1

$shortlist = $actual |
    Where-Object {
        $_.PricingModel -eq "OnDemand" -and
        $_.ChargeType -eq "Usage" -and
        $_.ServiceName -match "Virtual Machines|App Service|Azure SQL|PostgreSQL|MySQL|Cosmos DB"
    } |
    Group-Object ServiceName, ResourceLocation |
    ForEach-Object {
        $group = $_.Group
        $days = ($group | Select-Object -ExpandProperty Date | Sort-Object -Unique).Count
        $total = ($group | Measure-Object -Property $costColumn -Sum).Sum
        $avgPerDay = if ($days -gt 0) { [math]::Round($total / $days, 2) } else { 0 }

        [pscustomobject]@{
            ServiceName      = $group[0].ServiceName
            ResourceLocation = $group[0].ResourceLocation
            DaysSeen         = $days
            TotalOnDemand    = [math]::Round($total, 2)
            AvgPerDay        = $avgPerDay
        }
    } |
    Where-Object { $_.DaysSeen -ge 20 -and $_.AvgPerDay -ge 5 } |
    Sort-Object TotalOnDemand -Descending

$shortlist | Format-Table -AutoSize

Validation checks before anyone buys anything

  • Reservation recommendations still line up with current on-demand spend in the actual cost export.

  • The top recommendation targets have a real owner and a stable deployment pattern.

  • UnusedReservation and UnusedSavingPlan totals appear only in amortized analysis, not in your invoice-reconciliation view.

  • You imported all partitions, not just the first CSV in the folder.

  • The final Savings Plan number is validated in the portal or Benefit Recommendations API, not guessed from daily exports.

Five failure modes I see a lot

Failure mode

Fix

Using management group exports for commitment analysis

You will miss purchases and amortized cost. Move up to the billing scope or down to the supported child scopes.

Using only actual cost

You can reconcile the bill, but you will miss internal consumption value and unused commitment.

Treating daily exports as an hourly Savings Plan truth

Use exports for shortlist building. Use Microsoft’s hourly recommendation engine for final sizing.

Buying before rightsizing

Discounts reduce rates. They do not fix oversized or idle resources.

Ignoring the owner model

Unowned commitments become shared waste fast. Tie candidates to accountable teams before purchase.

Bottom line

If you want cleaner commitment decisions, stop treating exports as a finance-only artifact. They are the operator evidence set. Actual cost shows what is still exposed to on-demand rates. Amortized cost shows whether your commitments are creating value or wasting money. Reservation recommendation exports help you find the obvious RI floor fast. Savings Plan candidates can be shortlisted from exports, but the final commitment should be validated with Microsoft’s hourly recommendation logic.

That gets you to a better operating loop: right-size first, prove the baseline, buy the right commitment, and keep measuring waste after purchase.

Starter script pack

Bundle the three scripts above with your own folder paths, owner mapping, and threshold values. That is enough for a first operational pack: import partitions, measure unused commitment, and surface the next shortlist for review.

Keep reading