Skip to content

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

pip install -r docs/requirements.txt
zensical serve
# open http://localhost:8000/

CI

Three workflows:

  • test.yml - Pester on Ubuntu / macOS / Windows + parse-check on every script (top-level scripts and the helpers/ 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

  1. Keep Set-StrictMode -Version Latest and $ErrorActionPreference = 'Stop' in both top-level scripts.
  2. Add Pester tests for any new pure logic: lib/CEHelpers.psm1 helpers go in tests/CEHelpers.Tests.ps1, helpers/ module functions in tests/Helpers.Tests.ps1.
  3. 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).
  4. If you fix a footgun, add a one-line note in Troubleshooting so the next person doesn't hit it.
  5. PRs should be green on test.yml and lint.yml before review.

Reporting issues

Please include:

  1. Output of pwsh --version
  2. Output of Get-Module ExchangeOnlineManagement -ListAvailable | Select-Object Name,Version
  3. The exact command you ran
  4. 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.