Microsoft 365 license audit: a step-by-step checklist (2026)

Microsoft 365 cost optimization · ~7 min read

A Microsoft 365 license audit doesn't need a platform or a consultant — it needs a repeatable, read-only process. This is the checklist we'd run on any tenant: inventory what you own, find what's wasted, spot what can be downgraded, and put a dollar figure on it. Everything here is read-only and runs inside your own tenant.

Before you start: you need an account that can read directory + usage data (Global Reader is enough) and the Microsoft Graph PowerShell SDK: Install-Module Microsoft.Graph -Scope CurrentUser. Sign-in activity additionally needs Microsoft Entra ID P1.

The checklist

  1. Inventory your SKUs. List every license you've purchased vs. assigned. The gap is unassigned waste. Get-MgSubscribedSku gives prepaidUnits.enabled (bought) vs consumedUnits (assigned).
  2. Map SKUs to real prices. Use your contracted/regional price, not just list. Watch the legacy names — Microsoft 365 Business Standard's part number is literally O365_BUSINESS_PREMIUM.
  3. Find unassigned seats. Any SKU where purchased > assigned is money spent on nothing. The cleanest win — reduce quantity at (or before) renewal.
  4. Find disabled-but-licensed accounts. Blocked sign-in doesn't stop billing. Anyone with accountEnabled = false who still holds a license is pure waste.
  5. Find never-signed-in users. Licensed accounts with no sign-in ever (and old enough to be meaningful) — provisioned and forgotten.
  6. Find inactive users. No sign-in in your chosen window (30/60/90 days). Reclaim or reassign after checking with their manager.
  7. Spot overlapping plans. Users carrying two base plans (e.g. E3 + E5) — drop the redundant one.
  8. Spot downgrade candidates. E5 seats not using premium security/compliance/Power BI/voice can move to E3 — $21/user/month. (full E5-vs-E3 math →)
  9. Quantify it. Multiply each reclaimable seat by its price × 12. "47 inactive users" is a shrug; "$X,000/year recoverable" gets a decision.
  10. Remediate, then schedule. Reclaim at renewal, remove licenses from disabled accounts, and re-run monthly — waste creeps back the moment offboarding slips.

The starter queries

Connect-MgGraph -Scopes "Organization.Read.All","User.Read.All","Directory.Read.All","AuditLog.Read.All"

# 1) Purchased vs assigned per SKU
Get-MgSubscribedSku | Select SkuPartNumber,
  @{n='Purchased';e={$_.PrepaidUnits.Enabled}}, @{n='Assigned';e={$_.ConsumedUnits}}

# 2) Licensed users + status + last sign-in
Get-MgUser -All -Property displayName,userPrincipalName,accountEnabled,assignedLicenses,signInActivity |
  Where-Object { $_.AssignedLicenses.Count -gt 0 }
Two gotchas that trip up DIY audits: requesting signInActivity on a tenant without Entra ID P1 returns a 403 for the whole query (retry without it); and free/self-service SKUs report a giant "unlimited" prepaid count you must exclude before summing unassigned seats.

Do it automatically

That's the whole audit — but assembling the scripts, handling the gotchas, pricing each seat, and formatting a report takes an afternoon each time.

Run the whole checklist in one command

SeatScout does every step above read-only and produces a dollar-quantified, CFO-ready report (plus CSVs and a remediation checklist). Free tier available.

Get SeatScout →

Related: How to find wasted M365 licenses · Offset the 2026 price increase · Best M365 license tools compared

SeatScout is independent and not affiliated with Microsoft. Prices referenced are public list prices; your agreement may differ.