Licence review in one prompt

14 Oct 2026

A Microsoft 365 licence review in one prompt

The licence review used to cost an afternoon: export the active users report, export the sign-ins, export the subscriptions, line them up in Excel by email address, and argue with yourself about what an empty cell means. In the GraphPaaS connector for Claude it is one item in the tools menu, Licence review, and one tenant to point it at.

The prompt is a short brief. It tells Claude which domains to read, in which order, with the 90-day cut already worked out as a date, and it ends by asking for a table of savings and who to check with first. Below is that run against Fabrikam HQ, our demo tenant (synthetic people, real tool calls, data collected on 11 October at 03:07 UTC). Each step shows what the prompt asks, the call it became, and what came back.

22
paid seats held by nobody
10
of 42 idle on the 90-day rule
6
idle by activity and by sign-in
1
disabled account still licensed

Seats you pay for and nobody holds

The prompt asks

Per SKU, how many paid seats are assigned to nobody?

Claude calls
get_metrics(domain="licences", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"sku": ["SPE_E3", "EMS", "VISIOCLIENT", "PROJECTPLAN3", "POWER_BI_PRO"]},
            aggregate=["sum:free", "sum:total"])
→ sum:free 22 · sum:total 125
Claude answers

22 of 125 paid seats are unassigned: 9 Power BI Pro, 5 EMS E3, 4 Project Plan 3, 3 Microsoft 365 E3 and 1 Visio Plan 2.

Claude read the full SKU list first and left two rows out of the sum on purpose. Power Automate Free shows 10,000 seats with 9 assigned, which would bury everything else and costs nothing. The same rule runs through the rest of the review: someone whose only products are free or trial ones (Office 365 A1, Power Apps for Developer, Fabric Free) is not in the waste list at all, because removing a licence nobody pays for saves nothing.

Ninety days without activity, and a date that lies

The prompt asks

Who holds a paid licence with no activity, or none since 13 July?

Claude calls
get_metrics(domain="licence_waste", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"last_activity": null})
→ 5 rows
get_metrics(domain="licence_waste", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"last_activity": {"<": "2026-07-13"}}, order_by="last_activity")
→ 5 rows
get_metrics(domain="licence_waste", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            group_by="first_assigned")
→ 1 group: 2026-07-14 · 42
Claude answers

10 of the 42 people with a paid licence are idle. Ana Dias, João Yilmaz, Sofia Dias, Bernardo Yilmaz and Kelly Dias have no activity Microsoft reports. Clara Fonseca (15 February), Hugo Keller, Olivia Ramos, Jonas Moreira and Vera Yilmaz (15 June) were last active before the cut.

Two things in that data need reading carefully. The last activity is the most recent date across Exchange, OneDrive, SharePoint and Teams, the per-service columns of Microsoft's active user detail report. A null there means no date reported in any of the four, which is not quite the same as "never logged in", as the next step shows.

The third call is the trap. The same report has a License Assign Date per service, and it looks like the answer to "how long has this seat sat idle". Here all 42 people share one date, 14 July, including Clara, whose last activity was five months earlier. She did not get her licence after she stopped working. The date moves when licences are re-assigned or the SKU changes (we measured 14 users jumping together in a real tenant), so Claude reports it and never builds on it. Measure idleness from the activity, never from the assignment.

A second witness: the sign-in

The prompt asks

Which licensed accounts has nobody signed in to since 13 July, and which disabled accounts still hold a licence?

Claude calls
get_metrics(domain="dormant_accounts", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"licences": {">": 0}, "last_signin": {"<": "2026-07-13"}})
→ 5 rows
get_metrics(domain="dormant_accounts", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"licences": {">": 0}, "last_signin": null})
→ 4 rows
get_metrics(domain="dormant_accounts", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"enabled": false})
→ 2 rows (1 with licences)
Claude answers

9 licensed accounts have no sign-in since 13 July. Six are also on the activity list: Ana, Clara, Hugo, Olivia, Jonas and Vera. Filipe Moreira is disabled and still holds 2 licences; his last activity was 4 October.

