Every Module writes the same twelve lines around the one line that does the
work:
Invoke-WcdProgressCallback ... -Event 'Start'
try {
<the work>
Write-WcdLog -Level 'INFO' ...
Invoke-WcdProgressCallback ... -Event 'Finish' -Kind 'success'
$results += [pscustomobject]@{ Step = $key; Success = $true; Error = '' }
} catch {
Write-WcdLog -Level 'ERROR' ...
Invoke-WcdProgressCallback ... -Event 'Finish' -Kind 'error'
$results += [pscustomobject]@{ Step = $key; Success = $false; Error = $_.Exception.Message; RemedyKey = '...' }
}
The Result shape is a literal written 71 times across 12 files. Its optional
fields — Severity, RemedyKey, RemedyArgs, Applied, RebootPending —
have no schema anywhere. A typo in a property name is not an error; the
Diagnostic reads $null and the row quietly renders as a plain success.
The runner
$results += Invoke-WcdStep -Module 'Config-Power' -Key $key `
-LogPath $resolvedLogPath -ProgressCallback $ProgressCallback `
-SuccessLog 'Power: screen timeout on AC set to 15 min.' `
-FailureLabel 'Screen timeout on AC' -FailureRemedy 'PowerCfgFailed' `
-Action { Invoke-WcdPowerCfg '/change' 'monitor-timeout-ac' '15' }
Invoke-WcdStep owns the progress events, both log lines, the try/catch, and
the Result shape. The Action returns nothing on success, or emits a Result
fragment when the Step has something to say beyond OK.
What it has to absorb
Not every Step is the simple case, and the runner is only worth it if it covers
these without a -Raw escape hatch that half the callers use:
- Steps that succeed with a warning.
Config-Power unelevated returns
Success = $true; Severity = 'WARNING'; RemedyKey = 'RequiresAdmin' without
running anything. The Action needs a way to say "did not run, here is why".
- Steps that carry extra fields.
Applied on ComputerName / DomainJoin,
RebootPending on WindowsUpdateReboot. Both are read by the Diagnostic to
decide whether to raise the restart row.
- Steps whose severity depends on the reading.
Config-Disk and
Config-BitLocker pick OK / WARNING from what the machine reported, not from
whether the call threw.
- Steps with
RemedyArgs. The remediation template takes format arguments.
- One Module, many dynamic Steps.
Config-Applications and
Config-Printer loop over manifest entries.
If those five need five parameters, this is not a deepening — reconsider.
Do it incrementally
This touches all 12 Modules and all 12 test files. Convert Config-Power and
Config-TaskbarLeft first and stop there. Two adapters is enough to know
whether the interface holds; twelve at once is enough to know only that the
tests still pass.
Do #17 first — it settles what a Module owes the orchestrator, and this
issue settles what a Step owes a Module. Wrong order and this gets rewritten.
Done when
Every Module writes the same twelve lines around the one line that does the
work:
The Result shape is a literal written 71 times across 12 files. Its optional
fields —
Severity,RemedyKey,RemedyArgs,Applied,RebootPending—have no schema anywhere. A typo in a property name is not an error; the
Diagnostic reads
$nulland the row quietly renders as a plain success.The runner
Invoke-WcdStepowns the progress events, both log lines, the try/catch, andthe Result shape. The Action returns nothing on success, or emits a Result
fragment when the Step has something to say beyond OK.
What it has to absorb
Not every Step is the simple case, and the runner is only worth it if it covers
these without a
-Rawescape hatch that half the callers use:Config-Powerunelevated returnsSuccess = $true; Severity = 'WARNING'; RemedyKey = 'RequiresAdmin'withoutrunning anything. The Action needs a way to say "did not run, here is why".
AppliedonComputerName/DomainJoin,RebootPendingonWindowsUpdateReboot. Both are read by the Diagnostic todecide whether to raise the restart row.
Config-DiskandConfig-BitLockerpick OK / WARNING from what the machine reported, not fromwhether the call threw.
RemedyArgs. The remediation template takes format arguments.Config-ApplicationsandConfig-Printerloop over manifest entries.If those five need five parameters, this is not a deepening — reconsider.
Do it incrementally
This touches all 12 Modules and all 12 test files. Convert
Config-PowerandConfig-TaskbarLeftfirst and stop there. Two adapters is enough to knowwhether the interface holds; twelve at once is enough to know only that the
tests still pass.
Do #17 first — it settles what a Module owes the orchestrator, and this
issue settles what a Step owes a Module. Wrong order and this gets rewritten.
Done when
Invoke-WcdStepinsrc/WcdHelpers.ps1, with comment-based helptests/WcdHelpers.Tests.ps1covers: success, throw, did-not-run-with-reason,severity chosen by the Action, extra fields carried through,
RemedyArgsConfig-PowerandConfig-TaskbarLeftconvertedit should not