Before executing any steps, Stepper validates the script:
- Checks for
[CmdletBinding()]and the self-install guard independently. Each component is silently injected if missing. The guard is wrapped in#region Stepper ignoreso it won't trigger unmanaged-code warnings on the next run. No prompt, no#Requiresstatement added. - Scans for unmanaged code between
New-Stepblocks then prompts per block: Wrap / Mark / Delete / Ignore - Checks that
Stop-Stepperappears at the end - If the
$StepperConversionCompletesentinel is absent, invokesConvertTo-StepperScriptto detect and migrate cross-step variables to$Stepper.<Var>notation. On completion, ConvertTo injects$StepperConversionComplete = $trueinside#region Stepper ignore. The hook is skipped on all subsequent runs.
If the script is modified by any of the above, Stepper writes the changes and asks you to re-run.
- Each
New-Stepblock is identified byfilepath:lineNumber - After each step succeeds, state is serialized to a
.stepperfile (XML viaExport-Clixml) in the same directory as the script - State includes: SHA256 hash, full script contents, last completed step, step name/number, timestamp (ISO 8601), and the full
$Stepperhashtable
On the next run, Stepper finds the .stepper file, computes the current SHA256, and if it matches prompts:
[R] Resume (default) [s] Start over [m] More details [q] Quit
Resume mode skips all steps up to and including LastCompletedStep and continues from the next one.
If the hash doesn't match, Stepper warns about the inconsistency and prompts:
[r] Resume (risky) [S] Start over (default) [m] More details [q] Quit
Start over removes the state file and runs fresh.
Selecting [M] shows:
- Script hash comparison (saved vs. current)
- Full
$Steppervariable contents (JSON formatted) - Last completed step name, number, and line
- Full source code of the last completed step (extracted via PowerShell AST, with brace-matching fallback)
Stop-Stepper removes the .stepper file. The next run has no state and executes all steps from scratch.
When Read-Host is unavailable (CI/CD, remoting, unattended runs), Stepper falls back to safe defaults:
| Prompt | Default |
|---|---|
Missing [CmdletBinding()] |
Silent auto-inject (always; no prompt) |
| Unmanaged code | Wrap |
| Resume, script unchanged | Resume |
| Resume, script modified | Start over |
| Cross-step variable conversion | Convert all |
Run your script with -Verbose to see timestamped activity from Stepper:
[2026-03-08 14:22:01][Stepper] Executing step 1/3 - 'Download Files'
[2026-03-08 14:22:03][Stepper] Step complete. Writing state...
[2026-03-08 14:22:03][Stepper] Executing step 2/3 - 'Process Data'
Verbose messages cover: step execution, state read/write/remove, variable changes, and hash comparisons. Requires [CmdletBinding()] in the calling script.
Stepper writes a structured log file (<scriptname>.ps1.stepper.log) alongside the script by default. Each step produces:
- An
[INFO]entry at the start of execution with step number and source location - A per-step transcript section (
=== BEGIN STEP N TRANSCRIPT ===) capturing host output - An
[INFO]entry on completion with elapsed time - An
[ERROR]entry if the step fails
Logging is on by default. Use -NoLog on a New-Step call to exclude a step, or -LogPath to override the log file location. See Logging for full details.
Stepper displays a colorful pixel-art logo on module import. To suppress it:
$env:STEPPER_SHOW_LOGO = 'false'