Generalize the base image from audit mode, with hibernation off

The answer file now boots into audit mode after Setup instead of logging on
as the built-in Administrator with a password: no account or credentials in
the answer file, and no copy of one left in C:\Windows\Panther. The auditUser
commands disable the built-in Administrator, turn hibernation off (no
hiberfil.sys in the image), remove cached answer files and setup logs, and run
sysprep /generalize.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-11-02 12:51:54 +08:00
1 parent cb01d2c120
commit 9c5abac9bf
3 files changed
+36 -49

No files matched your search

+3 -3
View File
@@ -117,9 +117,9 @@ does not run Windows Setup again. `build-windows-base.sh` makes that base image
(by default at the path `./download-images.sh --print-path windows11` prints): it (by default at the path `./download-images.sh --print-path windows11` prints): it
installs Windows unattended from the ISO in `install-iso/` (it does everything installs Windows unattended from the ISO in `install-iso/` (it does everything
itself: answer file in `windows11/seed/`, QEMU hardware in `windows11/qemu/`; this itself: answer file in `windows11/seed/`, QEMU hardware in `windows11/qemu/`; this
directory has no dependency on any other repository). The answer file logs on once directory has no dependency on any other repository). The answer file boots
with the built-in Administrator, which it disables again, and runs into audit mode (no account and no credentials are needed) and runs
`sysprep /generalize` as its last step; the script waits for the guest to power `sysprep /generalize` there as its last step; the script waits for the guest to power
off and stores the disk read-only. The image is clean and generic, like a cloud off and stores the disk read-only. The image is clean and generic, like a cloud
image: nothing but Windows, with no account, no SSH, no settings, no VirtIO or image: nothing but Windows, with no account, no SSH, no settings, no VirtIO or
other hardware-specific drivers and no machine identity. Each VM is configured other hardware-specific drivers and no machine identity. Each VM is configured
+4 -3
View File
@@ -6,13 +6,14 @@
# made once, and this script needs nothing outside this directory: # made once, and this script needs nothing outside this directory:
# 1. an answer ISO is built from windows11/seed/Autounattend.xml; # 1. an answer ISO is built from windows11/seed/Autounattend.xml;
# 2. QEMU installs Windows unattended from the ISO into a scratch directory. # 2. QEMU installs Windows unattended from the ISO into a scratch directory.
# After the first logon, the answer file runs sysprep /generalize, which # The answer file then boots into audit mode, where it runs sysprep
# removes the machine identity and shuts the guest down; # /generalize, which removes the machine identity and shuts the guest down;
# 3. the shut-down disk is converted into the output file and made read-only. # 3. the shut-down disk is converted into the output file and made read-only.
# The image holds nothing but Windows itself, like a cloud image: no VirtIO or # The image holds nothing but Windows itself, like a cloud image: no VirtIO or
# other hardware-specific drivers (the installation hardware, windows11/qemu, # other hardware-specific drivers (the installation hardware, windows11/qemu,
# only uses devices with inbox Windows drivers), no machine identity, no user # only uses devices with inbox Windows drivers), no machine identity, no user
# account (the built-in Administrator is disabled), no SSH, no settings. Every # account (the answer file holds no credentials either: audit mode needs no
# account; the built-in Administrator is disabled), no SSH, no settings. Every
# VM is configured on its first boot: Windows looks for an Unattend.xml in the # VM is configured on its first boot: Windows looks for an Unattend.xml in the
# root of an attached CD-ROM during its specialize and OOBE passes, and so # root of an attached CD-ROM during its specialize and OOBE passes, and so
# takes the host name, account, auto logon, SSH and so on from a seed ISO. # takes the host name, account, auto logon, SSH and so on from a seed ISO.
+29 -43
View File
@@ -96,59 +96,45 @@
</RunSynchronous> </RunSynchronous>
</component> </component>
</settings> </settings>
<!-- After Setup, boot into audit mode instead of OOBE: Windows logs on as the
built-in Administrator (no password, no account is created) and runs the
auditUser commands below, the last of which generalizes the image and powers
off. So the answer file holds no credentials. -->
<settings pass="oobeSystem"> <settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<InputLocale>en-US</InputLocale> <Reseal>
<SystemLocale>en-US</SystemLocale> <Mode>Audit</Mode>
<UILanguage>en-US</UILanguage> </Reseal>
<UserLocale>en-US</UserLocale>
</component> </component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" </settings>
<settings pass="auditUser">
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<OOBE> <RunSynchronous>
<HideEULAPage>true</HideEULAPage> <RunSynchronousCommand wcm:action="add">
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<ProtectYourPC>3</ProtectYourPC>
</OOBE>
<!-- The built-in Administrator only exists to log on once and run sysprep; it
is disabled again before that, and the password is a throwaway. -->
<UserAccounts>
<AdministratorPassword>
<Value>Build-Only-1</Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
<AutoLogon>
<Enabled>true</Enabled>
<LogonCount>1</LogonCount>
<Username>Administrator</Username>
<Password>
<Value>Build-Only-1</Value>
<PlainText>true</PlainText>
</Password>
</AutoLogon>
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<Order>1</Order> <Order>1</Order>
<Description>Disable the built-in Administrator again</Description> <Description>Disable the built-in Administrator again</Description>
<CommandLine>net.exe user Administrator /active:no</CommandLine> <Path>net.exe user Administrator /active:no</Path>
</SynchronousCommand> </RunSynchronousCommand>
<SynchronousCommand wcm:action="add"> <RunSynchronousCommand wcm:action="add">
<Order>2</Order> <Order>2</Order>
<Description>Remove the cached copies of this answer file (Windows would read <Description>Turn hibernation off, which deletes hiberfil.sys (3 GB) from the image</Description>
them before the Unattend.xml on a seed ISO, and one has the build password) <Path>powercfg.exe /hibernate off</Path>
and the setup logs</Description> </RunSynchronousCommand>
<CommandLine>cmd.exe /c "del /f /q C:\Windows\Panther\unattend*.xml C:\Windows\Panther\Unattend\unattend*.xml C:\Windows\Panther\*.log &amp; rd /s /q C:\Windows\Panther\UnattendGC &amp; exit /b 0"</CommandLine> <RunSynchronousCommand wcm:action="add">
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>3</Order> <Order>3</Order>
<Description>Remove the cached copies of this answer file (Windows would read
them before the Unattend.xml on a seed ISO) and the setup logs</Description>
<Path>cmd.exe /c "del /f /q C:\Windows\Panther\unattend*.xml C:\Windows\Panther\Unattend\unattend*.xml C:\Windows\Panther\*.log &amp; rd /s /q C:\Windows\Panther\UnattendGC &amp; exit /b 0"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>4</Order>
<Description>Generalize the image and power off</Description> <Description>Generalize the image and power off</Description>
<CommandLine>C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /shutdown /quiet</CommandLine> <Path>C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /shutdown /quiet</Path>
</SynchronousCommand> </RunSynchronousCommand>
</FirstLogonCommands> </RunSynchronous>
</component> </component>
</settings> </settings>
</unattend> </unattend>