Make build-windows-base.sh self-contained and produce a clean base image

The script no longer needs the parent repository or SSH: it builds an answer
ISO from windows11/seed/Autounattend.xml, installs Windows from the ISO in
QEMU (hardware in windows11/qemu uses only devices with inbox Windows
drivers), and the answer file generalizes the image with sysprep at the end.

The base holds only Windows: no account (the built-in Administrator is
disabled), no SSH, no settings, no VirtIO drivers, no machine identity and no
cached answer files. VMs are configured on first boot from an Unattend.xml on
an attached CD-ROM. Add --window and --from-img; press a key at the ISO boot
prompt with the z key, which neither UEFI nor Windows Setup ignores or acts on.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-11-02 11:19:26 +08:00
1 parent 1dc40655df
commit cb01d2c120
7 files changed
+525 -150

No files matched your search

+19 -10
View File
@@ -112,19 +112,28 @@ otherwise `udisksctl`, otherwise `7z` extracts it into a temporary directory
## Windows base image
`run-windows11.py` creates a missing system disk as a QCOW2 overlay on the base
image that `./download-images.sh --print-path windows11` prints, so a new VM does
not run Windows Setup again. `build-windows-base.sh` makes that base image: it
installs Windows unattended from the ISO in `install-iso/`, generalizes it with
`sysprep` over SSH, and stores the shut-down disk read-only.
A VM disk can be created as a QCOW2 overlay on a Windows base image, so a new VM
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
installs Windows unattended from the ISO in `install-iso/` (it does everything
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
with the built-in Administrator, which it disables again, and runs
`sysprep /generalize` 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
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
on its first boot: Windows reads `Unattend.xml` from the root of an attached
CD-ROM during its specialize and OOBE passes (a VM launcher can mount such a
seed ISO when it creates a VM disk).
It needs `qemu`, `qemu-img`, an ISO tool (`xorriso`, `genisoimage` or `mkisofs`)
and `socat` or `nc`; there is no SSH to the guest.
```bash
./build-windows-base.sh [--force] [--no-sysprep] [--compress] [OUTPUT.qcow2]
./build-windows-base.sh [--force] [--compress] [--from-img] [--window] [OUTPUT.qcow2]
```
It refuses to replace an existing base image without `--force`, because the
overlays of existing VMs still point at that file. Build to another `OUTPUT`
(for example with a version in its name) and select it with
`WIN11_VM_BASE_IMAGE` instead. The installation runs in a scratch directory
`/var/tmp/build-windows-base.*` (set `BASE_BUILD_TMPDIR` to use another parent; about 25 GB are needed) and needs a private key that matches
the public key put on the answer media.
(for example with a version in its name) and point your VM launcher at it. The installation runs in a scratch directory
`/var/tmp/build-windows-base.*` (set `BASE_BUILD_TMPDIR` to use another parent; about 25 GB are needed).