In this module
AD7.5 Building the Complete Quarterly Report
Figure AD7.5 — The quarterly report has 7 sections covering every layer of the security program. A consolidated PowerShell script collects the data for all sections in 5 minutes. The template is filled in manually from the script output — total production time under 30 minutes.
The consolidated data collection script
Save this as C:\SecurityScripts\Get-QuarterlyReport.ps1. Run it at the start of each quarter to collect all report data:
# Get-QuarterlyReport.ps1 — Quarterly Security Posture Data Collection
# Run at the start of each quarter to collect data for the report
param(
[int]$DaysBack = 90 # Default: last quarter (90 days)
)
$startDate = (Get-Date).AddDays(-$DaysBack).ToString("yyyy-MM-ddTHH:mm:ssZ")
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " QUARTERLY SECURITY REPORT DATA" -ForegroundColor Cyan
Write-Host " Period: Last $DaysBack days" -ForegroundColor Cyan
Write-Host " Generated: $(Get-Date -Format 'dd MMM yyyy HH:mm')" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
# Connect to all required services
Connect-MgGraph -Scopes "AuditLog.Read.All","SecurityEvents.Read.All","DeviceManagementManagedDevices.Read.All" -NoWelcome
Connect-ExchangeOnline -ShowBanner:$false
# --- SECTION 2: IDENTITY ---
Write-Host "`n--- SECTION 2: IDENTITY ---" -ForegroundColor Yellow
$allSignIns = Get-MgAuditLogSignIn -Filter "createdDateTime ge $startDate" -Top 5000
$riskySignIns = ($allSignIns | Where-Object { $_.RiskLevelDuringSignIn -notin @("none","hidden") }).Count
$caBlocked = ($allSignIns | Where-Object { $_.ConditionalAccessStatus -eq "failure" }).Count
Write-Host "Total sign-ins: $($allSignIns.Count)"
Write-Host "Risky sign-ins detected: $riskySignIns"
Write-Host "Sign-ins blocked by CA: $caBlocked"
# MFA coverage
$allUsers = Get-MgUser -All -Property UserPrincipalName,AccountEnabled | Where-Object { $_.AccountEnabled }
$mfaRegistered = 0
foreach ($u in $allUsers | Select-Object -First 50) {
$methods = (Get-MgUserAuthenticationMethod -UserId $u.UserPrincipalName -ErrorAction SilentlyContinue).Count
if ($methods -gt 1) { $mfaRegistered++ }
}
Write-Host "MFA registered (sample): $mfaRegistered / $($allUsers.Count) users"
# --- SECTION 3: EMAIL ---
Write-Host "`n--- SECTION 3: EMAIL ---" -ForegroundColor Yellow
Write-Host "Check manually: security.microsoft.com → Reports → Threat protection status"
Write-Host "Record: phishing blocked, malware blocked, user-reported, delivered phishing"
# --- SECTION 4: DEVICES ---
Write-Host "`n--- SECTION 4: DEVICES ---" -ForegroundColor Yellow
$devices = Get-MgDeviceManagementManagedDevice -All
$compliant = ($devices | Where-Object { $_.ComplianceState -eq "compliant" }).Count
$total = $devices.Count
$rate = if ($total -gt 0) { [math]::Round($compliant / $total * 100, 1) } else { 0 }
Write-Host "Total managed devices: $total"
Write-Host "Compliant: $compliant ($rate%)"
Write-Host "Non-compliant: $($total - $compliant)"
# --- SECTION 5: DATA ---
Write-Host "`n--- SECTION 5: DATA ---" -ForegroundColor Yellow
Write-Host "Check manually: purview.microsoft.com → Data Classification → Overview"
Write-Host "Record: labeled documents %, label distribution, DLP matches, overrides"
# DLP summary
Connect-IPPSSession -ShowBanner:$false
$dlpMatches = Get-DlpDetailReport -StartDate (Get-Date).AddDays(-$DaysBack) -EndDate (Get-Date) -ErrorAction SilentlyContinue
if ($dlpMatches) {
Write-Host "DLP matches: $($dlpMatches.Count)"
$dlpMatches | Group-Object PolicyAction | Select-Object Name, Count | Format-Table
}
# --- SECTION 6: SECURE SCORE ---
Write-Host "`n--- SECTION 6: SECURE SCORE ---" -ForegroundColor Yellow
$score = Get-MgSecuritySecureScore -Top 1
$pct = [math]::Round($score.CurrentScore / $score.MaxScore * 100, 1)
Write-Host "Current: $($score.CurrentScore) / $($score.MaxScore) ($pct%)"
# --- SECTION 7: INCIDENTS ---
Write-Host "`n--- SECTION 7: INCIDENTS ---" -ForegroundColor Yellow
Write-Host "Check manually: weekly security log for incident count, classification"
Write-Host "Record: TP count, FP count, BTP count, mean time to detect, mean time to contain"
Write-Host "`n========================================" -ForegroundColor Green
Write-Host " DATA COLLECTION COMPLETE" -ForegroundColor Green
Write-Host " Paste results into report template" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinueThe complete report template
QUARTERLY SECURITY POSTURE REPORT
[Organization Name]
Q[X] [Year] | Prepared by: [Name] | Date: [Date]
1. EXECUTIVE SUMMARY
[4 sentences covering all layers. Example:]
"This quarter, [Organization] maintained robust security across all
layers: [X] credential attacks blocked by MFA and conditional access,
[X] phishing emails blocked by Defender for Office 365, [X]%
device compliance rate with BitLocker encryption verified, and [X]%
of documents classified with sensitivity labels. [X] security
incidents were detected and contained through weekly monitoring,
with mean time to detect of [X] hours. Secure Score maintained at
[X]% (industry benchmark: [X]%). All controls operate within the
existing E3 licence at no additional cost."
2. IDENTITY (Module AD1)
- MFA coverage: [X]% of active users
- Credential attacks blocked: [X] (CA failures from unfamiliar sources)
- Risky sign-ins detected: [X] (investigated during weekly review)
- Compromised accounts: [X] (contained via AD6.2 procedure)
- Conditional access policies active: [X] (CA001-CA003)
- Trend: [stable/improved/declined] vs last quarter
3. EMAIL (Module AD2)
- Phishing emails blocked: [X]
- Safe Links clicks blocked: [X]
- Malware attachments blocked: [X]
- User-reported suspicious emails: [X]
- Phishing emails delivered (missed by filters): [X]
- DMARC status: [p=none/quarantine/reject]
- Trend: [stable/improved/declined] vs last quarter
4. DEVICES (Module AD3)
- Compliance rate: [X]%
- Encryption coverage: [X]% (BitLocker verified)
- Unmanaged device access blocked: [X]
- Non-compliant devices remediated: [X]
- Exceptions: [X] active exceptions (reviewed quarterly)
- Trend: [stable/improved/declined] vs last quarter
5. DATA (Module AD4)
- Label adoption: [X]% of documents classified
- Label distribution: Public [X]%, Internal [X]%, Confidential [X]%,
Highly Confidential [X]%
- DLP matches: [X] (blocked: [X], overridden: [X])
- External sharing: anonymous links disabled, [X] external users active
- Stale external access removed: [X] users this quarter
- Trend: [stable/improved/declined] vs last quarter
6. INCIDENTS AND MONITORING (Modules AD5-AD6)
- Weekly security reviews conducted: [X]/13 (target: 13/13)
- Incidents detected: [X] total ([X] TP, [X] FP, [X] BTP)
- Mean time to detect: [X] hours
- Mean time to contain: [X] minutes
- Secure Score: [X]% (vs [X]% last quarter)
- Notable incidents: [brief summary of any TP incidents]
7. NEXT STEPS AND RECOMMENDATIONS
- Completed improvements: [list from post-incident reviews]
- In-progress improvements: [list with timelines]
- Recommendations for next quarter: [prioritized list]
- E5 evaluation: [status — see AD7.9 for full business case]
- Budget requests: [if any]
- Governance status: [X]/4 policies approved, IRP tested [date]
APPENDIX: Data Sources
- Identity: Entra ID sign-in logs, Get-MgAuditLogSignIn
- Email: Defender portal → Reports → Threat protection status
- Devices: Intune compliance dashboard, Get-MgDeviceManagementManagedDevice
- Data: Purview Data Classification dashboard, Get-DlpDetailReport
- Secure Score: Get-MgSecuritySecureScore
- Incidents: Weekly security log (C:\SecurityScripts\WeeklySecurityLog.csv)Report production workflow
Day 1 of the quarter (30 minutes):
- Run
Get-QuarterlyReport.ps1— automated data collection (5 min) - Open the report template — copy from the previous quarter's report (1 min)
- Update Section 1 (executive summary) with the new numbers (5 min)
- Update Sections 2-5 with automated data + manual portal checks (10 min)
- Update Section 6 from the weekly security log (5 min)
- Update Section 7 with improvements completed and planned (4 min)
The first quarterly report takes 45-60 minutes (building the template from scratch). Subsequent reports take 20-30 minutes (updating numbers in an existing template). The PowerShell script does the heavy lifting — you're mostly copying numbers from the script output into the report.
Save each quarter's report as a separate file: SecurityReport-Q1-2026.docx, SecurityReport-Q2-2026.docx. The collection of quarterly reports demonstrates continuous monitoring and improvement over time — auditors and management can see the progression.
Presenting the quarterly report to management
The report document is the artifact. The presentation is the conversation. Keep the presentation to 5-10 minutes:
Open with the executive summary (1 minute). Read or paraphrase the 4-sentence summary. This gives management the complete picture in 30 seconds.
Highlight one achievement (1 minute). "This quarter, our MFA enforcement blocked 89 credential attacks. Without MFA, any of these could have resulted in a compromised account." Choose the metric that best demonstrates value.
Flag one concern (1 minute). "Our Secure Score dropped by 4 points due to a temporary CA policy change. We identified and corrected it within the weekly review cycle." Transparency about issues builds trust — management respects honesty about challenges more than a presentation where everything is perfect.
Present next steps (2 minutes). "Priorities for next quarter: implement MFA registration restrictions, evaluate Entra ID P2 add-on, deploy phishing simulation." Each next step is justified by data from this quarter's report.
Answer questions (5 minutes). Management typically asks: "Are we secure?" (Yes — here are the metrics), "What's our biggest risk?" (The specific gap from Section 9), "What do we need to spend?" (Reference the E5 business case if applicable, otherwise "nothing — E3 covers everything").
Don't read the full report in the meeting — send it in advance and use the meeting for the summary and discussion. The report is the evidence; the meeting is the conversation.
Report distribution list
Send the quarterly report to:
Your direct manager: Full report. They need all 7 sections for their own reporting to senior management.
Senior management / board (if applicable): Executive summary only (Section 1) plus Section 7 (Next Steps and budget recommendations). They don't need the technical detail — they need the outcome and the resource request.
IT team colleagues: Sections 2-6 (technical detail). They may identify data they can contribute or corrections to metrics from their areas.
DPO / Legal (if applicable): Section 6 (incidents) and any GDPR-relevant findings. They need awareness of incidents that may have regulatory implications.
Auditor (on request): Full report with all sections. The quarterly report is primary evidence for active security monitoring and program management.
Your first quarterly report shows: Secure Score 67%, compliance rate 97%, 0 delivered phishing, 2 incidents (both contained within 30 minutes), all on E3. Your manager asks: "Can you benchmark this against industry?" How do you respond?
Option A: "I'll research industry benchmarks and add them to the next report."
Option B: "The Secure Score comparison tab in the Defender portal shows our score against similar-sized organizations in our industry. Currently we're at 67% vs an industry average of 52% — we're above average. For the other metrics, formal industry benchmarks are limited for SMBs, but the directional data is clear: 0 delivered phishing, 97% compliance, and sub-30-minute containment represent a mature security posture for an organization our size. I'll add the Secure Score benchmark to Section 6 of future reports."
The correct answer is Option B. Use the data you have (Secure Score benchmarking is built into the portal). Acknowledge the limitations of broader benchmarking for SMBs. The directional evidence (zero delivered phishing, high compliance, fast containment) tells the story even without precise industry comparisons.
Try it: Produce your first quarterly report
1. Run Get-QuarterlyReport.ps1 and record the output 2. Copy the report template into a Word document 3. Fill in all 7 sections with your real data (or estimated data if this is your first quarter) 4. Write the executive summary — 4 sentences covering all layers 5. Add at least 2 items to Section 7 (next steps) 6. Save as SecurityReport-Q[X]-2026.docx 7. Send to your manager
Time the exercise. Your target: under 30 minutes for future reports. The first one may take 45-60 minutes as you establish the template and data sources.
You're reading the free modules of M365 Security: From Admin to Defender
The full course continues with advanced topics, production detection rules, worked investigation scenarios, and deployable artifacts.