Skip to content

Troubleshooting

Rod Christiansen edited this page Sep 3, 2026 · 1 revision

Troubleshooting

Where to look first

Question File
What happened in the most recent run? C:\ProgramData\ManagedState\reports\run.log
What is the state of every payload? C:\ProgramData\ManagedState\reports\items.json
What happened in a specific run? C:\ProgramData\ManagedState\logs\<date>\<HHmm>\startset.log
Structured events for a run ...\<HHmm>\events.jsonl
Warnings and errors, machine-wide Application event log, source StartSet
Why did an MSI payload fail? C:\ProgramData\ManagedState\logs\installs\<name>_<timestamp>.log
Get-Content C:\ProgramData\ManagedState\reports\items.json | ConvertFrom-Json |
    Where-Object current_status -ne 'Installed' |
    Format-Table item_name, current_status, last_error

Raise verbosity by setting log_level: debug in Config.yaml and restarting the service. The --verbose and --debug command-line switches do not change the level.

Symptoms

Nothing runs at all, and there are no logs

Cause: the service is not running, or was never registered.

Get-Service StartSet

Fix: register and start it — see Installation. If it starts and immediately stops, check the Application event log for the fatal exception; the service logs StartSet Service failed to start and rethrows.

A payload is in the directory but never runs and nothing complains

Causes, in order of likelihood:

  1. It is in a subdirectory. Discovery is top level only. A file at login-every\MyTool\Setup.ps1 is invisible.
  2. Its extension is not in allowed_extensions. .psm1, .py, .vbs, .reg and anything else are ignored silently. Only .ps1, .cmd, .bat, .exe, .msi, .msix by default.
  3. It is a *-once payload that already ran. Check with managedstatekeeper list --type <type> --show-executed.

Fix for 1 and 2: move the file flat into the directory with a supported extension. Fix for 3: edit the script (the checksum change re-arms it) or clear the ledger entry.

A login payload runs once for a user and then never again

Cause: it is login-privileged-once, which is tracked in runonce-system.json — once per machine, not per user.

Fix: move genuinely per-user work to login-once, or make it idempotent and use login-privileged-every. See Coming From Outset.

Login payloads never fire on sign-in, but managedstatekeeper login works

Cause: the Security event log is not being watched. The worker logs Insufficient permissions to monitor Security event log. Login scripts will not be triggered automatically. This happens when the service is not running as LocalSystem.

Get-CimInstance Win32_Service -Filter "Name='StartSet'" | Select-Object StartName

Fix: the service must run as LocalSystem. Re-register it, or correct the account:

sc.exe config StartSet obj= LocalSystem

Also confirm logon success auditing is enabled — the watcher needs 4624 events to exist:

auditpol /get /subcategory:"Logon"

Payloads run at first sign-in on a new machine and never again after that

Cause: this is the classic symptom of a logon watcher that only sees logon types 2 and 10. StartSet watches 2, 10 and 11 precisely for this reason, so if you see it, the running binary is older than that fix.

Fix: update to a current build. Confirm the running version:

& 'C:\Program Files\StartSet\managedstatekeeper.exe' --version

A user-context payload reports success but had no effect

Cause: it ran as SYSTEM in session 0 — HKCU went to SYSTEM's hive, user32 calls did nothing, or a "skip administrators" guard matched SYSTEM and the script exited 0.

Current builds do not do this: user-context payloads either run in the user's session or are marked Deferred. If you see it, either the payload is in a privileged directory (which is SYSTEM by design), or it is an .msi/.msix (packages are never routed into the user session), or the binary predates the user-context dispatch.

Fix: move per-user work into login-once, login-every or on-demand, and keep it as a script rather than a package.

Payloads are marked Deferred / Pending

Cause: the console user's session could not be reached. The log line names the reason — no active console session or a WTSQueryUserToken failed message.

Common reasons:

Reason Explanation
no active console session Nobody is signed in at the console, or the run was driven from a remote/non-interactive context
WTSQueryUserToken failed … The token did not exist yet, or the caller is not LocalSystem
… still unavailable after 60s The full token wait elapsed with no token
… not waiting again; an earlier payload in this run already waited 60s A previous payload in the same run exhausted the wait

Fix: the condition is usually transient — the next sign-in retries. If it is persistent, confirm the service runs as LocalSystem, confirm a user really is signed in at the console (not only over RDP to a different session), and do not test user-context payloads from a remote shell.

Permission validation failed

Cause: a payload in an elevated directory is not owned by SYSTEM, the built-in Administrator, Administrators, or a service SID.

Get-Acl 'C:\ProgramData\ManagedState\boot-every\Configure-Firewall.ps1' | Select-Object Owner

Fix:

icacls 'C:\ProgramData\ManagedState\boot-every\Configure-Firewall.ps1' /setowner "SYSTEM"

