Files
personaEngine2/docs/ConfigurationReference.md
T
dave 5f125c34f2 Add elapsed run time, per-account results CSV, and a default config path
Summaries now show elapsed wall-clock time since the run started, and every
summary (interim and final) overwrites a results.csv (Object ID, UPN,
persona/status) next to the audit log, so an operator has a plain export
without parsing NDJSON. ConfigPath also now defaults to
./config/persona-engine.json instead of requiring -ConfigPath every run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 22:10:24 -04:00

11 KiB
Raw Blame History

Configuration reference

Every field in persona-engine.json, and every finding code the validator can produce.

The authoritative schema is config/persona-engine.schema.json (JSON Schema draft-07). A working example is config/persona-engine.example.json, which is validated against its own schema before every commit — if the example the documentation points at could not pass, every reader's first run would fail.

For a task-oriented walkthrough of every condition type and operator with worked JSON examples, see RuleAuthoringGuide.md. This document is the terse reference; that one teaches by example.

Top level

Field Required Notes
configVersion yes Semantic version, major.minor.patch. A downgrade is a safety finding.
metadata no owner, changeReference, description. Free-form; not read by the engine.
engine yes Engine behaviour.
dataSources yes Which directory data may be retrieved.
logging no Audit output.
personas yes The declared persona catalogue.
rules yes Ordered business rules.

engine

Field Required Default Notes
targetAttribute yes The single attribute the engine may write. Must be a directory extension property and must appear in approvedWritableAttributes.
approvedWritableAttributes yes The allow-list. Comparison is ordinal — extension property names are case-sensitive in Graph.
maxConditionDepth no 5 RE-004. Minimum 1, hard ceiling 10.
summaryInterval no 25 Interim summary frequency. 0 suppresses interim summaries; a final summary always appears.
defaultMembershipMode no direct Mode for membership conditions that do not specify one.
evaluationErrorThreshold no unset Count of EvaluationError results above which the run reports exit code 4. Unset means report, do not fail.

Setting evaluationErrorThreshold to 0 makes a single transient lookup failure fail the run. That is occasionally what you want; it is rarely what you meant.

dataSources

Field Required Notes
groups.enabled yes When false, no membership facet is retrieved. Rules needing it become EvaluationError.
groups.membershipMode no Pins a mode globally. Leave it out unless you mean to restrict — absent means "any mode is acceptable", and RE-007 makes mode a per-condition choice. Pinning it makes every per-condition override a PE-SEM-014 warning.
roles.enabled yes Directory role assignments.
roles.includeEligible no PIM-eligible assignments. Out of scope for v1; no provider is implemented.

The engine retrieves only the facets enabled rules actually reference. A configuration with no role conditions never calls the role endpoint, so a tenant where role reads are unavailable can still run property-only rules.

logging

Field Required Default Notes
destination no both file, stream, both, or none. stream writes records to the PowerShell Information stream.
path no <current-directory>/logs/persona-engine-audit.ndjson NDJSON output file. One record per line.
resultsFileName no results.csv Per-account results CSV, written next to path's directory. Lists AccountObjectId, UserPrincipalName, PersonaStatus for every account processed so far. Overwritten on every summary, interim and final.
traceConditionValues no false Writes evaluated attribute values into audit records.
acknowledgeConditionTracing no false Required whenever traceConditionValues is true (VR-003).

personas

The declared catalogue. A rule assigning a persona absent from this list is a PE-SEM-010 error — the catalogue is what stops a typo from writing a new persona value into the directory.

Unclassified and EvaluationError are processing results and may never be declared or assigned.

rules

Field Required Notes
id yes Unique. Appears in every audit record; this is how a decision is traced to its rule.
name yes Human-readable.
description yes Why the rule exists. Required, because a rule nobody can explain cannot be safely changed.
enabled yes Disabled rules are excluded from evaluation but still appear in summaries with zero matches.
priority yes Unique integer. Lower evaluates first.
persona yes Must appear in personas.
match yes The root condition group.
tags, owner, changeReference, effectiveDate, notes, testCases no Metadata. effectiveDate is not evaluated — a date-dependent decision would break determinism.

Priorities must be unique among enabled rules. The engine breaks ties by rule ID so results stay deterministic, but the resulting order is an accident rather than a decision, so PE-SEM-002 blocks it.

Condition groups and conditions

A group has operator (all or any) and a conditions array. Each entry is either another group or a condition.

Field Applies to Notes
type all property, membership, or role.
property property One of the supported names below, or an extension property.
operator all See the operator table.
value most Single comparison value.
values in, notIn Comparison set.
groupObjectIds membership Group Object IDs. Names are mutable; IDs are not (RE-009).
roleIds role Role template IDs, which are stable across tenants.
membershipMode membership direct or transitive, per condition.
caseSensitive Reserved. Not implemented in v1; the schema accepts the key so a later version needs no breaking change.

