diff --git a/src/ci_orchestrator/commands/template.py b/src/ci_orchestrator/commands/template.py index 469cd28..7868de1 100644 --- a/src/ci_orchestrator/commands/template.py +++ b/src/ci_orchestrator/commands/template.py @@ -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(