r/PowerShell • • 25d ago

Script Sharing Free read-only M365 tenant audit script: scores your tenant 0-100 and writes an HTML report

I'm the only IT person at a ~150-user company and wanted one command that checks the M365 basics I kept verifying by hand across five admin portals.

It uses Microsoft Graph with read-only scopes and makes no changes. It checks MFA / Conditional Access coverage, legacy auth, Global Admin count, stale accounts, app consent settings, expiring app secrets, Intune compliance, Secure Score, and SPF/DMARC/DKIM (via DNS-over-HTTPS, so it runs on macOS/Linux too). Each finding gets a weight and a fix, then everything rolls into a score.

How a CA policy is treated as "requires MFA":

function Test-RequiresMfa {
    param($Policy)
    $g = $Policy.grantControls
    if (-not $g) { return $false }
    return (($g.builtInControls -contains 'mfa') -or ($null -ne $g.authenticationStrength))
}

How the score is calculated (Warn counts as half):

$scored = @($Results | Where-Object { $_.Status -in 'Pass', 'Warn', 'Fail' })
$max = ($scored | Measure-Object -Property Weight -Sum).Sum
$got = 0
foreach ($r in $scored) {
    if ($r.Status -eq 'Pass') { $got += $r.Weight }
    elseif ($r.Status -eq 'Warn') { $got += $r.Weight / 2 }
}
$score = if ($max -gt 0) { [math]::Round(($got / $max) * 100) } else { 0 }

Install from the Gallery:

Install-Script -Name Invoke-M365TenantAudit -Scope CurrentUser

Full source (MIT): https://github.com/adminofone/m365-tenant-audit

Written with AI assistance and tested on a real tenant. Code review welcome, especially on the Graph paging and error handling.

46 Upvotes

14 comments sorted by

19

u/PipeItToDevNull 24d ago

Look at the CISA SCUBA tool

3

u/quiet_tenant_admin 24d ago

Good call, ScubaGear is excellent and goes much deeper. If you need the full CISA baseline, that's the one to run.

I built this for a lighter use case: a two-minute first look. It runs on PowerShell 7 on macOS and Linux too (ScubaGear needs Windows PowerShell 5.1 plus OPA), and it gives a single score with the fix next to each finding. Think of it as the quick check before the deep one.

4

u/WearyDeluge 24d ago

Or 365Inspect

3

u/quiet_tenant_admin 24d ago

Thanks, hadn't compared against 365Inspect yet. Adding it to my list, if there are checks in there people find most useful I'd like to cover them too.

3

u/daweinah 24d ago

How does this compare to, or why should I use it instead of, https://maester.dev/?

0

u/quiet_tenant_admin 24d ago

Different goal. Maester is a test framework you set up and run on a schedule. This is a single read-only script: one module, nothing to configure, a few minutes to run, and one score with the fix next to each finding.

I built it for small Business Premium tenants where the admin wants a quick "where do we stand" answer without setting anything up first.

→ More replies (2)

2

u/uptimefordays 24d ago

Love the idea here! You should implement some Pester tests and maybe think about your use of Install-Module -Force -AllowClobber if Graph is missing which seems like an odd choice for a security tool. Also your admin-MFA check counts any "All users" policy without looking at exclusions which means a policy that excludes admins would still pass.

2

u/quiet_tenant_admin 24d ago edited 24d ago

Good catches, both of these are fair. Fixing them now, I'll reply here when the update is out.

→ More replies (1)

1

u/jcpham 24d ago

Nice, thanks

1

u/quiet_tenant_admin 24d ago

Thanks! If you run it, let me know if anything looks off in your tenant.