7
source systems
1617
PowerShell LOC
28
functions
RO
credentials
Y
idempotent

corvus is one PowerShell module file --- ~1500 lines, 29 exported functions --- that runs against an existing AD environment and writes JSON / CSV / summary artifacts. It is read-only by design. Detectors investigate and report; nothing in the module ever calls Set-AD* or Remove-AD*. The wrapper script Invoke-Corvus.ps1 runs preflight + a full sweep and lands a run folder under %TEMP%\Corvus\<RunId>\.

Tech scope

  • Detectors named Find-Corvus* follow a strict contract: take -Inventory (output of Get-CorvusInventory) and emit findings as a side effect. Adding a new detector means writing the function, exporting it, and inserting one call in the orchestrator.
  • Module-scoped state ($script:RunContext, $script:Findings, $script:Inventory, $script:Config) is mutated across calls; Initialize-CorvusRun resets, detectors append via New-CorvusFinding.
  • Configuration ships with vendor-account name patterns (SailPoint, Workday, Oracle HCM, UKG, CyberArk, Entra Connect) and AD attribute mappings (extensionAttribute1 for source system, extensionAttribute14 for source record id). Override per-environment with Set-CorvusConfiguration; never edit the defaults.
  • Reads Security event log (event 4720, account creation) from domain controllers when available. -SkipEventLog falls back to inventory-only mode.

What "read-only" means here

The module never calls a write cmdlet against the directory. Detectors investigate and report; remediation is the operator’s responsibility, performed in their own change-control process. This is preserved as an invariant — mirrored when adding new detectors, and enforced socially by code review.

Output

One run produces three artifacts in %TEMP%\Corvus\<RunId>\:

  • JSON dump of every finding (machine-readable; suitable for feeding into a SIEM or ticketing system).
  • CSV with one row per finding (spreadsheet-friendly).
  • Markdown summary written for a human to read first.
corvus HCM Workday UKG SailPoint CyberArk AD Entra
as of 2026-04-26
pull normalize match keys score duplicates report
as of 2026-04-26
AD12000 Entra11000 Workday9000 HCM8500 UKG8100 SailPoint7800 CyberArk900
as of 2026-04-26

Surface

The surface is a PowerShell module: Import-Module corvus; Invoke-CorvusTriage -Sources @(...). Read-only by contract — the module does not have write credentials to any of the 7 systems, so the worst it can do is exhaust a connector. Output is a single normalized table per source plus a cross-source duplicate ledger keyed on a deterministic identity hash.

Constraints

Every connector has its own definition of “the same person.” Workday's worker ID is canonical inside Workday and meaningless to AD; SailPoint's identityName may match Entra's userPrincipalName but only after a normalization pass. corvus does the normalization explicitly and exposes the rules as data, not code — so a triage-time rule change does not require a module re-publish. Idempotency is non-negotiable: the same input across the same 7 sources yields a byte-identical duplicate ledger.

:/ ESC