Academyby Dasow

Stop 8 of 9 · Weekly

Automation with guardrails

The recurring admin as PowerShell and Graph, promoted through a pilot tenant, with MCP to the PSA and RMM read-only until the reads have been right for a month.

Watch first · 0:53

Twelve tenants is not one tenant twelve times

Hazem runs the same admin every month across twelve tenants: licence reconciliation, stale account review, MFA registration gaps, device compliance drift, mailbox permission audits. Each one is twenty minutes of clicking per tenant, which is four hours a month of work that produces nothing except a list.

Automating it is the obvious move and the dangerous one. The code that fixes one tenant is the code that breaks all of them. So the rule for this stop is not about writing scripts, it is about how a script earns the right to run somewhere that matters.

The guardrails

Guardrail What it means here
Read first The reporting version exists, runs and is checked before the acting version is written
Dry run Every acting script supports -WhatIf and prints its full target list before it acts
Pilot tenant A tenant you own, with representative objects, that everything runs against first
Explicit targets The tenant list comes from a file you maintain, never from discovery
Stop on surprise The script refuses to continue when the target count is outside the range you declared

The last one is cheap and it is the one that saves you. Declare that a stale account script should touch between zero and fifteen objects in a tenant. When it finds two hundred, it stops and tells you, and you find out the filter was wrong before it was expensive.

Ask for the reporting version with the guardrails built in
Write me a PowerShell script using Microsoft Graph that reports, for a single tenant, every enabled user account with no interactive sign-in in 90 days, along with their licences and any mailbox delegations pointing at them.

Reporting only, no changes anywhere. It takes the tenant from a parameter, authenticates with a certificate rather than a secret, never has a credential written into it, and writes a CSV plus a one-line summary. Before the code, explain in plain English what it reads and what permissions it needs, using the least privileged Graph scopes that will do the job.
Get the acting version with the stop built in
Now the acting version, which disables the accounts I approve from that CSV. It must support -WhatIf, read the approved list from a CSV I have edited rather than deciding for itself, print the full list of accounts it will touch before it touches any, and abort with a message if the count is outside a MinExpected and MaxExpected range I pass in.

Show me the dry-run command line and the real command line separately, and tell me what it writes to a log.

Connectors, read-only first

MCP connectors to the PSA and the RMM turn the monthly review into a question. The discipline is the same as the scripts: reads for a month, checked against the console, before anyone talks about writes.

Use the read-only connector for the monthly review
Using the PSA connector, list every ticket across all clients closed in the last 30 days where the time logged was over two hours, grouped by client and by cause. For each group tell me which of them would be prevented by a change we could make once. Read only, and tell me any client where the data looks incomplete rather than filling the gap.

The artefact

A script pack: the reporting version, the acting version with its dry run and its stop, the tenant list file, and a change log with a dated line for every run and every tenant it touched. That log is what an auditor asks for when they ask how you manage privileged access.

Quick check

Try it

Report a bug or share feedback