TL;DR
- What it does: Audits your M365 tenant against the security baseline β Identity, CA, Email, Endpoints, and Monitoring.
- What you get: Colour-coded terminal output ordered by priority, a full HTML report with per-finding Priority, Recommended Action, Why It Matters, Quick Wins, Top 3 Issues, and a separate executive summary for stakeholders.
- What it needs: PowerShell 7+, Microsoft.Graph modules, ExchangeOnlineManagement, and a set of delegated Graph API permissions.
- How long: Typically completes in a few minutes on small to mid-sized tenants. Email checks (forwarding, mailbox auditing) scale with mailbox count β larger tenants will take longer.
# Install Microsoft Graph SDK (minimum required modules)
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser -Force
Install-Module Microsoft.Graph.Identity.SignIns -Scope CurrentUser -Force
Install-Module Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser -Force
Install-Module Microsoft.Graph.DeviceManagement -Scope CurrentUser -Force
# Install Exchange Online Management
Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force
# Verify
Get-Module -ListAvailable Microsoft.Graph.* | Select-Object Name, Version
Get-Module -ListAvailable ExchangeOnlineManagement | Select-Object Name, Version
| Permission | Used for | Type |
|---|---|---|
| Policy.Read.All | Read Conditional Access policies, auth methods, security defaults | Delegated |
| Directory.Read.All | Read directory roles, members, admin assignments | Delegated |
| Organization.Read.All | Read tenant name, ID, accepted domains | Delegated |
| DeviceManagementConfiguration.Read.All | Read Intune configuration and compliance policies | Delegated |
| DeviceManagementManagedDevices.Read.All | Read managed device inventory and compliance state | Delegated |
| AuditLog.Read.All | Read audit log configuration | Delegated |
| Application.Read.All | Read consented OAuth applications (Enterprise Apps) | Delegated |
Get-TransportConfig, Get-CASMailbox, Get-Mailbox, Get-AdminAuditLogConfig). You can run this safely in production.
# Standard run β outputs to terminal + HTML in current directory
.\M365-SecurityAudit.ps1
# Specify a custom HTML export path
.\M365-SecurityAudit.ps1 -ExportPath "C:\Reports\TenantAudit-$(Get-Date -Format 'yyyyMMdd').html"
# Skip Exchange Online checks (faster, Graph-only)
.\M365-SecurityAudit.ps1 -SkipExchange
β Microsoft 365 Security Audit β’ v2.0 β
β tiagoscarvalho.com β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tenant : Contoso Ltd
ID : a1b2c3d4-0000-0000-0000-000000000000
Date : 2026-03-19 09:41
β FAILURES β requires immediate action
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β [CRITICAL ] SMTP AUTH globally disabled SMTP AUTH is enabled globally β all accounts exposed
β Disable in Exchange Admin Center β Settings β Mail flow. Whitelist only specific service accounts.
β [CRITICAL ] DMARC policy (contoso.com) p=none β monitoring only, spoofing is not blocked
β Update DNS record to p=quarantine now. Monitor rua reports 2β4 weeks, then move to p=reject.
β [HIGH ] High risk sign-in policy No CA policy targeting high-risk sign-ins
β Create a CA policy: Users = All, Sign-in risk = High, Grant = Block or require MFA + password change.
β WARNINGS β review recommended
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β [CRITICAL ] Block legacy authentication Policy 'BLOCK - Legacy Auth' is in Report-Only [REPORT-ONLY]
β Review sign-in logs, confirm no legitimate legacy auth, then switch state to On.
β [HIGH ] Global Admin count 4 Global Admins β consider reducing to 2
β Audit each GA account. Replace with scoped roles where full GA is not needed.
β PASSING CONTROLS
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β [CRITICAL ] MFA enforced β all users Policy: 'REQUIRE - MFA All Users'
β [HIGH ] Mailbox auditing enabled All mailboxes have auditing enabled
β [HIGH ] High risk sign-in policy Risk-based CA active: 'BLOCK - High Risk Sign-ins'
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PASS 14 FAIL 3 WARN 4 VALIDATE 2 INFO 3 TOTAL 26
Baseline checks passed: 82% (PASS vs FAIL β not Microsoft Secure Score)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Full report : .\M365-SecurityAudit-20260319-0941.html
Exec summary : .\M365-SecurityAudit-20260319-0941-executive.html
