License usage report: SKU inventory, assigned counts, and per-user breakdown.¶
Exports a comprehensive report useful for audits — combines inventory, unlicensed users, and per-SKU user lists into a single view.
Permissions
Requires delegated permission User.Read.All, Organization.Read.All.
Reference¶
- https://learn.microsoft.com/en-us/graph/api/subscribedsku-list
- https://learn.microsoft.com/en-us/graph/api/user-list
from office365.graph_client import GraphClient
from tests.settings import client_id, client_secret, tenant
client = GraphClient(tenant=tenant).with_client_secret(client_id, client_secret)
# 1. SKU inventory
skus = client.subscribed_skus.get().execute_query()
print("=" * 80)
print("LICENSE INVENTORY")
print("=" * 80)
print(f"{'SKU':35s} {'Enabled':>8s} {'Consumed':>8s} {'Status':12s}")
print("-" * 80)
for s in sorted(skus, key=lambda x: x.sku_part_number or ""):
enabled = s.prepaid_units.enabled if s.prepaid_units else 0
consumed = s.consumed_units or 0
status = s.capability_status or ""
print(f"{s.sku_part_number or '':35s} {enabled:8d} {consumed:8d} {status:12s}")
# 2. All users with their licenses
all_users = (
client.users.select(["displayName", "userPrincipalName", "assignedLicenses"])
.order_by("userPrincipalName")
.get()
.execute_query()
)
sku_map = {s.sku_id: s.sku_part_number for s in skus}
print()
print("=" * 80)
print("USER LICENSE ASSIGNMENTS")
print("=" * 80)
for u in all_users:
assigned = u.assigned_licenses or []
if assigned:
names = [str(sku_map.get(lic.skuId, lic.skuId) or "")[:8] for lic in assigned]
print(f" {u.user_principal_name:45s} {', '.join(names)}")
# 3. Unlicensed users
unlicensed = [u for u in all_users if not u.assigned_licenses]
print()
print("=" * 80)
print(f"UNLICENSED USERS ({len(unlicensed)})")
print("=" * 80)
for u in unlicensed:
print(f" {u.user_principal_name:45s} {u.display_name or ''}")