IT licence management, building materials
Finding unused AI licences — without revoking them automatically
A weekly report sorts every licence holder into keep, coach, reclaim or review. Someone who does not use Copilot but is otherwise active counts as a training problem, not a cost problem.
- Year
- 2026
- Services
- Automation
- Area
- Corporate IT
- Role
- In-house, employed
Delivered in an employed role for an internal department, not under an external consulting contract. The organisation is not named.
The situation
The project folder does not document it. No README, no design notes, no ticket references — and no commit messages, because the repository contains no commits at all. Any account of the prior situation would be invented.
What the code implies, and no more: it answers “are we paying for seats nobody uses?” — a per-seat cost is configurable, and unused seats are priced out to an annual waste figure. And the email tells the reader to filter the attached spreadsheet in Excel “before any bulk action”, which suggests such reviews were previously done by hand. An inference, not a statement.
The approach
A single Function App with two entry points: a weekly timer and an HTTP endpoint for on-demand runs. Both call the same pipeline.
Authentication goes through the managed identity — no credentials anywhere in the code. It pulls the user directory with licence assignments and last sign-in timestamps, the per-user usage report, and three baseline activity reports covering email, Teams and files. Directory data arrives as JSON; the baseline reports are only reliably served as CSV, which the collector normalises into the same shape.
These sources are joined per person into one wide record of 47 fields: identity, department, country, manager, which applications the AI was used in, and how long ago.
On top sits a department benchmark: median and upper quartile of days since last use, computed only for departments with at least three licence holders so small teams do not skew the picture. A rules engine classifies each user; results go to storage as CSV and JSON, and out as an HTML email with the spreadsheet attached.
Where it could have gone the other way
The system recommends, but never acts.
Every call in the entire codebase is a read. No path removes a licence, changes group membership or emails an end user — despite having everything needed to do so, including each affected person’s manager.
The judgement is clearest in the classification rules. A user with no AI activity is not automatically flagged for removal. The rules first check whether that person is otherwise active — meetings attended, emails sent, files touched. If so, the recommendation becomes coach, not reclaim. A cost problem turns into a training problem.
This could have gone the other way: a simpler tool would flag every non-user as waste and automate revocation. The design trades that automation away deliberately, and several “review” cases exist purely to route ambiguity to a person — for example users seen only in chat, which also exists as a free tier.
The result
13 modules, around 1,690 lines, of which roughly 750 are the email rendering alone. Four connected systems, nine API endpoints, two entry points.
A second entitlement path is handled separately: the AI workspace tier is not a per-seat licence; access comes from usage-based spending policies scoped to security groups. The system resolves transitive membership of two configured groups to determine it.
Limits stated openly: there is no test suite — including for the classification rules, whose output drives cost decisions. Workspace credit consumption is not exposed through the API at all; the report says so in its own output and points to the admin centre rather than substituting a proxy metric.
And the most honest limitation is in the project too: activity is a proxy for value. “Last active” says somebody opened the application, not that it helped. Light-but-critical use looks exactly like habitual low-value use.
Stack
- Python
- Azure Functions
- Microsoft Graph API
- Azure Blob Storage
- SendGrid
More projects
Group customer service, construction chemicals
2026One contact centre for eleven countries — one platform, not eleven islands
Customer service across eleven countries over voice and SMS, with data from SAP, Salesforce and the product system surfaced directly in the agent workspace. Country differences are configuration, not separate installations.
- Twilio Flex
- Twilio TaskRouter
- Twilio Studio
- SAP
Group compliance, construction chemicals
202610,872 EU declarations of conformity, not copy-paste
New EU packaging regulation required declarations of conformity in 12 languages for around 900 packaging materials. Instead of filling them in one by one, a pipeline generates and files them in a single run.
- Python
- docxtpl / Jinja2
- Microsoft Word COM
- Microsoft Graph API
Sales & inside sales, construction chemicals
2026One orchestrator, three specialist agents for product questions
Instead of one agent with three knowledge sources, a parent agent routes to three specialists — one each for ERP article data, product content and SharePoint documents.
- Microsoft Copilot Studio
- Azure AI Search
- Azure Functions
- SharePoint
A similar process at your company?
30 minutes, free, no sales pitch. You describe what is costing you time — I tell you honestly whether automation is worth it.