A few days ago, a PM.org list member asked the following question:
I’m trying to find out what the status is on clients installing the September Cumulative Update.
He also reported that he was using WID (Windows Internal Database) and not SQL. He was also struggling with the Microsoft Report Viewer and Microsoft System CLR Types for SQL Server.
I replied that he can achieve this using only #PowerShell and the WSUS API 😀 but my first try was:
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope $updateScope.TextIncludes= '4038777' (Get-WsusServer).GetUpdateApprovals($updateScope) | ForEach-Object { $tg = (Get-WsusServer).GetComputerTargetGroup($($_.ComputerTargetGroupId)) Write-Verbose -Message "Dealing with approval type $($_.Action) on to target group '$($tg.Name)'" -Verbose $tg.GetComputerTargets($true) | ForEach-Object { $computer = $_ $State = $computer.GetUpdateInstallationSummary($updateScope) [PSCustomObject]@{ ComputerName = $_.FullDomainName ; Unknown = $( if($State.UnknownCount) { $true } else { $false} ); NotApplicable = $( if($State.NotApplicableCount) { $true } else { $false } ); NotInstalled = $( if($State.NotInstalledCount) { $true } else { $false } ); Downloaded = $( if($State.DownloadedCount) { $true } else { $false } ); Installed = $( if($State.InstalledCount) { $true } else { $false } ); InstalledPendingReboot = $( if($State.InstalledPendingRebootCount) { $true } else { $false } ); Failed = $( if($State.FailedCount) { $true } else { $false } ); } } } | ogv
Well, the above code did the job but performed very poorly. It took more than a minute to display the results for a hundred client computers.
I took the update scope approach with a custom text filter and I’ve been inspired by my previous blog post about WSUS reporting.
I wasn’t satisfied and I believed I took the wrong approach and that there should be one or more efficient ways to get the results.
So, the next morning, I gave it another try and found another way to skin the cat:
$kb = '4038777' | % { (Get-WsusServer).SearchUpdates($_) } | ? Title -match 'Windows 7 for x64-based ' | ? { $_.IsLatestRevision } (Get-WsusServer).GetComputerTargetGroups() | ForEach-Object { $kb.GetUpdateInstallationInfoPerComputerTarget($_) | ForEach-Object { [PSCustomObject]@{ Computer = (Get-WsusServer).GetComputerTarget($_.ComputerTargetId).FullDomainName State = $_.UpdateInstallationState } } } | ogv
The above way performs much faster (max 8 seconds for the same 100 computers) and has less code 😎