WSUS Windows Update Compliance PowerShell

WSUS Windows Update Compliance PowerShell


We previously saw how to request the local Windows Update configuration of a Windows computer or server. Today, we’ll check the installation of a specific update. On a given computer, then, on the WSUS reporting server. This will allow us to be sure that a specific KB was deployed on all our computers/server.

Get Installation Status for a Named Update

You have two options:

  • Get-WmiObject/Get-CimInstance -ClassName Win32_QuickFixEngineering
  • Get-Hotfix

All of those methods works, the Get-CimInstance may be a bit faster and more firewall friendly but it requires PowerShell3+.

WSUS Windows Update Compliance PowerShell - Methods

WSUS Windows Update Compliance PowerShell – Methods

If you want to check all of your domain joined computer, you can use this:

Get-ADForest | Select-Object -ExpandProperty Domains | ForEach-Object -Process {Get-ADComputer -Filter *} | ForEach-Object -Process {Get-CimInstance -ClassName Win32_QuickFixEngineering -ComputerName $_.Name}
WSUS Windows Update Compliance PowerShell - All Forest

WSUS Windows Update Compliance PowerShell – All Forest

As you can expect, it will be quite long. You can get the work done faster if you want to get only a subset of installed update:

Get-HotFix -Id KB4041691
Get-CimInstance -ClassName Win32_QuickFixEngineering -Filter "HotFixID='KB4041691'"

But you still need to query each computer one by one.

WSUS Windows Update Compliance PowerShell Massively

If you use a WSUS server with a WSUS reporting server, you can skip the step to query each computer one by one and directly query the WSUS report server, it will me much more efficient, but the data may not be fully up to date depending of the frequency reporting configured on your clients computers. To do this, you need to be connected on a computer or server with the WSUS dll, you can check with this:

[reflection.assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | Out-Null

If it works, you’re good to go on the next step, if not, you need to find a computer with the WSUS server role.

[reflection.assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | Out-Null
$WsusServerList = 'WSUS01','WSUS02'

#Choose one of the two kind of names, the short or full one
$KBName = 'KB4038777'
$KBName = '2017-09 Security Monthly Quality Rollup for Windows Server 2008 R2 for x64-based Systems (KB4038777)'

$UpdateScope = New-Object -TypeName Microsoft.UpdateServices.Administration.UpdateScope
$UpdateScope.TextIncludes = $KBName
$ComputerScope = New-Object -TypeName Microsoft.UpdateServices.Administration.ComputerTargetScope

$WsusAllInfo = ForEach($WsusServer in $WsusServerList){
    $WsusConnection = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$false,'8530')

    $WsusConnection.GetUpdates($UpdateScope) | ForEach-Object -Process {
        $_.GetUpdateInstallationInfoPerComputerTarget($ComputerScope) | ForEach-Object -Process {
            New-Object -TypeName PSObject -Property @{
                Name                        = $WsusConnection.GetComputerTarget($_.ComputerTargetId).FullDomainName
                UpdateInstallationState     = $_.UpdateInstallationState
                UpdateApprovalAction        = $_.UpdateApprovalAction
                Update                      = $WsusConnection.GetUpdate([GUID]$_.UpdateId).LegacyName
    $WsusConnection = $null
#Export and display information
$WsusAllInfo | Group-Object -Property UpdateInstallationState
$WsusAllInfo | Sort-Object -Property Name -Unique | Export-Csv -NoTypeInformation -Delimiter ';' WSUS-Compliance.csv

Those few lines will allow you to query the WSUS database to get the information, it will be very much faster, only a few minutes against a few hours if you query each host one by one.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.