[Windows] Update helper function that returns Windows Update states (#8878)

This commit is contained in:
Vasilii Polikarpov
2023-11-27 12:29:42 +01:00
committed by GitHub
parent 12066050d0
commit e1e621e78c
5 changed files with 49 additions and 29 deletions

View File

@@ -21,14 +21,14 @@ function Install-WindowsUpdates {
Write-Host "Installing windows updates" Write-Host "Installing windows updates"
Get-WindowsUpdate -MicrosoftUpdate -NotKBArticleID "KB5001148" -AcceptAll -Install -IgnoreUserInput -IgnoreReboot | Out-Host Get-WindowsUpdate -MicrosoftUpdate -NotKBArticleID "KB5001148" -AcceptAll -Install -IgnoreUserInput -IgnoreReboot | Out-Host
Write-Host "Validating windows updates installation and skip Microsoft Defender Antivirus" Write-Host "Validating windows updates installation"
# Azure service can automatic updates AV engine(Microsoft.Azure.Security.AntimalwareSignature.AntimalwareConfiguration)
# Get-WUHistory doesn't support Windows Server 2022 # Get-WUHistory doesn't support Windows Server 2022
$wuHistory = Get-WindowsUpdatesHistory | Where-Object { $_.Status -in ("Successful", "InProgress") } $notFailedUpdateNames = Get-WindowsUpdateStates | Where-Object { $_.State -in ("Installed", "Running") } | Select-Object -ExpandProperty Title
$wuFail = $updates[0] | Where-Object Title -notmatch "Microsoft Defender Antivirus" | Where-Object { -not ($wuHistory.Title -match $_.KB) } # 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 ) { if ( $failedUpdates ) {
Write-Host "Windows updates failed to install: $($wuFail.KB)" Write-Host "Windows updates failed to install: $($failedUpdates.KB)"
exit 1 exit 1
} }
} }

View File

@@ -4,9 +4,9 @@
################################################################################ ################################################################################
Invoke-SBWithRetry -RetryCount 10 -RetryIntervalSeconds 120 -Command { 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 ) { if ( $inProgress ) {
$title = $inProgress.Title -join "`n" $title = $inProgress.Title -join "`n"
throw "InProgress: $title" throw "Windows updates are still installing: $title"
} }
} }

View File

@@ -46,7 +46,7 @@ Export-ModuleMember -Function @(
'Get-AndroidInstalledPackages' 'Get-AndroidInstalledPackages'
'Get-VisualStudioInstance' 'Get-VisualStudioInstance'
'Get-VisualStudioComponents' 'Get-VisualStudioComponents'
'Get-WindowsUpdatesHistory' 'Get-WindowsUpdateStates'
'New-ItemPath' 'New-ItemPath'
'Use-ChecksumComparison' 'Use-ChecksumComparison'
'Get-HashFromGitHubReleaseBody' 'Get-HashFromGitHubReleaseBody'

View File

@@ -595,14 +595,33 @@ function Get-AndroidInstalledPackages {
return (cmd /c "$sdkManager --list_installed 2>&1") -notmatch "Warning" return (cmd /c "$sdkManager --list_installed 2>&1") -notmatch "Warning"
} }
function Get-WindowsUpdatesHistory { function Get-WindowsUpdateStates {
$allEvents = @{} <#
# 19 - Installation Successful: Windows successfully installed the following update .SYNOPSIS
# 20 - Installation Failure: Windows failed to install the following update with error Retrieves the status of Windows updates.
# 43 - Installation Started: Windows has started installing the following update
.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 = @{ $filter = @{
LogName = "System" LogName = "System"
Id = 19, 20, 43 Id = 19, 20, 43
ProviderName = "Microsoft-Windows-WindowsUpdateClient" ProviderName = "Microsoft-Windows-WindowsUpdateClient"
} }
$events = Get-WinEvent -FilterHashtable $filter -ErrorAction SilentlyContinue | Sort-Object Id $events = Get-WinEvent -FilterHashtable $filter -ErrorAction SilentlyContinue | Sort-Object Id
@@ -610,30 +629,31 @@ function Get-WindowsUpdatesHistory {
foreach ( $event in $events ) { foreach ( $event in $events ) {
switch ( $event.Id ) { switch ( $event.Id ) {
19 { 19 {
$status = "Successful" $state = "Installed"
$title = $event.Properties[0].Value $title = $event.Properties[0].Value
$allEvents[$title] = "" $completedUpdates[$title] = ""
break break
} }
20 { 20 {
$status = "Failure" $state = "Failed"
$title = $event.Properties[1].Value $title = $event.Properties[1].Value
$allEvents[$title] = "" $completedUpdates[$title] = ""
break break
} }
43 { 43 {
$status = "InProgress" $state = "Running"
$title = $event.Properties[0].Value $title = $event.Properties[0].Value
break 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 continue
} }
[PSCustomObject]@{ [PSCustomObject]@{
Status = $status State = $state
Title = $title Title = $title
} }
} }

View File

@@ -62,19 +62,19 @@ Describe "Windows Updates" {
"$env:windir\WindowsUpdateDone.txt" | Should -Exist "$env:windir\WindowsUpdateDone.txt" | Should -Exist
} }
$testCases = Get-WindowsUpdatesHistory | Sort-Object Title | ForEach-Object { $testCases = Get-WindowsUpdateStates | Sort-Object Title | ForEach-Object {
@{ @{
Title = $_.Title Title = $_.Title
Status = $_.Status State = $_.State
} }
} }
It "<Title>" -TestCases $testCases { It "<Title>" -TestCases $testCases {
$expect = "Successful" $expect = "Installed"
if ( $Title -match "Microsoft Defender Antivirus" ) { if ( $Title -match "Microsoft Defender Antivirus" ) {
$expect = "Successful", "Failure", "InProgress" $expect = "Installed", "Failed", "Running"
} }
$Status | Should -BeIn $expect $State | Should -BeIn $expect
} }
} }