Copilot usage from the Microsoft 365 apps usage report.¶
When Copilot is licensed, getM365AppUserCounts gains a Copilot column
next to Outlook, Word, Excel and so on. This script isolates that column and
prints Copilot active users per day, plus the peak.
Tenants without Copilot licenses have no such column; the script says so and exits cleanly.
python usage_report.py
python usage_report.py --period D30
Permissions
Requires application permission Reports.Read.All (delegated works too).
Reference¶
from __future__ import annotations
import argparse
from office365.graph_client import GraphClient
from tests.settings import client_id, client_secret, tenant
def _int(value) -> int:
try:
return int(value or 0)
except ValueError:
return 0
def main() -> None:
parser = argparse.ArgumentParser(description="Copilot usage from the M365 apps report")
parser.add_argument("--period", default="D30", help="Aggregation period: D7/D30/D90/D180 (default: D30)")
args = parser.parse_args()
client = GraphClient(tenant=tenant).with_client_secret(client_id, client_secret)
rows = client.reports.get_m365_app_user_counts(args.period).execute_query().csv_rows()
copilot_columns = [c for c in (rows[0] if rows else {}) if "copilot" in c.lower()]
if not copilot_columns:
print(f"No Copilot column in the M365 apps report for {args.period}.")
print("The tenant has no Copilot licenses assigned, so the report has nothing to show.")
return
column = copilot_columns[0]
print(f"Copilot active users ({args.period}), column '{column}':\n")
peak = 0
for row in sorted(rows, key=lambda r: r.get("Report Date") or ""):
value = _int(row.get(column))
peak = max(peak, value)
print(f" {(row.get('Report Date') or '?')[:10]} {value:>6,}")
print(f"\nPeak: {peak:,} active Copilot user(s)")
if __name__ == "__main__":
main()