Files
SilverMetal/windows/installer/autounattend/autounattend.xml
sysadmin 30a168e853
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m46s
perf(welcome): cut first-boot cold-start + add loading affordance
The Welcome wizard showed nothing until WebView2 cold-started and Blazor
booted, so the whole startup cost presented as a blank window long enough
that operators thought first boot had failed.

- Native MAUI splash overlay (renders in the first frame, no WebView2/JIT
  dependency) + a visually identical in-page splash inside #app, so the
  native -> webview -> Blazor handoff reads as one continuous loading
  screen. Fades out on first successful WV2 NavigationCompleted.
- PublishReadyToRun=true (publish-only) to remove first-run JIT on the
  one-shot cold-disk path. R2R header verified present after publish.
- Fixed-version WebView2 runtime baked offline next to the exe (build.ps1
  stages it, app points WEBVIEW2_BROWSER_EXECUTABLE_FOLDER at it). Removes
  the Evergreen registry probe and the LTSC "no WebView2 at all" risk flagged
  in welcome-app-spec.md; air-gap friendly. Absent => falls back to Evergreen.
- De-flash launch: drop the `cmd /c` wrapper and add -WindowStyle Hidden in
  autounattend FirstLogonCommands (kills the console flash + one process).

Verified: Release build clean, win-x64 self-contained publish succeeds with
R2R confirmed, 38/38 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 09:06:02 +01:00

147 lines
7.6 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!--
SilverMetal Enhanced - Windows : Windows 11 IoT Enterprise LTSC answer file.
Automates OOBE, wipes disk 0 to a clean GPT/UEFI layout, installs the LTSC
image (index 1), forces a LOCAL account (no Microsoft Account / no cloud key
escrow), and hands off to C:\Windows\Setup\Scripts\SetupComplete.cmd (run
automatically as SYSTEM at end of setup) for the §A-H hardening.
SECURITY NOTE: the bootstrap local-admin password below is a PLACEHOLDER for
unattended setup only. The shippable SKU pipeline MUST inject a per-device
credential (or force change at first logon); never ship this value.
Design: ../../iso-builder.md Controls: ../../hardening-spec.md (domains A, C)
-->
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="windowsPE">
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<SetupUILanguage><UILanguage>en-US</UILanguage></SetupUILanguage>
<InputLocale>0809:00000809</InputLocale>
<SystemLocale>en-GB</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-GB</UserLocale>
</component>
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<DiskConfiguration>
<WillShowUI>OnError</WillShowUI>
<Disk wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
<CreatePartitions>
<CreatePartition wcm:action="add"><Order>1</Order><Type>EFI</Type><Size>300</Size></CreatePartition>
<CreatePartition wcm:action="add"><Order>2</Order><Type>MSR</Type><Size>16</Size></CreatePartition>
<CreatePartition wcm:action="add"><Order>3</Order><Type>Primary</Type><Extend>true</Extend></CreatePartition>
</CreatePartitions>
<ModifyPartitions>
<ModifyPartition wcm:action="add"><Order>1</Order><PartitionID>1</PartitionID><Label>System</Label><Format>FAT32</Format></ModifyPartition>
<ModifyPartition wcm:action="add"><Order>2</Order><PartitionID>2</PartitionID></ModifyPartition>
<ModifyPartition wcm:action="add"><Order>3</Order><PartitionID>3</PartitionID><Label>Windows</Label><Format>NTFS</Format><Letter>C</Letter></ModifyPartition>
</ModifyPartitions>
</Disk>
</DiskConfiguration>
<ImageInstall>
<OSImage>
<InstallTo><DiskID>0</DiskID><PartitionID>3</PartitionID></InstallTo>
<InstallFrom>
<MetaData wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<Key>/IMAGE/INDEX</Key><Value>1</Value>
</MetaData>
</InstallFrom>
</OSImage>
</ImageInstall>
<UserData>
<!-- IoT Enterprise LTSC eval media is pre-pidded; no product key required. -->
<AcceptEula>true</AcceptEula>
</UserData>
</component>
</settings>
<settings pass="oobeSystem">
<!-- Pre-answer the OOBE region/keyboard pages (CloudExperienceHost). Without
International-Core in the oobeSystem pass, 24H2 OOBE prompts for these
interactively even under legacy Setup. -->
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<InputLocale>0809:00000809</InputLocale>
<SystemLocale>en-GB</SystemLocale>
<UILanguage>en-US</UILanguage>
<UILanguageFallback>en-US</UILanguageFallback>
<UserLocale>en-GB</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<ProtectYourPC>3</ProtectYourPC>
</OOBE>
<UserAccounts>
<LocalAccounts>
<!--
sm-bootstrap: ephemeral one-time admin account used ONLY for the
SilverOS Welcome onboarding wizard. The Welcome app's ApplyService
tears this account down on success (removes AutoAdminLogon registry
keys, deletes the account, and creates the real end-user account
instead). Never ship this password as-is for end-users; the
production pipeline MUST inject a per-device credential.
-->
<LocalAccount wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<Name>sm-bootstrap</Name>
<Group>Administrators</Group>
<DisplayName>SilverOS Bootstrap</DisplayName>
<Password><Value>bootstrap-OneTime!</Value><PlainText>true</PlainText></Password>
</LocalAccount>
</LocalAccounts>
</UserAccounts>
<!--
AutoLogon: logs in as sm-bootstrap exactly once so FirstLogonCommands can
launch the Welcome wizard. After the wizard completes successfully,
ApplyService removes the AutoAdminLogon registry values and deletes
sm-bootstrap, so the one-time session cannot be re-entered.
-->
<AutoLogon>
<Enabled>true</Enabled>
<LogonCount>1</LogonCount>
<Username>sm-bootstrap</Username>
<Password><Value>bootstrap-OneTime!</Value><PlainText>true</PlainText></Password>
</AutoLogon>
<!--
Launch the Welcome wizard ELEVATED over the (locked-down) Explorer session.
Explorer stays the shell so the MAUI/WebView2 wizard renders (it does NOT
render when launched as a bare Shell Launcher shell). Configure-Kiosk.ps1
bakes the silent-elevation UAC policy + the lockdown (Keyboard Filter,
DisableTaskMgr, hidden taskbar); the wizard runs fullscreen-topmost on top.
Launch is via a single hidden-window PowerShell (no `cmd /c` wrapper): the
old `cmd /c powershell ...` spawned an extra process AND flashed a visible
console window on the bare first-boot desktop — which itself read as "the
machine is doing something broken" before the wizard appeared. `-WindowStyle
Hidden` + dropping the cmd shim removes that flash and one process off the
critical path. Elevation (-Verb RunAs) is still required for ApplyService
(account/BitLocker/hardening) and is silent thanks to the baked UAC policy.
-->
<FirstLogonCommands>
<SynchronousCommand wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<Order>1</Order>
<CommandLine>powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command "Start-Process -FilePath 'C:\Program Files\SilverOS\Welcome\SilverOS.Welcome.App.exe' -Verb RunAs"</CommandLine>
<Description>Launch SilverOS Welcome elevated</Description>
</SynchronousCommand>
</FirstLogonCommands>
<RegisteredOwner>SilverMetal</RegisteredOwner>
<RegisteredOrganization>SilverLABS</RegisteredOrganization>
<!--
Hardening runs from C:\Windows\Setup\Scripts\SetupComplete.cmd, which
Windows Setup executes automatically (as SYSTEM) at the end of setup.
-->
</component>
</settings>
</unattend>