๐Ÿ’ณ Recipe ยท Licensing & Cost Optimization

Export a Report of All Users and Their Assigned Licenses

Generate a complete CSV inventory of every Microsoft 365 user with their assigned license SKUs, resolved to friendly product names

Complexity

Beginner

Impact

read-only + reporting + license-audit + compliance + bulk

Context

Why This Matters

License reporting is one of the most common recurring tasks for a Microsoft 365 administrator. Finance wants to reconcile monthly spend, security wants to verify who holds privileged SKUs (E5 Security, P2, etc.), and IT leadership wants to identify unused or overprovisioned licenses before renewal.

This recipe produces a full per-user license inventory across the tenant: display name, UPN, and every assigned SKU (translated from GUIDs to human-readable product names like ENTERPRISEPACK or SPE_E5). Run it whenever you need an audit-ready snapshot โ€” typically before a renewal, during a license true-up, or as part of quarterly access reviews.

Microsoft 365 does not expose a single built-in export that joins users with their resolved license names, so admins either click through the GUI one user at a time, use the Licenses blade's limited export, or script against Microsoft Graph. Scripting is the fastest and most repeatable option.

Expected Outcomes

After running this recipe you will have:

  • A CSV file (User_License_Report.csv) with one row per user containing Display Name, User Principal Name, Account Enabled, and a comma-separated Licenses column.
  • License SKU GUIDs resolved to friendly skuPartNumber values (e.g. ENTERPRISEPACK, SPE_E5, FLOW_FREE).
  • A clear view of unlicensed accounts โ€” useful for spotting guest users, shared mailboxes, room resources, and stale enabled users who are wasting no license but may still pose a risk.
  • A reusable script you can schedule (Task Scheduler / Azure Automation) for monthly reporting.

Risks & Considerations

Before you run this:

  • Data sensitivity. The output contains every user's UPN and license entitlements. Treat the CSV as confidential and store it in a location governed by your DLP / retention policy.
  • Read-only scopes only. This recipe needs User.Read.All and Organization.Read.All. Do not consent to write scopes (User.ReadWrite.All, Directory.ReadWrite.All) for a reporting task.
  • Guest users are included. GET /users returns members and guests by default. If you only want employees, filter on userType eq 'Member'.
  • Disabled accounts are included. Disabled accounts can still hold licenses (common licensing waste). Review before deprovisioning โ€” if you remove a license from a mailbox-enabled user without a grace-period plan, mailbox data can be deleted after 30 days.
  • Friendly SKU names are internal codes. skuPartNumber values like SPE_E5 are Microsoft's internal identifiers. Use Microsoft's product names and service plan identifiers reference to translate for non-technical stakeholders.
  • Large tenants require paging. Tenants over 999 users need @odata.nextLink handling โ€” the script provided does this automatically.

Required Permissions

PermissionWhy It's Needed
User.Read.AllRead every user's profile and assignedLicenses property
Organization.Read.AllRead tenant subscribedSkus to map SKU GUIDs to skuPartNumber friendly names
Directory.Read.AllAlternative broader scope if User.Read.All is not available; grants the same read-only view

The fastest way to get this done โ€” just ask Dex. Copy the prompt below and paste it into your Dex conversation.

For IT Admins

Paste into Dex CoAdmin

Generate a report of all users in our Microsoft 365 tenant with their assigned licenses. Resolve SKU GUIDs to friendly product names, include whether each account is enabled, and produce a downloadable CSV I can share with finance.
Try in Dex CoAdmin