-
Notifications
You must be signed in to change notification settings - Fork 1
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.
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.
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.
The two phases run in a fixed order — setupassistant first, then userland — in 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.
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.
For each item, in order:
-
Condition. If
conditioncontainsarchitecture_x64orarchitecture_arm64and the OS architecture does not match, the item is skipped and logged[SKIPPED]. Any otherconditiontext is ignored — it is a substring test, not an expression language. -
Cache. Any existing cached copy of
fileis deleted first. Downloads are always fresh. -
Download. The
Authorizationheader 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 producesDownload failed: {StatusCode}. -
Signature.
msiandexeitems are verified withWinVerifyTrustwhenVerifyPackageSignaturesis on, which is the default. Revocation checking is deliberately disabled, because OCSP and CRL are unreliable during OOBE. An untrusted signature can be permitted withallowUnsigned; a publisher mismatch is always refused.ps1,nupkgandpkgitems are not signature-gated. See Security and Package Verification. -
Install. Dispatch by
type—msiexecfor MSI, the executable itself for EXE,powershell.exefor scripts, sbin-installer or Chocolatey fornupkg, sbin-installer forpkg. Details and per-type exit-code handling are in Item Types. -
Cleanup. On success the cached file is deleted. On failure it is kept on purpose, with
Keeping cached file for inspection. A non-emptyC:\ProgramData\ManagedBootstrap\cachetherefore means something failed.
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.
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.
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.