Skip to content

Autopilot and the ESP

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

Autopilot and the ESP

BootstrapMate is usually deployed to run during Windows Autopilot provisioning. This page describes what that window actually looks like on the device, and — more importantly — what BootstrapMate does and does not know about it.

OOBE and the ESP

The Out-of-Box Experience (OOBE) is the first-boot sequence a Windows device runs before anyone has a desktop: region and keyboard, network, and then, on an Autopilot-registered device, Entra ID join and MDM enrolment.

The Enrollment Status Page (ESP) is the blocking screen Intune shows during and just after that. It has two phases. The device phase runs before any user signs in; everything installed here runs in the SYSTEM context and there is no user profile, no interactive desktop, and no HKCU for a real user. The user phase runs after the first sign-in, once a user token and profile exist. Intune decides when each phase is complete based on the apps you have marked as blocking.

For BootstrapMate's purposes, what matters is that the device phase has no user session and the user phase does.

BootstrapMate performs no OOBE or ESP detection

Stated plainly, because it is easy to assume otherwise: there is no OOBE detection, no ESP detection and no enrolment detection anywhere in the codebase. Nothing probes for an ESP registry key, nothing looks for the ESP shell process, nothing tests for session 0, and nothing waits for a user to log in.

The two manifest phases, setupassistant and userland, are labels within a single process run. ProcessManifest runs every setupassistant item and then immediately runs every userland item, in the same await chain, in the same process, under the same token. There is no pause between them and no second invocation.

ManagementDetector, despite its name, detects managed settings — values under HKLM\SOFTWARE\Policies\BootstrapMate. It does not detect MDM enrolment or provisioning state.

So the device-phase versus user-phase distinction comes entirely from when you invoke the CLI, not from any branch inside it.

What this means in practice

The MSI's install-time run is fired through the BootstrapMate Self-Heal scheduled task, which is registered /RU SYSTEM. The daily 03:00 run uses the same task. In both cases both phases execute as SYSTEM. If you deploy the MSI as a device-context Win32 app during the ESP device phase, your userland items run as SYSTEM before any user has signed in.

Guidance that follows from that:

  • Treat userland as "second", not as "in a user session". Anything that genuinely needs an interactive user token, a user profile, or HKCU will not get one from a SYSTEM-context run. Deliver that work through a different mechanism — a logon task, a user-context Intune app, or a per-user configuration policy — and use userland for ordering only.
  • If you want a run that really is in the user's context, invoke managedbootstrapinstall.exe yourself at that point, elevated, with a manifest whose setupassistant array is absent so that phase is marked Skipped.
  • Keep ESP-blocking work bounded. The MSI's custom action starts the scheduled task and ignores its result, so the MSI can finish while packages are still installing. If you mark the app as blocking, ESP will pass as soon as the MSI completes and its detection rule matches — not when the manifest has finished. See Deployment for what the shipped detection scripts actually detect.
  • Do not rely on a reboot. There is no pending-reboot detection, no resume-after-reboot state machine, and no reboot handling of any kind. /norestart is passed to every MSI install, and the Reboot setting is never read. The only thing that resumes work is the daily task re-running the entire manifest.
  • Expect signature checks to work offline-ish. Authenticode verification runs with revocation checking deliberately disabled, because OCSP and CRL fetches are unreliable on the partly configured network of an OOBE session. See Security and Package Verification.
  • Never put an interactive flag in an ESP invocation. --reset-chocolatey and the unelevated-startup path both call Console.ReadLine() and will block forever under a scheduled task.

The macOS equivalent

On macOS the same window is Setup Assistant plus the MDM bootstrap, and the sibling tool uses the same setupassistant and userland vocabulary — that vocabulary is inherited from InstallApplications on the Mac side. The macOS implementation handles the phase split differently, so read that page before assuming behaviour carries across:

https://github.com/bootstrapmate/bootstrapmate-macintosh/wiki/Setup-Assistant-and-MDM-Bootstrap

See also

Clone this wiki locally