PoC: Windows Guest Support via autounattend.xml (Issue #4852) #5013
Draft
liketosweep wants to merge 1 commit into
Draft
PoC: Windows Guest Support via autounattend.xml (Issue #4852) #5013liketosweep wants to merge 1 commit into
liketosweep wants to merge 1 commit into
Conversation
…s issue lima-vm#4852. Signed-off-by: liketosweep <liketosweep@gmail.com>
Member
|
AI code review: https://jandubois.github.io/lima/20260519-084740-pr-5013.html |
Author
|
Hey @jandubois thanks for the review , I've gone through the report and working on resolving the associated issues . |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PoC implements fully automated, unattended Windows Server 2025 installation inside a QEMU VM by generating and delivering a Windows Answer File (
autounattend.xml) .Approach
Two new Go packages -
pkg/windows/autounattend- a typed, validated XML generator usinghtml/template. takes aConfigstruct (hostname, credentials, SSH public keys, locale, edition index, extra commands) and renders a complete three-pass answer file. Passwords are never stored as plaintext they are encoded asbase64(UTF-16LE(password + "Password"))per the Microsoft answer file specification before being written into XML, enforced by a dedicated security test.pkg/windows/cidata- a Go ISO builder that stagesautounattend.xmlandfirst_logon.ps1into a temp directory, detects whichever ISO tool is available on the host (genisoimage,mkisofs, orxorriso), builds the ISO atomically via a.tmprename, and validates the output is non-empty before returning. This replaces ad-hoc shell calls with a reusable, error-handled package.Why ISO delivery, not floppy -
The Windows installer (WinPE) scans all CD/DVD drives for
autounattend.xmlat boot. Modern WinPE builds do not reliably scan floppy devices. The answer file and provisioning script are bundled into a single ISO image (win-cidata.iso) and presented to QEMU as a third CD-ROM drive, which the installer finds and processes automatically before showing any UI.VirtIO driver injection in
windowsPEpass -Without loading the
viostor(VirtIO storage) driver during thewindowsPEsetup pass, Windows PE cannot see a virtio-backed disk and installation fails. ThePnpCustomizationsWinPEcomponent in the answer file points to the VirtIO-Win driver ISO (mounted as a second CD-ROM) so the disk is visible to the installer from the start.Partition layout -
A two-partition MBR layout (100 MB NTFS System + remainder as Windows C:) is used. This is compatible with the legacy BIOS boot mode QEMU defaults to without OVMF firmware, making the setup dependency-free — no
swtpm, no OVMF binaries required.Structured provisioning via
first_logon.ps1-A single
<FirstLogonCommands>entry callsfirst_logon.ps1from the cidata ISO. The script runs underSet-StrictMode -Version Latestand$ErrorActionPreference = 'Stop', wrapping each phase (OpenSSH install, firewall rule, SSH key injection, WinFSP, VirtIO-FS service) in anInvoke-Stephelper that logs success or failure per step and exits immediately on any error. The SSH public key is passed as a-SSHKeyparameter rather than read from a separate file, keeping the provisioning interface clean.Results
PasswordNeverPlaintextsecurity testgo build ./pkg/windows/...xmllint --noout autounattend.xmlisoinfo -lshowsAUTOUNA.XML+FIRST_LO.PS1Get-Service sshd→ Runningadministrators_authorized_keyscontains Lima SSH public keyC:\lima-setup.log→All steps completed successfullyssh -p 60022 limauser@localhost)Files Changed
Next Steps (full implementation)
pkg/windows/autounattendandpkg/windows/cidatainto Lima's instance creation flow viapkg/cidata/cidata.godispatch onguestOS: windowsguestOSfield andwindowsEditionIndexparam tolimayamlpkg/qemu/qemu.gowindows.yamlexample template toexamples/Image Proofs
Go Package Tests - 90.2% statement coverage, all 9 tests pass
ISO Contents and Answer File Verification
Unattended Installation - Windows installing autonomously from autounattend.xml
Fully Automated Boot - Windows Server 2025 running with hostname set from config
SSH Access - Remote login from WSL host into Windows guest
Provisioning Log - All first_logon.ps1 steps completed successfully
Proposed solution for other issues as defined in #4907
Issue #4961 - Windows host support without depending on QEMU (Hyper-V / HCS)
I intend to use Microsoft's
hcsshimlibrary(github.com/microsoft/hcsshim)to create a newvmType: hcsdriver inpkg/vz-stylethat callshcsshim.CreateComputeSystemwith a JSON schema document.Issue #4820 - Autoappend
%PROGRAMFILES%\QEMUetc. to%PATH%on Windows hostsI intend to add to Lima's QEMU binary resolution logic: on
runtime.GOOS == "windows", probe a list of well-known install locations(%PROGRAMFILES%\QEMU, %PROGRAMFILES(X86)%\QEMU , the Chocolatey shim path)usingos.Statbefore falling back toexec.LookPath, and prepend any found directory to the resolved path.Issue #4819 - Drop dependency on cygpath.exe, MSYS2, and Git for Windows
I intend to use Go's standard library tools
filepath.ToSlash,filepath.FromSlash,strings.TrimPrefix,filepath.VolumeNameto produce/c/Users/...-style paths natively. Replacing theWindowsSubsystemPathshell-out inpkg/ioutilx/ioutilx.gowith a pure-Go implementation .##Seperate Prs would be raised for catering these issues
Assistance taken from Claude opus for the documentation of this Pr.