Contributing¶
PRs welcome. The codebase is small (two PowerShell scripts + a helper module + Pester tests) and the design rationale is in the Git log.
Architecture¶
purview-content-explorer-export/
Export-CEItems.ps1 # worker — one (TagType, TagName), N workloads
Invoke-CESweep.ps1 # orchestrator — enumerate, filter, dispatch, roll-up
lib/CEHelpers.psm1 # pure helpers (offline-testable)
tests/CEHelpers.Tests.ps1 # Pester unit tests (exporter helpers)
tests/Helpers.Tests.ps1 # Pester unit tests (helpers/ reporting module)
scripts/Find-CESitMatch.ps1 # canonical-name fuzzy matcher
examples/
items_all.sample.csv # synthetic sample output
names-credentials.example.csv # sample curated SIT list (52 names)
helpers/ # PurviewContentExplorerHelpers — reporting module over the CSV output
src/ # module (psd1/psm1 + Public/ + Private/)
README.md
output/ # gitignored, created at runtime
The orchestrator imports the worker as a script (& $workerScript ...) per tag, so each tag is a fresh script execution. Per-workload errors stay inside the worker (logged as warnings, don't abort the tag); per-tag errors stay inside the orchestrator (logged to sweep.log as fail, don't abort the sweep). Only a wholesale enumeration failure or connection failure aborts the run.
Running tests locally¶
Invoke-Pester ./tests -CI
# Expected: Tests Passed: 61
# Or a single file:
Invoke-Pester ./tests/CEHelpers.Tests.ps1 -CI
# Expected: Tests Passed: 34
The exporter's pure-logic helpers (Get-CESafeName, Test-CETagNameFilter,
Get-CETagTypeEnumeration, Get-CEConfidenceSummary, Get-CESitName) are unit-tested in
tests/CEHelpers.Tests.ps1, and the helpers/ reporting module in tests/Helpers.Tests.ps1
(synthetic CSV fixtures on TestDrive). Cmdlet integration is covered by manual smoke testing
against a real M365 tenant - no offline equivalent exists for Export-ContentExplorerData and
mocking it would just verify the mock.
Building docs locally¶
CI¶
Three workflows:
test.yml- Pester on Ubuntu / macOS / Windows + parse-check on every script (top-level scripts and thehelpers/module source)lint.yml- Super-Linter v8 (PSScriptAnalyzer / yamllint / markdownlint / gitleaks / actions-lint)docs.yml- Builds and deploys this site to GitHub Pages on every push to main
House rules¶
- Keep
Set-StrictMode -Version Latestand$ErrorActionPreference = 'Stop'in both top-level scripts. - Add Pester tests for any new pure logic:
lib/CEHelpers.psm1helpers go intests/CEHelpers.Tests.ps1,helpers/module functions intests/Helpers.Tests.ps1. - Don't introduce a dependency on a third-party PowerShell module that isn't already required (e.g. don't pull in
ImportExcel- read CSVs). - If you fix a footgun, add a one-line note in Troubleshooting so the next person doesn't hit it.
- PRs should be green on
test.ymlandlint.ymlbefore review.
Reporting issues¶
Please include:
- Output of
pwsh --version - Output of
Get-Module ExchangeOnlineManagement -ListAvailable | Select-Object Name,Version - The exact command you ran
- The first ~50 lines of the failure (or a summary if it's the same per-tag error 200 times)
For tenant-side issues (e.g. cmdlets behaving differently than documented), include your tenant region if you're comfortable sharing - the cmdlet has known regional quirks.