<# .SYNOPSIS Installs all available Windows Updates via PSWindowsUpdate module. .DESCRIPTION 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. 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, [string]$LogFile ) $ErrorActionPreference = "Continue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue Add-Content -Path $LogFile -Value $line -Encoding UTF8 Write-Output $line } Write-Log "=== Step 12 - Windows Update ===" -Level STEP # ----------------------------------------------------------------------- # 1. NuGet provider + PSWindowsUpdate module # ----------------------------------------------------------------------- Write-Log "Setting up PSWindowsUpdate module..." -Level INFO try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null $existing = Get-Module -ListAvailable -Name PSWindowsUpdate | Select-Object -First 1 if ($existing) { Write-Log " PSWindowsUpdate $($existing.Version) already installed" -Level INFO } else { Install-Module -Name PSWindowsUpdate -Force -Scope AllUsers -AllowClobber | Out-Null Write-Log " PSWindowsUpdate installed" -Level OK } Import-Module PSWindowsUpdate -Force } catch { Write-Log " Module setup failed: $_" -Level ERROR exit 1 } # ----------------------------------------------------------------------- # 2. First update pass (no reboot) # ----------------------------------------------------------------------- Write-Log "Running first Windows Update pass..." -Level INFO try { $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 { Write-Log " System already up to date" -Level OK } } catch { 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