Repository navigation
Package Delivery
StartSet has no transport of its own. It executes what it finds in
C:\ProgramData\ManagedState\<payload-directory>; getting files there is somebody else's job —
an MSI, a managed-install package, an Intune app, Group Policy, a configuration-management run, or
managedstatekeeper add.
This page covers what a delivery mechanism has to get right for StartSet to actually pick the payload up, and documents the packaging convention this repository itself uses.
| Requirement | Why |
|---|---|
| The file lands directly in the payload directory | Discovery is top level only; subdirectories are never walked |
The extension is in allowed_extensions
|
.ps1 .cmd .bat .exe .msi .msix by default; anything else is ignored silently |
| For an elevated directory, the file's owner is SYSTEM / Administrator / Administrators / a service SID | Ownership check; otherwise the payload is skipped with Permission validation failed
|
| The filename sorts where you want it to run | Case-insensitive alphabetical within the directory |
| The filename is stable | The run-once ledger keys on the lowercased filename; renaming a *-once payload makes it run again |
The first two are where deliveries go wrong. A package that lays down
login-every\MyTool\Configure.ps1 produces a payload directory that looks populated and a
StartSet run that does nothing and reports nothing missing.
This repository packages StartSet itself with cimipkg, and the same layout is how you would
package a payload for a StartSet directory. A package source directory looks like:
mypackage/
├── build-info.yaml
├── payload/
└── scripts/
├── preinstall.ps1
└── postinstall.ps1
build-info.yaml names the product and, critically, the destination:
product:
name: StartSet
version: 2026.03.01.1030
developer: Windows Admins Open Source
identifier: com.github.windowsadmins.startset
description: Automatically process packages and scripts during boot, login, or on demand on Windows.
architecture: x64
install_location: C:\Program Files\StartSetThe contents of payload/ are laid down at install_location. StartSet's own package puts
managedstatekeeper.exe and StartSetService.exe flat inside payload/ with
install_location: C:\Program Files\StartSet, and they arrive as
C:\Program Files\StartSet\managedstatekeeper.exe.
To deliver a StartSet payload, point install_location at the payload directory and put the
script flat in payload/:
product:
name: DepartmentDriveMap
version: 2026.03.01.0900
developer: Example Org
identifier: com.example.departmentdrivemap
description: Maps department drives at every user logon.
architecture: x64
install_location: C:\ProgramData\ManagedState\login-everydepartmentdrivemap/
├── build-info.yaml
└── payload/
└── Map-DepartmentDrives.ps1
That produces C:\ProgramData\ManagedState\login-every\Map-DepartmentDrives.ps1.
Because the payload tree is laid down at install_location, the leaf directory must appear in
exactly one of the two — never both. This layout:
payload/
└── login-every/
└── Map-DepartmentDrives.ps1
combined with install_location: C:\ProgramData\ManagedState\login-every produces
...\login-every\login-every\Map-DepartmentDrives.ps1. The package installs cleanly, reports
success, and the script never runs. Pick one convention:
| Convention | install_location |
payload/ contents |
|---|---|---|
| Flat | the payload directory | the script |
| Nested | C:\ProgramData\ManagedState |
login-every\Map-DepartmentDrives.ps1 |
When you cannot tell which one a package used, look for the file on a target machine rather than trusting the install status:
Get-ChildItem C:\ProgramData\ManagedState -Recurse -Filter *.ps1 | Select-Object FullNamescripts\preinstall.ps1 runs before the payload is laid down, scripts\postinstall.ps1 after.
StartSet's own package uses them to stop the service before replacing binaries and to create the
directory tree, register the service and start it afterwards.
Write their output to stdout and let the packaging tool capture it — that is the record that gets
collected. StartSet's own scripts used to Start-Transcript into a file under the data directory,
which diverted the output away from that capture: the file sat where nothing reads it and the
session log recorded nothing at all.
Both scripts must exit 0 on success; a non-zero exit fails the install.
Two shapes are possible, and they behave very differently.
An MSI that installs a payload file into C:\ProgramData\ManagedState\login-every and then
exits. StartSet picks the file up at the next matching trigger, in the right context. This is
usually what you want.
An .msi file placed inside a payload directory. StartSet then treats it as a payload and
installs it with msiexec /i … /qn /norestart /l*v. Note that package payloads are not routed
through the user session — an MSI in login-every installs as the service account in session 0.
Exit codes 0 and 3010 count as success; anything else is a failure with the mapped message.
Verbose installer logs go to C:\ProgramData\ManagedState\logs\installs\<name>_<timestamp>.log
and are aged out with the same 30-day retention as everything else.
build.ps1 -IntuneWin wraps the MSI (or, failing that, the binaries) with IntuneWinAppUtil.exe
into a .intunewin. The same wrapping approach works for a payload package. Nothing in StartSet
reads Intune state; from its point of view the file either appeared in the directory or it did not.
For elevated payload directories, remember the ownership check. Files laid down by an installer
running as SYSTEM are owned by SYSTEM or Administrators and pass. Files copied in by a standard
user, or extracted from an archive by one, are owned by that user and are skipped. If a payload is
being skipped for Permission validation failed, check the owner:
Get-Acl 'C:\ProgramData\ManagedState\boot-every\Configure-Firewall.ps1' | Select-Object Ownericacls 'C:\ProgramData\ManagedState\boot-every\Configure-Firewall.ps1' /setowner "SYSTEM"For *-every payloads, just replace the file.
For *-once payloads, the run-once ledger keys on the lowercased filename and records the SHA256.
Replacing the file with different content is enough to make it run again — the checksum no longer
matches and the ledger reports it as not executed. Keeping the same filename with the same content
will not re-run it, and a delivery that "succeeded" will produce no StartSet activity at all. If
you need a byte-identical payload to run again, use an override:
managedstatekeeper add-override Map-DepartmentDrives.ps1Or clear the ledger entry:
managedstatekeeper remove-override Map-DepartmentDrives.ps1 --clear-runonce --user jsmithDeleting the file stops it running. It does not remove the run-once ledger entry, so
re-delivering the same filename later will find it already recorded. Use
managedstatekeeper remove <name> --type <type> --clear-runonce to do both.
boot-once payloads delete themselves from disk after a successful run, so a redelivery of the
same filename with the same content will be blocked by the ledger rather than by the file's
presence.
StartSet — MIT licensed — windowsadmins/startset — a Windows port of macadmins/outset.
StartSet
How it works
Migrating
Operating
Contributing