Design for SilverMetal Windows first-boot: declarative branding build (4 layers baked offline into the WIM, shared dual-mode module), hardened onboarding kiosk (Shell Launcher v2 + Keyboard Filter for the one-time sm-bootstrap session), and the Hybrid fullscreen glass-card presentation for the Welcome app. Fills the empty Invoke-Brand stub (M4 branding). Approved in brainstorming. Next: writing-plans. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
SilverMetal Windows — First-Boot Experience & Branding
Status: design — 2026-06-09. Approved in brainstorming. Fills the
Invoke-Brandstub ininstaller/build.ps1(M4 branding milestone) and adds the hardened onboarding kiosk + branded first-boot presentation. Bound by../../../iso-builder.md,../../../hardening-spec.md, and the product principles in../../../../docs/.
1. Goal
Give SilverMetal Windows one cohesive, declaratively-built identity across every surface a user sees from power-on to desktop, and present the existing SilverOS Welcome onboarding wizard as a hardened, escape-proof, branded first-boot experience.
Everything is baked declaratively — offline registry/file servicing of the WIM in
build.ps1 plus a SYSTEM configuration step at end-of-setup. No VM capture / golden-image
(that idea remains parked).
2. Scope — three components, one initiative
| # | Component | Where it runs |
|---|---|---|
| A | Declarative branding — the four brand layers | Offline (WIM) and online (self-apply) — shared module |
| B | Hardened kiosk — Shell Launcher v2 + Keyboard Filter for the one-time sm-bootstrap session |
Build / OOBE path only |
| C | First-boot presentation — Welcome app as fullscreen Hybrid glass card | MAUI Welcome app |
Out of scope: renaming the SilverOS.* app/namespace/paths to SilverMetal (tracked as a
separate follow-up); a graphical OEM pre-boot/boot-logo splash (Secure Boot — out, per
earlier brainstorm); bit-identical reproducibility (non-goal per iso-builder.md §5).
3. Decisions locked in brainstorming
- Presentation: Hybrid — fullscreen branded backdrop + centered frosted-glass card.
- Kiosk: hardened via Shell Launcher v2 (per-user → only
sm-bootstrap), escapes disabled. - Branding: all four layers — BitLocker pre-boot message, lock/sign-in, desktop wallpaper+theme, OEM About. Custom bootloader / firmware logo OUT (Secure Boot).
- Build: declarative (
build.ps1+ offline registry). VM used only to design/verify visuals. - Aesthetic: dark "void" canvas, cyan (
#00d4ff) core mark, teal-green (#00e5a0) secondary. Mockup:.superpowers/mockups/02-branding-layers.htmland01-presentation-model.html. - Name shown to users: SilverMetal Windows on every branding surface. (The Enhanced
line is hardened Windows, not our own OS, so "SilverOS" would overclaim. The
SilverOS.*app strings are working-title leftovers → separate rename follow-up.) - Content: support URL =
https://silverlabs.uk(until a dedicated domain is locked); OEM Model = genericSilverMetal Windows; BitLocker recovery message = minimal, URL-only. - Code structure: split — shared dual-mode branding module + build-only kiosk.
4. Component A — Declarative branding (windows/branding/)
A shared, dual-mode module, mirroring the hardening/ "write once, used by ISO + self-apply"
pattern.
windows/branding/
├── Apply-Branding.ps1 # -Mode Offline -MountPath <wim mount> | -Mode Online
├── branding.manifest.json # all strings (names, URLs, OEM fields) — single source of truth
├── assets/
│ ├── lockscreen.jpg
│ ├── wallpaper.jpg
│ ├── oemlogo.bmp # ~120x120 OEM About logo
│ └── SilverMetal.theme # dark + cyan accent .theme
└── README.md
- Offline mode:
reg loadthe mounted image'sSOFTWAREandC:\Users\Default\NTUSER.DAThives, write values,reg unload(with the[gc]::Collect()+ sleep guard already used elsewhere inbuild.ps1). Stage asset files into the mounted image. - Online mode: write live
HKLM/ default-user hive and copy assets to the running system. Same value set both ways.
Layers, mechanism, lock policy
| Layer | Registry / file | Locked? |
|---|---|---|
| 1 · BitLocker pre-boot | SOFTWARE\Policies\Microsoft\FVE — pre-boot recovery message + URL policy values. Message ≈ "SilverMetal Windows. Locked out? silverlabs.uk". |
n/a (firmware) |
| 2 · Lock / sign-in | SOFTWARE\…\PersonalizationCSP lock-screen image (per-device reliable path) and SOFTWARE\Policies\Microsoft\Windows\Personalization\NoChangingLockScreen=1. Stage lockscreen.jpg to C:\Windows\Web\Screen\SilverMetal\. |
Locked |
| 3 · Wallpaper + theme | default-user NTUSER.DAT: Control Panel\Desktop\WallPaper (+ WallpaperStyle), dark mode (…\Themes\Personalize\AppsUseLightTheme=0, SystemUsesLightTheme=0), cyan accent. Stage wallpaper.jpg + SilverMetal.theme. Applies to every new account incl. the real end user. |
Changeable |
| 4 · OEM About | SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation: Manufacturer=SilverLABS, Model=SilverMetal Windows, SupportURL=https://silverlabs.uk, Logo=<oemlogo.bmp path>. |
n/a |
Honest limitation — BitLocker pre-boot (Layer 1)
Only the BitLocker recovery screen's message + URL are customizable. The normal
PIN-entry screen text ("Enter the PIN to unlock this drive") is fixed Windows UI and
cannot be branded. The mockup's branded PIN title is aspirational; Layer 1's real
deliverable is the recovery message + URL only. Exact FVE value names are pinned during
implementation (the M1 hardening 02-data-at-rest.ps1 already touches FVE for PIN enrolment).
5. Component B — Hardened kiosk (build-only)
Locks the ephemeral sm-bootstrap onboarding session so the user cannot escape the wizard.
The sm-bootstrap account, AutoLogon, and teardown already exist
(autounattend.xml,
SetupComplete.cmd, the Welcome app's ApplyService).
Offline (in build.ps1)
DISM /Enable-Feature /AllforClient-EmbeddedShellLauncher(Shell Launcher v2) andClient-KeyboardFilter, applied to the mounted WIM. (Both ship in IoT Enterprise LTSC.)- Stage
windows/installer/oem/Configure-Kiosk.ps1intoC:\Windows\Setup\Scripts\.
At end-of-setup (SetupComplete.cmd, runs as SYSTEM, after accounts exist, before first logon)
Configure-Kiosk.ps1:
- Shell Launcher v2 (WMI
WESL_UserSetting, online-only — hence configured here, not offline): default shell =explorer.exe;sm-bootstrap's shell = a small launcher that starts the Welcome app elevated (reuses the baked UAC auto-approve:ConsentPromptBehaviorAdmin=0). With no Explorer in that session there is no taskbar and no Start menu — the escape the operator saw is structurally gone. - Keyboard Filter (WMI
WEKF_PredefinedKey/WEKF_Settings): block Win, Win+L, Ctrl+Esc, and similar shell hotkeys;DisableKeyboardFilterForAdministrators=false. - Security-screen / escape policies:
DisableTaskMgr=1,DisableLockWorkstation=1, hide fast-user-switching and Log off. Applied scoped to thesm-bootstrapsession and reverted at teardown (so the real user is unaffected).
Interaction with the existing flow
- The
autounattend.xmlFirstLogonCommandsapp-launch is now redundant and removed — Shell Launcher launches the Welcome app as the session shell. SetupComplete.cmdkeeps its existing "defer hardening to Welcome when the app is present" branch; it gains theConfigure-Kiosk.ps1call.
Teardown (Welcome app ApplyService, on wizard success)
Already deletes sm-bootstrap + removes AutoLogon. Adds: remove the sm-bootstrap WESL
custom-shell entry, revert the escape policies, (optionally clear Keyboard Filter rules). The
features remain enabled but inert. The real end-user account then logs in to a normal,
branded Explorer desktop.
6. Component C — First-boot presentation (MAUI Welcome app)
The Welcome app
(windows/welcome/src/SilverOS.Welcome.App) is
MAUI Blazor (WebView2). Today its window is the plain default and MainLayout is the stock
template.
Native — window chrome
In the Windows lifecycle handler, customize the WinUI AppWindow:
OverlappedPresenterwith border + title bar off, not resizable / minimizable / maximizable; use the FullScreen presenter so it covers the whole display.- Non-closable (suppress/ignore close); Alt+F4 is additionally blocked by the Keyboard Filter. This is the only native requirement — it removes the title bar and makes the app own the screen.
Visual — Blazor + CSS only
The Hybrid look (full-bleed branded backdrop + centered frosted-glass card) is rendered
entirely in the WebView with CSS (backdrop-filter: blur(...) over the in-WebView wall),
exactly as the mockup demonstrates. No OS-level Mica/Acrylic — in a Shell-Launcher kiosk
there is no desktop behind the app to blur, so OS backdrop buys nothing.
Work: restyle MainLayout and the wizard step shell from the stock MAUI template to the brand
identity — branded backdrop, centered glass card, step rail, cyan/teal accents, the type and
motion direction from the SilverLABS aesthetic. The step components' logic is unchanged.
7. Build-flow wiring — what changes
installer/build.ps1Invoke-Brand→ callbranding\Apply-Branding.ps1 -Mode Offline -MountPath $mountand stage assets (inside the existing WIM-mounted block).installer/build.ps1→ new offline step: enable Shell Launcher + Keyboard Filter features; stageConfigure-Kiosk.ps1.installer/oem/SetupComplete.cmd→ invokeConfigure-Kiosk.ps1before first logon.installer/autounattend/autounattend.xml→ remove theFirstLogonCommandsWelcome launch.welcome/...→ fullscreen borderless window + Hybrid CSS shell;ApplyService→ kiosk teardown.
8. Testing
- Branding module: Pester tests for
Apply-Branding.ps1— offline (load a throwaway hive into a temp mount, apply, assert each value + asset staged) and online (apply, read back, revert). Runs on the Windows runner; no hardware needed. - Kiosk + presentation: the existing VM e2e harness (SLAB01 VM 102,
_stageiso.py/_pverun.py/_shot.py). Boot the built ISO → assert: no taskbar / Start in the bootstrap session, Task Manager / Win+L / Ctrl+Alt+Del options blocked, the glass card is fullscreen, the wizard completes → real user logs into a branded Explorer desktop with wallpaper, accent, locked lock-screen, and correct OEM About. - Honest scope: per
iso-builder.md §5, "reproducible" = pinned inputs + recorded tool versions + output SHA-256 + SBOM; bit-identical rebuild stays a documented stretch goal.
9. Open items (resolve during implementation, not blocking)
- Pin exact
FVEpre-boot recovery-message value names against the base media. - Confirm
PersonalizationCSPvsPolicies\…\Personalization\LockScreenImagereliability on IoT Enterprise LTSC 24H2/25H2; pick the one that survives a clean OOBE. - Decide whether
Configure-Kiosk.ps1sets thesm-bootstrapshell to the app directly (withrequireAdministratormanifest) or to an elevating launcher script — pick the robust one during the elevation spike. - Final logo asset (
oemlogo.bmp, lock-screen, wallpaper) — placeholder void/cyan mark used until brand identity is finalized (shared/branding/README.mdis still "to be defined"). - Separate follow-up: rename
SilverOS.*app / namespace / install path to SilverMetal.