Skip to content

Phase5-InheritanceSource

Synopsis

Phase 5 helpers for AD Permissions Analyzer: streaming composite-key index over explicit ACEs + inheritance source resolution rewriter with DACL_PROTECTED short-circuit.

Description

Implements §9 from docs/AD-Permissions-Analyzer-Plan.md. Per ADR-030, Phase 5 is now a two-pass streaming consumer of the Phase 3 CLIXML batch file: Pass 1 builds a compact in-memory index over explicit rows only (no full-row payload), Pass 2 streams every row and rewrites to a Phase 5 CLIXML file with the two added columns (InheritanceSourceDN, InheritanceSourceNote). The detail-CSV schema is uniform across explicit and inherited rows.

The index keying is plan §9: (ObjectDN, TrusteeSid, AccessMask, ObjectTypeGuid). DN strings are normalised to upper-invariant before insertion AND lookup because ValueTuple<...,string,...> uses case-sensitive ordinal equality by default; AD DN comparison is case-insensitive.

Synthetic.Owner rows (AceIndex = -1) and PARSE_ERROR placeholders (AceIndex = -2) are excluded from the index — they are never the source of an inheritance chain — but they ARE rewritten to the Phase 5 output stream with the two added columns set to defaults.

Inheritance flags are sourced from each ACE's AceFlagsRaw byte (Phase 3 composes ContainerInherit / ObjectInherit / NoPropagateInherit / InheritOnly / Inherited bits there). The InheritanceFlags string on each record is the [System.Security.AccessControl.InheritanceFlags] enum form — useful for CSV output, but missing the propagation bits we need for Phase 5's class-filter rule.

The index bucket payload is a minimal PSCustomObject with only the two fields Test-InheritanceFlagsPropagateTo decodes (AceFlagsRaw and InheritedObjectTypeName). Dropping the full ~30-property ACE record is what makes the streaming index fit in memory at the 50k-object scale — see ADR-030 for the heap-budget rationale.

Inputs

None.

Outputs

None.