This is a security control, not a bug: it is what stops a standard user with write access to the directory from obtaining SYSTEM execution.

Checksum validation failed

Cause: checksum_validation is on and the payload's hash no longer matches share\checksums.yaml.

Fix: re-record after an intentional edit:

managedstatekeeper checksum "C:\ProgramData\ManagedState\login-every\Map-DepartmentDrives.ps1" --record

Remember the checksum entry is keyed by full path — a moved payload silently stops being covered.

Boot payloads never run because the network never arrived

Cause: wait_for_network is true, the network did not come up within network_timeout, and ignored_network_failure is false, so the whole run aborts with Network not available, aborting execution.

Fix: either raise network_timeout, or set ignored_network_failure: true to run anyway. Watch the key spelling — it is ignored_network_failure, with the -ed. The mis-spelled ignore_network_failure is silently ignored and leaves the default in place.

For an ad-hoc run, bypass it:

managedstatekeeper boot --skip-network

Note that "network available" means a non-loopback, non-tunnel interface that is Up with an IPv4 default gateway. A machine on an isolated VLAN with no gateway will never satisfy it.

A configuration change had no effect

Causes:

  1. The service was not restarted. Preferences are loaded once at start-up; the file watcher is not enabled in the service host.
  2. The key is misspelled. Unknown keys are ignored silently.

Fix:

Restart-Service StartSet

Then confirm Loaded preferences from C:\ProgramData\ManagedState\Config.yaml in the session log, and that the behaviour actually changed.

A payload hangs and the whole run stalls

Cause: the payload is waiting on something — a prompt, a UI, a lock. Execution is sequential, so one hung payload blocks everything after it until script_timeout (default one hour) expires and the process tree is killed.

Fix: lower script_timeout, and make payloads non-interactive. PowerShell payloads are already launched with -NonInteractive -NoProfile; batch payloads and executables are not protected in the same way. A hung msiexec is usually another installation holding the Windows Installer mutex — check for exit code 1618 in logs\installs\.

The CLI exits 0 even though something clearly went wrong

Cause: only ExecutionStatus.Failed — a payload that ran and returned non-zero — raises the exit code. A timeout, a deferral, a skipped permission or checksum check, and an unsupported extension all leave it at 0.

Fix: do not gate automation on the exit code alone. Read reports\items.json and check for current_status values other than Installed.

An MSI payload fails with 1603 / 1618 / 1638

msiexec exit codes are mapped in the log:

Code Meaning
0 Success
3010 Success, restart required — treated as success
1601 Installation service not started
1603 Fatal error during installation
1618 Another installation is already in progress
1619 Installation package could not be opened
1620 Installation package path not found
1625 Installation prohibited by policy
1638 Another version of this product is already installed

The verbose log is at C:\ProgramData\ManagedState\logs\installs\<name>_<timestamp>.log. Start there; the mapped message alone is rarely enough for a 1603.

PowerShell payload behaves differently than when you tested it

Cause: StartSet prefers PowerShell 7 (pwsh.exe) when it is installed, falling back to Windows PowerShell 5.1. It also runs with -NoProfile -NonInteractive -ExecutionPolicy Bypass, so nothing from your profile is loaded, and the working directory is the payload directory.

Fix: test the payload the same way:

pwsh.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File .\MyPayload.ps1

Log files a payload wrote are disappearing

Cause: anything sitting loose in C:\ProgramData\ManagedState\logs is treated as a log and deleted once it is 30 days old, regardless of filename.

Fix: write payload output somewhere else, or let StartSet capture it — payload stdout and stderr are folded into the session log when log_script_output is true.

The log stops mid-run with no error

Cause: the process was killed. On a machine with a scheduled restart or a forced shutdown, an in-flight session simply ends; session.json stays at "status": "running" with no end_time.

Fix: look at what was executing at the end of startset.log. A long-running package payload truncated by a reboot will be retried on the next trigger, which for a *-once payload means it was never recorded and will run again.

Reset procedures

Force every *-once payload to run again for one user:

Remove-Item 'C:\ProgramData\ManagedState\share\runonce-jsmith.json'

Force system-context *-once payloads to run again:

Remove-Item 'C:\ProgramData\ManagedState\share\runonce-system.json'

Clear one payload for one user without touching the rest:

managedstatekeeper remove-override Map-DepartmentDrives.ps1 --clear-runonce --user jsmith

Clear stale trigger files:

managedstatekeeper cleanup

Full reset of runtime state, keeping payloads:

Stop-Service StartSet
Remove-Item 'C:\ProgramData\ManagedState\share\runonce-*.json'
Remove-Item 'C:\ProgramData\ManagedState\logs' -Recurse -Force
Start-Service StartSet

Clone this wiki locally