Supported properties

AccountObjectId · UserPrincipalName · DisplayName · UserType · AccountEnabled · CompanyName · JobTitle · Department

Plus any directory extension property named extension_<32-hex-app-id>_<name>. Anything else is PE-SEM-015: unsupported properties are never retrieved, so the condition would compare against a permanently absent value and quietly never match.

Operators (RE-005)

Operator Applies to Notes
equals, notEquals property Case-insensitive (RE-006).
contains, notContains property Case-insensitive substring.
startsWith, endsWith property Case-insensitive.
matchesRegex property Pattern compiled at validation time. An invalid pattern is PE-SEM-016, not a runtime failure.
in, notIn property Requires values.
isNull, isNotNull property Tests presence. Must not carry a value — it would be silently ignored (PE-SEM-009).
memberOf, notMemberOf membership, role Requires groupObjectIds or roleIds.

Null and absent properties are treated as empty for ordinary comparisons and never cause an evaluation failure (FR-012). Intentional null matching uses isNull / isNotNull.

Tri-state evaluation

Conditions return True, False, or Unknown. Unknown means required data could not be retrieved, and it propagates:

Group Contains Result
all any False False
all only True plus at least one Unknown Unknown
any any True True
any only False plus at least one Unknown Unknown

An Unknown at a rule's root makes the account EvaluationError: the stored persona is preserved and no write is attempted (FR-013, FR-014).

Validation layers

Run in order, stopping at the first that produces Error findings. Running semantic checks over a structurally invalid document yields noise, not signal.

Layer Mechanism Codes
1 Syntax ConvertFrom-Json PE-SYN-nnn
2 Schema Test-Json -SchemaFile PE-SCH-nnn
3 Semantic PowerShell checks PE-SEM-nnn
4 Safety PowerShell checks PE-SAF-nnn

Codes are stable. Pipelines and runbooks match on them, so a code is never reused for a different condition and never renumbered.

Syntax — PE-SYN

Code Condition
PE-SYN-001 Configuration file not found, or is not a file
PE-SYN-002 File exists but could not be read
PE-SYN-003 File is not valid JSON

Schema — PE-SCH

Code Condition
PE-SCH-001 Document violates the schema
PE-SCH-002 Schema file not found
PE-SCH-003 Schema file exists but is not valid JSON Schema

PE-SCH-003 exists because of V-5a: Test-Json returns $true when the schema itself cannot be parsed. A wrapper trusting the return value would report every configuration as schema-valid against a schema that never ran.

Semantic — PE-SEM (VR-002)

Code Condition Severity
PE-SEM-001 Duplicate rule ID Error
PE-SEM-002 Duplicate priority among enabled rules Error
PE-SEM-003 No rules, or no enabled rules Error
PE-SEM-004 Blank target attribute Error
PE-SEM-005 Target attribute absent from the approved list Error
PE-SEM-006 Rule references a disabled data source Error
PE-SEM-007 memberOf / notMemberOf with no group or role IDs Error
PE-SEM-008 in / notIn with no values Error
PE-SEM-009 isNull / isNotNull carrying a comparison value Error
PE-SEM-010 Persona not in the declared catalogue Error
PE-SEM-011 Unclassified used as a rule persona Error
PE-SEM-012 Nesting deeper than maxConditionDepth Error
PE-SEM-013 maxConditionDepth outside 110 Error
PE-SEM-014 Condition mode differs from an explicitly pinned global mode Warning
PE-SEM-015 Unsupported property name Error
PE-SEM-016 Invalid regular expression Error

Several of these are also enforced by the schema. The overlap is deliberate: layer 2 can be bypassed with -SchemaPath, and V-5a showed an unparseable schema passes silently. Anything that can misclassify a privileged account is checked twice.

Safety — PE-SAF (VR-003)

Code Condition Severity
PE-SAF-001 Blank target attribute Error enforcing, Warning in preview
PE-SAF-002 Approved list contains a non-extension attribute Error
PE-SAF-003 Enabled rules need data the data sources do not provide Error
PE-SAF-004 configVersion lower than the deployed version Error enforcing, Warning in preview
PE-SAF-005 Rules removed or reordered with no version change Error enforcing, Warning in preview
PE-SAF-006 Tracing enabled without acknowledgement Error
PE-SAF-007 Save would overwrite an existing configuration with no backup Error

PE-SAF-004 and PE-SAF-005 need -PreviousConfigPath. Without it they are skipped, and an Information finding says so — silence would be read as approval.

Escalation (VR-005)

Error blocks execution and saving. Warning blocks only under -TreatWarningsAsErrors. Information never blocks. Passing -TreatWarningsAsErrors does not change a finding's severity; it changes the caller's tolerance for it.