Skip to content

How It Works

Rod Christiansen edited this page Sep 5, 2026 · 2 revisions

How It Works

This page describes what actually happens during a run, in order. Read it when a run did something you did not expect and you need to know which step could have produced that behaviour.

1. Invocation

A run is one execution of managedbootstrapinstall.exe. Nothing is resident between runs. There are three ways a run starts on a managed device: the MSI triggers one at InstallFinalize, the BootstrapMate Self-Heal scheduled task starts one daily at 03:00 as SYSTEM, and you can start one by hand or from your MDM.

Before any argument parsing, the process prunes logs older than 30 days, deletes phase status entries whose CompletionTime is more than 24 hours old, and empties the download cache directory entirely. Then --version/-V is honoured if and only if it is the first argument; --silent and --verbose/-v are picked up from anywhere in the argument list.

Next comes the administrator check. Elevated, the run continues. Unelevated and interactive, it offers a UAC relaunch. Unelevated with --silent, it refuses to raise UAC and returns 1. Finally the run takes the global single-instance mutex; if another run holds it, this one waits up to 30 minutes and then gives up with exit code 1.

2. Manifest fetch

The manifest URL comes from --url if you passed one — that value bypasses the settings system entirely. Otherwise it is resolved through the precedence chain in Preferences: the URL baked into the binary, then HKCU settings, then HKLM settings, then the policy key HKLM\SOFTWARE\Policies\BootstrapMate, highest wins. Because the baked-in default is non-empty and the MSI writes a machine-level value, a URL is effectively always resolvable.

The manifest is fetched with a default HttpClient — a 100-second timeout, redirects followed. The NetworkTimeout and FollowRedirects settings do not affect this; see Troubleshooting and Gotchas. If an AuthorizationHeader is configured it is sent with the manifest request, and the manifest URL's host is remembered as the run's authorised host.

The response is parsed as JSON, or as YAML when the URL path ends .yaml/.yml or the content does not start with { or [. A parse or download failure ends the run with exit code 1.

3. Phase ordering

The two phases run in a fixed order — setupassistant first, then userlandin the same process, in the same run, with no wait in between. A phase whose root key is missing from the manifest is recorded as Skipped.

Within each phase the items are reordered before execution. Items are grouped by type: msi and exe first, then nupkg, then ps1/powershell, then anything else. Scripts whose name contains a cleanup-sounding word run last of all. Manifest order is preserved inside each group. This is logged as Optimizing package installation order to prevent dependency conflicts. There is no dependency graph — if item B needs item A, the order is not guaranteed by the manifest alone.

If the optional progress dialog is available, every item from both phases is listed in it before the first install starts. That listing reads name from each item, so a single item missing name aborts the run before anything installs.

Where the device/user split actually comes from

There is no OOBE or Enrollment Status Page (ESP) detection anywhere in this product. The code does not probe enrollment state, does not test for a user session, does not wait for logon, and does not resume across a reboot. setupassistant and userland are labels for two lists in one process.

What makes the split real is when the run is invoked. The MSI's install-time trigger fires during the ESP, so those items land in the device phase; the daily SYSTEM task keeps the manifest converging afterwards. In both cases the process runs as SYSTEM, so userland items also execute as SYSTEM and not in a user's session. If you need something to run in a logged-in user's context, BootstrapMate is not the mechanism — put it in the ongoing management tool. This differs from macOS, where the stage names correspond to genuinely different points in provisioning; see Stages.

4. Per-item download and install

For each item, in order:

  1. Condition. If condition contains architecture_x64 or architecture_arm64 and the OS architecture does not match, the item is skipped and logged [SKIPPED]. Any other condition text is ignored — it is a substring test, not an expression language.
  2. Cache. Any existing cached copy of file is deleted first. Downloads are always fresh.
  3. Download. The Authorization header is attached only when the item's URL host matches the manifest host; otherwise it is withheld and the omission is logged at Debug. A non-2xx response produces Download failed: {StatusCode}.
  4. Signature. msi and exe items are verified with WinVerifyTrust when VerifyPackageSignatures is on, which is the default. Revocation checking is deliberately disabled, because OCSP and CRL are unreliable during OOBE. An untrusted signature can be permitted with allowUnsigned; a publisher mismatch is always refused. ps1, nupkg and pkg items are not signature-gated. See Security and Package Verification.
  5. Install. Dispatch by typemsiexec for MSI, the executable itself for EXE, powershell.exe for scripts, sbin-installer or Chocolatey for nupkg, sbin-installer for pkg. Details and per-type exit-code handling are in Item Types.
  6. Cleanup. On success the cached file is deleted. On failure it is kept on purpose, with Keeping cached file for inspection. A non-empty C:\ProgramData\ManagedBootstrap\cache therefore means something failed.

5. Retry handling

Retries exist for MSI installs only. A normal MSI gets up to 5 attempts, 10 seconds apart, and only for the retryable exit codes 1603, 1619, 1620 and 1612. An sbin-installer package is treated as critical: up to 10 attempts, 15 seconds apart, retried on any error.

Exit code 1618 — another Windows Installer transaction in progress — is not a failure. The run waits on the installer mutex before each attempt, and a 1618 result backs off and retries without consuming the retry budget, up to 30 collisions. Colliding with the Intune Management Extension is expected and benign.

PowerShell, EXE, sbin-installer and Chocolatey items are not retried. The first non-zero exit fails the item.

A failed item does not abort the run. The exception is caught, logged as Failed to install package {name}: {msg}, and the loop moves to the next item. See Retries and Timeouts.

6. Status and registry writes

Each phase writes its own key under HKLM\SOFTWARE\Cimian\BootstrapMate\Status\, in both the 64-bit and 32-bit registry views, carrying Stage, StartTime, CompletionTime, ExitCode, Phase, Architecture, BootstrapUrl, LastError and RunId. The same information is mirrored to C:\ProgramData\ManagedBootstrap\status.json. A run that completes without an unhandled exception writes LastRunVersion to HKLM\SOFTWARE\Cimian\BootstrapMate.

If ReportingUrl is configured, a JSON run summary is POSTed from both the success and failure paths. Reporting never fails the run. See Logging and Reporting.

7. Exit

Exit code 0 does not mean every item installed. Per-item failures are caught and swallowed so the run can continue, so a run in which every single item failed still exits 0, still writes Stage=Completed, and still writes LastRunVersion. Exit code 1 is reserved for things that stop the run outright: not elevated, no resolvable manifest URL, a manifest that would not download or parse, an unhandled exception, or a 30-minute wait on another instance.

To know whether a run actually worked, check three things rather than the exit code: count Failed to install package lines in the newest log under C:\ProgramData\ManagedBootstrap\logs; confirm Stage is Completed on both phase keys under HKLM\SOFTWARE\Cimian\BootstrapMate\Status\; and confirm C:\ProgramData\ManagedBootstrap\cache is empty.

See also

Clone this wiki locally