diff --git a/images/windows/scripts/build/Install-WindowsUpdates.ps1 b/images/windows/scripts/build/Install-WindowsUpdates.ps1 index c6828719f..b9da01836 100644 --- a/images/windows/scripts/build/Install-WindowsUpdates.ps1 +++ b/images/windows/scripts/build/Install-WindowsUpdates.ps1 @@ -21,14 +21,14 @@ function Install-WindowsUpdates { Write-Host "Installing windows updates" Get-WindowsUpdate -MicrosoftUpdate -NotKBArticleID "KB5001148" -AcceptAll -Install -IgnoreUserInput -IgnoreReboot | Out-Host - Write-Host "Validating windows updates installation and skip Microsoft Defender Antivirus" - # Azure service can automatic updates AV engine(Microsoft.Azure.Security.AntimalwareSignature.AntimalwareConfiguration) + Write-Host "Validating windows updates installation" # Get-WUHistory doesn't support Windows Server 2022 - $wuHistory = Get-WindowsUpdatesHistory | Where-Object { $_.Status -in ("Successful", "InProgress") } - $wuFail = $updates[0] | Where-Object Title -notmatch "Microsoft Defender Antivirus" | Where-Object { -not ($wuHistory.Title -match $_.KB) } + $notFailedUpdateNames = Get-WindowsUpdateStates | Where-Object { $_.State -in ("Installed", "Running") } | Select-Object -ExpandProperty Title + # We ignore Microsoft Defender Antivirus updates; Azure service updates AV automatically + $failedUpdates = $updates[0] | Where-Object Title -notmatch "Microsoft Defender Antivirus" | Where-Object { -not ($notFailedUpdateNames -match $_.KB) } - if ( $wuFail ) { - Write-Host "Windows updates failed to install: $($wuFail.KB)" + if ( $failedUpdates ) { + Write-Host "Windows updates failed to install: $($failedUpdates.KB)" exit 1 } } diff --git a/images/windows/scripts/build/Install-WindowsUpdatesAfterReboot.ps1 b/images/windows/scripts/build/Install-WindowsUpdatesAfterReboot.ps1 index 4d782299b..401a45ed0 100644 --- a/images/windows/scripts/build/Install-WindowsUpdatesAfterReboot.ps1 +++ b/images/windows/scripts/build/Install-WindowsUpdatesAfterReboot.ps1 @@ -4,9 +4,9 @@ ################################################################################ Invoke-SBWithRetry -RetryCount 10 -RetryIntervalSeconds 120 -Command { - $inProgress = Get-WindowsUpdatesHistory | Where-Object Status -eq "InProgress" | Where-Object Title -notmatch "Microsoft Defender Antivirus" + $inProgress = Get-WindowsUpdateStates | Where-Object State -eq "Running" | Where-Object Title -notmatch "Microsoft Defender Antivirus" if ( $inProgress ) { $title = $inProgress.Title -join "`n" - throw "InProgress: $title" + throw "Windows updates are still installing: $title" } } diff --git a/images/windows/scripts/helpers/ImageHelpers.psm1 b/images/windows/scripts/helpers/ImageHelpers.psm1 index e83f530a7..dfbcd8eb2 100644 --- a/images/windows/scripts/helpers/ImageHelpers.psm1 +++ b/images/windows/scripts/helpers/ImageHelpers.psm1 @@ -46,7 +46,7 @@ Export-ModuleMember -Function @( 'Get-AndroidInstalledPackages' 'Get-VisualStudioInstance' 'Get-VisualStudioComponents' - 'Get-WindowsUpdatesHistory' + 'Get-WindowsUpdateStates' 'New-ItemPath' 'Use-ChecksumComparison' 'Get-HashFromGitHubReleaseBody' diff --git a/images/windows/scripts/helpers/InstallHelpers.ps1 b/images/windows/scripts/helpers/InstallHelpers.ps1 index 354b22115..b1daaee01 100644 --- a/images/windows/scripts/helpers/InstallHelpers.ps1 +++ b/images/windows/scripts/helpers/InstallHelpers.ps1 @@ -595,14 +595,33 @@ function Get-AndroidInstalledPackages { return (cmd /c "$sdkManager --list_installed 2>&1") -notmatch "Warning" } -function Get-WindowsUpdatesHistory { - $allEvents = @{} - # 19 - Installation Successful: Windows successfully installed the following update - # 20 - Installation Failure: Windows failed to install the following update with error - # 43 - Installation Started: Windows has started installing the following update +function Get-WindowsUpdateStates { + <# + .SYNOPSIS + Retrieves the status of Windows updates. + + .DESCRIPTION + The Get-WindowsUpdateStates function checks the Windows Event Log for specific event IDs related to Windows updates and returns a custom PowerShell object with the state and title of each update. + + .PARAMETER None + This function does not take any parameters. + + .OUTPUTS + PSCustomObject. This function returns a collection of custom PowerShell objects. Each object has two properties: + - State: A string that represents the state of the update. Possible values are "Installed", "Failed", and "Running". + - Title: A string that represents the title of the update. + + .NOTES + Event IDs used: + - 19: Installation Successful: Windows successfully installed the following update + - 20: Installation Failure: Windows failed to install the following update with error + - 43: Installation Started: Windows has started installing the following update + #> + + $completedUpdates = @{} $filter = @{ - LogName = "System" - Id = 19, 20, 43 + LogName = "System" + Id = 19, 20, 43 ProviderName = "Microsoft-Windows-WindowsUpdateClient" } $events = Get-WinEvent -FilterHashtable $filter -ErrorAction SilentlyContinue | Sort-Object Id @@ -610,30 +629,31 @@ function Get-WindowsUpdatesHistory { foreach ( $event in $events ) { switch ( $event.Id ) { 19 { - $status = "Successful" + $state = "Installed" $title = $event.Properties[0].Value - $allEvents[$title] = "" + $completedUpdates[$title] = "" break } 20 { - $status = "Failure" + $state = "Failed" $title = $event.Properties[1].Value - $allEvents[$title] = "" + $completedUpdates[$title] = "" break } 43 { - $status = "InProgress" + $state = "Running" $title = $event.Properties[0].Value break } } - if ( $status -eq "InProgress" -and $allEvents.ContainsKey($title) ) { + # Skip update started event if it was already completed + if ( $state -eq "Running" -and $completedUpdates.ContainsKey($title) ) { continue } [PSCustomObject]@{ - Status = $status + State = $state Title = $title } } diff --git a/images/windows/scripts/tests/WindowsFeatures.Tests.ps1 b/images/windows/scripts/tests/WindowsFeatures.Tests.ps1 index a170e6cd7..802dc6f7f 100644 --- a/images/windows/scripts/tests/WindowsFeatures.Tests.ps1 +++ b/images/windows/scripts/tests/WindowsFeatures.Tests.ps1 @@ -62,19 +62,19 @@ Describe "Windows Updates" { "$env:windir\WindowsUpdateDone.txt" | Should -Exist } - $testCases = Get-WindowsUpdatesHistory | Sort-Object Title | ForEach-Object { + $testCases = Get-WindowsUpdateStates | Sort-Object Title | ForEach-Object { @{ - Title = $_.Title - Status = $_.Status + Title = $_.Title + State = $_.State } } It "