The weak-password report was text only: DSInternals' formatted output
captured with Out-String, with UPNs spliced in by re-parsing that
text. Nothing downstream could consume it reliably.
- Next to the text report, Invoke-WeakPasswordTest now writes
<domain>_WeakPasswordReport_<timestamp>.json: tool, version,
generatedAt, domain, DC, accountsTested, and one finding per
non-empty check (WeakPassword, LMHash, DuplicatePasswordGroups, ...)
listing each account's logon name and UPN. Duplicate-password groups
stay grouped. The text and UPN-only reports are unchanged.
- ConvertTo-PasswordQualityFinding builds that data generically from
the result object's properties, so it does not depend on the exact
set of checks a DSInternals version reports. Arrays are assembled
with List.ToArray() rather than pipeline output, because Windows
PowerShell 5.1's ConvertTo-Json renders pipeline-wrapped arrays as
{"value": [...], "Count": n}.
- Test-ElysiumPasswordQuality returns a summary object: domain,
accounts tested, finding counts per check, and the three report
paths.
- UPNs come from the DSAccount objects already replicated for the
test (SamAccountName -> UserPrincipalName) instead of one Get-ADUser
query per dictionary hit; Get-UserUPN is removed. Missing UPNs still
read "UPN not found" in the text report (null in the JSON).
Tests: the converter on a result shaped like DSInternals' (string
sets, a list of sets for duplicate groups, an empty check) - empty
checks omitted, UPNs mapped, unknown UPN null, groups preserved, no
array-wrapper artefacts in the JSON. 33/33 Pester tests pass on pwsh 7.
The JSON shape on Windows PowerShell 5.1 and the real DSInternals
result object still need the Windows run.