Skip to content

Payload Directories

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

Payload directories

Every payload directory is a flat folder under C:\ProgramData\ManagedState. A file dropped in one becomes a payload; there is no manifest, no registration and no ordering file.

The nine directories

Directory Payload type Runs as Elevated Once Deleted after run
boot-once BootOnce Service account (LocalSystem) yes yes yes, on success
boot-every BootEvery Service account (LocalSystem) yes no no
login-window LoginWindow Service account (LocalSystem) yes no no
login-once LoginOnce Console user no yes, per user no
login-every LoginEvery Console user no no no
login-privileged-once LoginPrivilegedOnce Service account (LocalSystem) yes yes, per machine no
login-privileged-every LoginPrivilegedEvery Service account (LocalSystem) yes no no
on-demand OnDemand Console user no no no
on-demand-privileged OnDemandPrivileged Service account (LocalSystem) yes no no

"Runs as console user" means StartSet impersonates the interactive session — see Windows Session Model. Everything else runs in the service's own LocalSystem context in session 0 (or, when you invoke the CLI by hand, in whatever context you invoked it from).

The per-machine tracking of login-privileged-once is a deliberate consequence of how the tracker is selected: the engine uses a per-user ledger only for payload types flagged as user context (login-once, login-every, on-demand). login-privileged-once is not one of them, so it is recorded in runonce-system.json and fires once per machine, not once per user. This differs from outset — see Coming From Outset.

Supporting directories and files

Path Contents
share\ Run-once ledgers, checksums.yaml, and a general-purpose shared data directory
share\runonce-system.json Run-once ledger for system-context once payloads
share\runonce-<username>.json Run-once ledger for one user's login-once payloads
share\checksums.yaml Recorded SHA256 checksums, used when checksum_validation is on
Config.yaml Configuration — see Configuration
logs\ Day-nested session logs — see Logging and Reporting
logs\installs\ Verbose msiexec /l*v logs from .msi payloads
reports\ Machine-readable sessions.json, events.json, items.json, run.log

What counts as a payload

Discovery is Directory.GetFiles(directory) — top level only. Subdirectories are not walked. A script tucked into login-every\MyApp\Setup.ps1 will never run and nothing will report it as missing; this is the single most common cause of "the package installed but nothing happened".

A file is a payload only if its extension is in allowed_extensions, which defaults to:

Extension Handled by
.ps1 PowerShell processor — pwsh if present, otherwise Windows PowerShell
.cmd, .bat cmd.exe /c
.exe started directly
.msi msiexec /i … /qn /norestart /l*v
.msix Add-AppxPackage -ForceApplicationShutdown

Anything else in the directory is ignored silently — including .txt notes, .json sidecars and .psm1 modules. If you need a module alongside a script, keep it outside the payload directory and load it by absolute path.

Execution order

Within one directory, payloads run sequentially in case-insensitive alphabetical order by filename. Number your files if order matters:

10-Set-Registry.ps1
20-Map-Drives.ps1
90-Cleanup.ps1

parallel_execution exists as a configuration key but is not implemented; setting it logs a warning and execution stays sequential.

Across directories, the order is fixed by the trigger — see Architecture.

Run-once semantics

For boot-once, login-once and login-privileged-once, the engine consults the ledger before running a payload, and records it afterwards:

  • The ledger key is the lowercased filename, not the full path. Moving a script between payload directories does not make it run again.
  • Only a successful run is recorded, and HasExecuted returns the recorded success value — so a payload that failed will be retried on the next trigger.
  • The recorded SHA256 is compared on every check. Editing a script makes it run again, which is how you re-issue a once payload without touching the ledger.
  • A filename listed in overrides bypasses the check entirely and runs every time.
  • boot-once payloads are additionally deleted from disk after a successful run.

managedstatekeeper list --show-executed shows the current state; remove --clear-runonce and remove-override --clear-runonce clear ledger entries. See CLI Reference.

Permissions

Payloads in an elevated directory (boot-*, login-window, login-privileged-*, on-demand-privileged) are permission-checked before execution. The file's owner must be one of:

Owner SID
SYSTEM S-1-5-18
The built-in Administrator account any SID ending -500
Administrators S-1-5-32-544
TrustedInstaller and other service SIDs any SID starting S-1-5-80-

A file owned by anyone else is skipped with Permission validation failed, which is what stops a standard user from dropping a script into boot-every and getting SYSTEM execution. Payloads in user-context directories are only checked for readability.

Ownership, not ACLs, is the test — copying a script into place as an administrator normally satisfies it, but a file extracted from an archive by a standard user will not.

Trigger files

Four sentinel files at the root of C:\ProgramData\ManagedState ask the running service to do something. The service's FileSystemWatcher matches .startset.* and acts on creation, then deletes the file.

File Effect
.startset.ondemand Run on-demand payloads
.startset.ondemand-privileged Run on-demand-privileged payloads
.startset.login-privileged Allow login-privileged-once payloads to run at the next logon
.startset.cleanup Delete the trigger files

Content is irrelevant; existence is the signal.

New-Item -ItemType File 'C:\ProgramData\ManagedState\.startset.ondemand' -Force

Existing trigger files are also processed once when the service starts, so one dropped while the service was stopped is not lost.

login-privileged-every runs at every logon with no trigger file needed. Only the -once half is gated by .startset.login-privileged.

Clone this wiki locally