Reporting & Artifacts
Generate and customize HTML scan reports.
What Is the HTML Report?
The HTML report is a comprehensive, standalone document of a complete scan. Unlike emails/webhooks (which summarize changes), the report shows all detected activity with deep detail.
Contents:
- Severity breakdown with counts
- All detected changes organized by workload and severity
- Before/after diffs for each change
- Tenant metadata and scan timestamp
- Git commit SHA (if available)
- Dark mode compatible
- Responsive mobile-friendly design
Quick Setup
- Set
REPORT_ARTIFACT=truein pipeline variables - Run the pipeline
- Download
scan-report.htmlfrom pipeline artifacts - Open in browser
Enabling Reports
Azure DevOps
- Pipelines → PIM Monitor → Edit → Variables
- Click + Variable
- Name:
REPORT_ARTIFACT - Value:
true(case-sensitive) - Save
- Next scan will generate report
GitHub Actions
- Settings → Secrets and variables → Actions → Variables
- Click New repository variable
- Name:
REPORT_ARTIFACT - Value:
true - Create variable
- Next scan will generate report
Accessing Reports
Azure DevOps
- Go to Pipelines → PIM Monitor → [latest run]
- Scroll to Artifacts section
- Click Download for
scan-report.html - Save and open in browser
GitHub Actions
- Go to Actions → PIM Change Scan → [latest run]
- Scroll to Artifacts section
- Click scan-report.html
- Download and open in browser
Report Structure
Header
Brand, title, tenant name, scan timestamp:
PIM MONITOR
Scan Report — 2026-04-27 18:42:15 UTC
Tenant: Contoso Inc.
Summary Section
High-level counts of detected changes:
Total changes: 5
High ████████████████░░░░░░░░░░░░░░░░░░ 2 (40%)
Medium ░░░░░░░░░░░░░░░░░░████████░░░░░░░░░░░░░░░ 2 (40%)
Low ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█░░░░░░░░ 1 (20%)
Changes by Workload
Organized sections for each scanned entity type:
Directory Roles
- Role name
- Changes (policy, assignments, definition)
- Severity badges
- Diff details
PIM Groups
- Group name
- Changes (policy, assignments, definition)
- Severity badges
- Diff details
Authentication Contexts
- Context name
- Properties changed
- Severity
Administrative Units
- Unit name
- Properties changed
- Severity
Diff Details
For each change:
OLD → NEW
[red] - oldValue
[green] + newValue
Links to Entra portal (if role/group)
Footer
Metadata and generation details:
Scan complete: 2026-04-27T18:42:15Z
Repository: github.com/contoso/PIM-Monitor
Commit: a3cd69c
Generated by: PIM Monitor v1.0
Customizing Reports
Change Report Title
Edit Export-ScanReport in src/notifications.ps1 (line ~691):
$pageTitle = "[PIM Monitor] Scan Report"
Change to:
$pageTitle = "Azure Identity Governance Scan"
Customize Report Colors
Edit the CSS variables in Format-ScanReportHtml (src/notifications.ps1, lines ~350-380):
--color-high: #dc2626; /* Red */
--color-medium: #ea580c; /* Orange */
--color-low: #eab308; /* Yellow */
--color-bg: #fafafa; /* Light background */
Change to your brand colors:
--color-high: #1e40af; /* Blue */
--color-medium: #7c3aed; /* Purple */
--color-low: #059669; /* Green */
Add Custom Branding
Edit the header section to add logo or organizational branding:
<div style="display: flex; align-items: center; margin-bottom: 20px;">
<img src="https://example.com/logo.png" alt="Logo" style="height: 40px; margin-right: 20px;">
<h1>Your Organization PIM Report</h1>
</div>
Include Additional Metadata
Add tenant ID, region, or custom fields to the footer:
# In Export-ScanReport, before closing HTML:
$footer = @"
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #e5e5e5;">
<p><strong>Tenant ID:</strong> $TenantId</p>
<p><strong>Region:</strong> North America</p>
<p><strong>Classification:</strong> Internal Use Only</p>
</div>
"@
Change Severity Label Names
Edit Format-ScanReportHtml to change "High", "Medium", "Low", "Informational" to custom labels:
# Change:
$severityLabel = $severity # "High", "Medium", etc.
# To:
$severityLabel = switch ($severity) {
"High" { "Critical"; break }
"Medium" { "Important" }
"Low" { "Minor" }
"Informational" { "FYI" }
}
Remove Sections
To exclude certain workloads or severity levels, edit the section generation logic.
Example: Skip Informational changes:
if ($change.severity -eq "Informational") {
continue # Skip informational changes in report
}
Report Privacy & Retention
Storage Location
Azure DevOps:
- Stored in Build Artifacts storage
- Retention policy: Default is 30 days, configurable per project
- Accessible to anyone with project access
GitHub Actions:
- Stored in Actions artifacts storage
- Retention policy: Default is 90 days, configurable per repository
- Accessible to anyone with repository access
Security Considerations
The report includes:
- Display names of roles, groups, administrative units
- Property values that changed (e.g., MFA settings)
- Commit links and timestamps
Recommendations:
- Store reports in private repositories (GitHub) or secure project (Azure DevOps)
- If sharing reports, redact sensitive display names
- Set artifact retention to match your compliance policy
- Review access permissions regularly
Archival & Compliance
To keep historical reports:
Option 1: Configure extended retention
- Azure DevOps: Project Settings → Pipelines → Artifact retention
- GitHub Actions: Settings → Actions → Artifacts and logs → Retention policy
Option 2: Manually download and store
- Download reports to secure storage (OneDrive, SharePoint, etc.)
- Tag with date and tenant
- Implement archival workflow
Troubleshooting
Report not generated
Check:
- Is
REPORT_ARTIFACT=trueset in variables? - Were changes detected? Reports only generate on changes
- Check pipeline logs:
Export-ScanReportshould appear - Verify
BUILD_ARTIFACTSTAGINGDIRECTORYis available (Azure DevOps)
Report looks corrupted or incomplete
Check:
- Is HTML file fully downloaded? Incomplete file → browser error
- Try opening in different browser (Chrome, Firefox, Edge)
- Check pipeline logs for errors during report generation
- Ensure HTML has valid encoding (UTF-8)
Report file too large
Check:
- How many changes were detected? Many changes = larger file
- Disable report for scans with no changes (already does this)
- Implement filtering by severity level (before report generation)
Styling looks wrong in browser
Check:
- Browser supports CSS custom properties? (Modern browsers OK)
- Dark mode toggle? Some browsers have dark mode that conflicts
- Try incognito/private browsing (skips extensions that might affect styling)
- Check console for errors (F12 → Console tab)
Comparing Report vs. Email/Webhook
| Aspect | Report | Webhook | |
|---|---|---|---|
| Trigger | Always (if enabled) | Only on changes | Only on changes |
| Detail level | Very high (all data) | Summary (top issues) | Summary |
| Format | HTML (browser) | Email (multi-client) | JSON/Slack/Teams |
| Deep linking | Yes (Entra portal) | Yes | Limited |
| Accessibility | Requires download | Immediate delivery | Immediate delivery |
| Archival | Artifact storage | Email archive | Webhook logs |
| Mobile friendly | Yes | Responsive | Platform-dependent |
Best practice: Use both:
- Email/webhook for immediate alerts (urgent issues)
- Report artifact for detailed review and compliance archival
Related Pages
- Environment Variables — REPORT_ARTIFACT
- Pipeline Configuration — REPORT_ARTIFACT setup
- Notifications — Email/webhook alternatives
- Email Notifications — Email format vs. report