fix(prepare-win): run disk cleanup before the final reboot

Heavy servicing (DISM StartComponentCleanup in the -CleanupOnly step, like
WU finalization) destabilises the running shell session — explorer
crash-loops until the next reboot. Cleanup ran *after* the final reboot, so
the template ended on a crash-looping desktop and the idle check aborted.

Reorder: disk cleanup + autologin re-affirm now run before the final
reboot, making that reboot the last action before the idle check — the
shell comes up against fully-settled components and the snapshot captures a
clean, idle desktop.
This commit is contained in:
2026-06-09 22:00:08 +02:00
parent c1be0f276f
commit d4d349dee2
+12 -6
View File
@@ -807,11 +807,11 @@ Register-ScheduledTask -TaskName 'CI-StaticIp' `
f"[prepare-win] Validation script error:\n{val_result.stderr}", err=True
)
# Final reboot to flush installation state
click.echo("[prepare-win] Final reboot to flush installation state ...")
_reboot_and_wait(transport, guest_ip, 5986, winrm_timeout)
# Disk cleanup — runs after final reboot on fully-installed system
# Disk cleanup BEFORE the final reboot. Heavy servicing ops (DISM
# StartComponentCleanup, WU finalization) destabilise the running shell
# session — explorer crash-loops until the next reboot — so all such work
# must happen before the final reboot, never after it (otherwise the
# template snapshots a crash-looping desktop).
if not skip_cleanup:
click.echo("[prepare-win] Running post-update disk cleanup (-CleanupOnly) ...")
cleanup_invoke = (
@@ -839,7 +839,7 @@ Register-ScheduledTask -TaskName 'CI-StaticIp' `
raise click.ClickException(f"Disk cleanup failed (exit {cleanup_ec}).")
click.echo("[prepare-win] Post-update cleanup complete.")
# Re-affirm autologin
# Re-affirm autologin (registry persists across the reboot below).
click.echo("[prepare-win] Re-affirming autologin registry settings ...")
transport.run(
"$wl = 'HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon'\n"
@@ -851,6 +851,12 @@ Register-ScheduledTask -TaskName 'CI-StaticIp' `
"}\n"
)
# Final reboot — the LAST action before the idle check, so the shell
# comes up against fully-settled components (no crash loop) and the
# snapshot captures a clean, idle desktop.
click.echo("[prepare-win] Final reboot to flush installation state ...")
_reboot_and_wait(transport, guest_ip, 5986, winrm_timeout)
# Pre-snapshot idle check — abort (no snapshot) if the template is busy.
if not skip_idle_check:
_check_guest_idle(