feat: windows-update step handles multiple reboot rounds via scheduled task
All checks were successful
release / build-and-release (push) Successful in 22s
All checks were successful
release / build-and-release (push) Successful in 22s
First pass runs during deployment (no reboot). Then registers X9-WindowsUpdate scheduled task that fires on every logon, installs remaining updates, and self-deletes when system is fully up to date - covers the typical 2-3 reboot cycles needed on a fresh Windows install. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b508ec4b3e
commit
2236fe48e9
1 changed files with 65 additions and 38 deletions
|
|
@ -3,14 +3,21 @@
|
|||
Installs all available Windows Updates via PSWindowsUpdate module.
|
||||
|
||||
.DESCRIPTION
|
||||
Installs the PSWindowsUpdate module from PSGallery and runs a full
|
||||
Windows Update pass. Does not auto-reboot - the operator restarts
|
||||
manually after all deployment steps complete. Skips drivers (handled
|
||||
by step 11 Dell Command Update or Windows Update for Business).
|
||||
First pass: installs all currently available updates without rebooting.
|
||||
Then registers a scheduled task "X9-WindowsUpdate" that runs on every
|
||||
logon (as SYSTEM) until no more updates are found - handles the typical
|
||||
2-3 reboot cycles required on a fresh Windows installation.
|
||||
|
||||
Operator workflow:
|
||||
1. xetup completes all steps
|
||||
2. Operator reboots manually
|
||||
3. On each subsequent logon the scheduled task runs another update pass
|
||||
4. Task removes itself automatically when system is fully up to date
|
||||
|
||||
.ITEMS
|
||||
nainstalovat-pswindowsupdate-modul: Installs NuGet provider and PSWindowsUpdate module from PSGallery. Required only on first run - subsequent runs reuse the cached module.
|
||||
spustit-windows-update-vsechny-aktualizace: Calls Install-WindowsUpdate -AcceptAll -IgnoreReboot. Installs all Quality, Security and Feature updates. Skips reboot - operator restarts manually after deployment completes.
|
||||
nainstalovat-pswindowsupdate-modul: Installs NuGet provider and PSWindowsUpdate module from PSGallery.
|
||||
spustit-prvni-kolo-windows-update: First update pass without reboot - installs all currently available updates.
|
||||
registrovat-scheduled-task-pro-dalsi-kola: Registers X9-WindowsUpdate scheduled task that runs on logon, handles post-reboot update rounds, and self-deletes when no more updates are found.
|
||||
#>
|
||||
param(
|
||||
[object]$Config,
|
||||
|
|
@ -30,21 +37,11 @@ function Write-Log {
|
|||
Write-Log "=== Step 12 - Windows Update ===" -Level STEP
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 1. NuGet provider (required for Install-Module from PSGallery)
|
||||
# 1. NuGet provider + PSWindowsUpdate module
|
||||
# -----------------------------------------------------------------------
|
||||
Write-Log "Installing NuGet provider..." -Level INFO
|
||||
Write-Log "Setting up PSWindowsUpdate module..." -Level INFO
|
||||
try {
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null
|
||||
Write-Log " NuGet provider ready" -Level OK
|
||||
} catch {
|
||||
Write-Log " NuGet provider install failed: $_" -Level WARN
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 2. PSWindowsUpdate module
|
||||
# -----------------------------------------------------------------------
|
||||
Write-Log "Installing PSWindowsUpdate module..." -Level INFO
|
||||
try {
|
||||
$existing = Get-Module -ListAvailable -Name PSWindowsUpdate | Select-Object -First 1
|
||||
if ($existing) {
|
||||
Write-Log " PSWindowsUpdate $($existing.Version) already installed" -Level INFO
|
||||
|
|
@ -54,35 +51,65 @@ try {
|
|||
}
|
||||
Import-Module PSWindowsUpdate -Force
|
||||
} catch {
|
||||
Write-Log " PSWindowsUpdate module setup failed: $_" -Level ERROR
|
||||
Write-Log " Skipping Windows Update step" -Level WARN
|
||||
Write-Log " Module setup failed: $_" -Level ERROR
|
||||
exit 1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 3. Run Windows Update
|
||||
# 2. First update pass (no reboot)
|
||||
# -----------------------------------------------------------------------
|
||||
Write-Log "Checking for available updates..." -Level INFO
|
||||
|
||||
Write-Log "Running first Windows Update pass..." -Level INFO
|
||||
try {
|
||||
$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot 2>&1
|
||||
if (-not $updates) {
|
||||
Write-Log " No updates available - system is up to date" -Level OK
|
||||
$result = Install-WindowsUpdate -AcceptAll -IgnoreReboot -Verbose 2>&1
|
||||
$installed = @($result | Where-Object { $_ -match 'KB\d+|Downloaded|Installed' })
|
||||
if ($installed.Count -gt 0) {
|
||||
$result | Where-Object { "$_" -match '\S' } | ForEach-Object { Write-Log " $_" -Level INFO }
|
||||
Write-Log " First pass complete - reboot required for remaining rounds" -Level OK
|
||||
} else {
|
||||
$count = ($updates | Measure-Object).Count
|
||||
Write-Log " Found $count update(s) - installing..." -Level INFO
|
||||
|
||||
Install-WindowsUpdate -AcceptAll -IgnoreReboot -Verbose 2>&1 | ForEach-Object {
|
||||
if ($_ -match '\S') {
|
||||
Write-Log " $_" -Level INFO
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log " Windows Update complete ($count updates processed)" -Level OK
|
||||
Write-Log " System already up to date" -Level OK
|
||||
}
|
||||
} catch {
|
||||
Write-Log " Windows Update failed: $_" -Level ERROR
|
||||
exit 1
|
||||
Write-Log " First pass failed: $_" -Level ERROR
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 3. Scheduled task for post-reboot update rounds (self-deleting)
|
||||
# -----------------------------------------------------------------------
|
||||
Write-Log "Registering post-reboot update task..." -Level INFO
|
||||
|
||||
$taskName = "X9-WindowsUpdate"
|
||||
|
||||
# PowerShell block that runs on each logon until no more updates found
|
||||
$updateScript = @'
|
||||
Import-Module PSWindowsUpdate -Force -ErrorAction Stop
|
||||
$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot
|
||||
if ($updates) {
|
||||
Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\Setup\Scripts\wu-pass-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" -Encoding UTF8
|
||||
} else {
|
||||
# No more updates - remove this task
|
||||
Unregister-ScheduledTask -TaskName "X9-WindowsUpdate" -Confirm:$false
|
||||
}
|
||||
'@
|
||||
|
||||
try {
|
||||
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
|
||||
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$updateScript`""
|
||||
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
||||
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
|
||||
-MultipleInstances IgnoreNew
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
|
||||
|
||||
# Remove existing task first (idempotent)
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
|
||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger `
|
||||
-Settings $settings -Principal $principal -Force | Out-Null
|
||||
|
||||
Write-Log " Task '$taskName' registered - runs on each logon until fully updated" -Level OK
|
||||
} catch {
|
||||
Write-Log " Failed to register scheduled task: $_" -Level WARN
|
||||
Write-Log " Manual Windows Update rounds will be needed after reboot" -Level WARN
|
||||
}
|
||||
|
||||
Write-Log "Step 12 - Windows Update complete" -Level OK
|
||||
Write-Log " ACTION REQUIRED: Reboot the machine to complete remaining update rounds" -Level WARN
|
||||
|
|
|
|||
Loading…
Reference in a new issue