The two lists overlap on six names and disagree on seven, and the disagreement is the useful part. The sign-in date is lastSignInDateTime, which Microsoft defines as the last interactive sign-in attempt. Henrique Yilmaz, Liam Moreira and Wei Fonseca have none on record, yet all three show workload activity since 23 September. The likely reason is apps that refresh the session without prompting, which only the separate non-interactive date records. João, Sofia, Bernardo and Kelly are the opposite case. They signed in recently but show nothing in the four workloads, so ask what they use before touching their licence.

TWO LENSES ON THE SAME 42 PEOPLE · CUT: 13 JULY no workload activity since the cut workload activity since the cut Signed in interactive, since the cut No sign-in interactive, since the cut 4 · ask what they use João, Sofia, Bernardo, Kelly present, but outside Exchange, OneDrive, SharePoint and Teams 29 · keep both lenses agree they work here except Filipe Moreira: disabled, still holding 2 licences 6 · take to their managers Ana, Clara, Hugo, Olivia, Jonas, Vera no activity and no sign-in: the strongest candidates 3 · keep, likely silent sign-ins Henrique, Liam, Wei apps refresh their session without a prompt, so no interactive date Activity: licence_waste (usage reports) · Sign-in: dormant_accounts (signInActivity)

Copilot seats that may already be gone

The prompt asks

Which paid Copilot seats were never used?

Claude calls
get_metrics(domain="copilot_usage", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"last_activity": null})
→ 3 rows of 14
get_metrics(domain="licences", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            search="copilot")
→ 0 rows
Claude answers

Ana Dias, Elena Fonseca and João Yilmaz have 0 prompts. But the tenant has no Copilot SKU today, so there is nothing to reclaim here.

This is why the check against licences matters. Microsoft's Copilot usage report lists everyone licensed for Copilot at any point in the past 180 days, even if the licence was later removed. Counting its idle rows as seats to cancel would count seats that were cancelled already.

What renews before you decide

The prompt asks

Which subscriptions are trials, or change state before 10 December?

Claude calls
get_metrics(domain="subscriptions", tenant_id="ce48e256-019f-4f8c-b951-0c52d1d65b8e",
            where={"next_lifecycle": {"<": "2026-12-10"}}, order_by="next_lifecycle")
→ 4 rows
Claude answers

Visio Plan 2 (5 seats) is in Warning; its date, 5 October, has passed. Power BI Pro is a 20-seat trial that changes state on 20 October. Microsoft 365 E3 and EMS E3, 45 seats each, both reach their next date on 18 November.

Each subscription's nextLifecycleDateTime is when it moves to its next state if not renewed, and Warning means it already expired and sits in the grace period before suspension. So Visio needs a decision this week, the Power BI trial within ten days, and the 3 spare E3 and 5 spare EMS seats are worth settling before 18 November.

The table it ends with

The prompt closes by asking for savings opportunities, biggest first, and who to check with before removing anything. It also tells Claude not to invent prices: it only puts a money figure on a row when the organisation uploaded its own price catalogue to the GraphPaaS licence advisor, or when you give it the prices. The demo's catalogue is a sample, so the table counts seats.

What Seats Check with
Paid seats assigned to nobody 22 Whoever owns the renewal, before 18 November
No activity and no sign-in in 90 days 6 people Their managers
Disabled account, still licensed 2 licences Whoever runs offboarding
Power BI Pro trial ending 20 October 20 The Power BI report owners
Signed in, no workload activity 4 people The users themselves; not a removal yet
Why the receipts matter
Every row above traces back to a call you can re-run, and three of the review's best calls were the ones that stopped a wrong answer: the free SKUs left out, the assignment date ignored, the Copilot seats checked against what the tenant actually owns. Our licence waste audit covers the same ground by hand, and the dormant accounts article covers what to say to those six managers.
Sources
GraphPaaS

Run the licence review on your own tenant: it is in the connector's tools menu.

Add the connector →

Newsletter

Get the next article by email

Practical M365 & Azure cost pieces like this one. No spam, unsubscribe anytime.