Script to pull all updates for a particular group in WSUS

I recently installed WSUS for a smaller client, with ~ 150 servers in 4 main computer groups. This past month I had someone else on the team go through and approve the updates for each of these groups. Three of them should be the same (Prod, Non-Prod, and a “download and notify only” group), but the number of updates is off on one group by a significant amount. I thought to write a script that would pull updates by computer group so I could compare, but there doesn’t seem to be an easy way to do this. I tried the following:

$group = $sWSUS.GetComputerTargetGroups() | ? {$_.Name -eq "Non-Prod"}
$group.GetSummaryPerUpdate()

But while this does return a list of updates, all of which show the Non-Prod ID in the ComputerTargetGroupID column, it returns a total of 2489 updates, which is everything approved on this WSUS server and about 100 more than is actually approved for this group. I am just curious why the discrepancy, and if anyone has a better way of defining a computer group and then pulling every update approved for just that group. In the WSUS console I can set an Update View that shows me this exact info, so there has got to be a way (I would think) to do it via PS.

This is what I have used before we switched away from WSUS. Tweak it as needed.

Param($TargetGroup="All Computers")
#Updates by server in a specific group
$SusServer = 'wsus01.domain.local'
$UseSSL = $False
$Port = 8530

# The below is to accommodate for WSUS 2.0 which has no standard UpdateServices module
# This can be accomplished easier and quicker using the WSUS 3.0+ standard update module.
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($SusServer,$UseSSL,$Port)

$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
# Other values for "IncludedInstallationStates" (All, Downloaded, failed, installed,
# installedpendingreboot, notapplicable, notinstalled, unknown)
$updateScope.IncludedInstallationStates = 'Downloaded','NotInstalled'

$ComputerTargets = ($wsus.GetComputerTargetGroups() | Where {$_.Name -eq $TargetGroup}).GetComputerTargets()
$Computertargets |
ForEach {
        $Computername = $_.fulldomainname.split('.')[0]
        $_.GetUpdateInstallationInfoPerUpdate($updateScope) |
        ForEach {
            $update = $_.GetUpdate()
            $serv = new-object PSObject
            $serv | add-member NoteProperty Computername $Computername.split(".")[0]
            $serv | add-member NoteProperty TargetGroup $TargetGroup
            $serv | add-member NoteProperty IsApproved $update.IsApproved
            $serv | add-member NoteProperty UpdateTitle $Update.Title
            $serv
            }
    }

Thanks for the reply. This works, although it returns the updates approved for each computer (so 2453 updates approved for 125 computers in a group is going to return ~300,000 entries. I can certainly trim this down by just grabbing the approved updates from $ComputerTargets[0], so that gets me farther than I was. But I am surprised there is not an easier way to simply get the updates I have approved for the group itself rather than having to touch one of the members of that group. If (and I admit I don’t know why I would) I happened to have a group with updates approved but no members, I would not be able to run this. I can, however, see approved updates for an empty computer group through the console.

Nevertheless, this at least gets me started, thanks!

[pre]
You may want to decline all updates that have been superseded. That may trim your update list.

# Change server name and port number and $True if it is on SSL
# https://xenappblog.com/2016/how-to-clean-up-wsus/
# https://blogs.technet.microsoft.com/gborger/2009/02/27/what-to-do-when-your-wsuscontent-folder-grows-too-large/

[String]$Computer = $env:COMPUTERNAME
[Boolean]$useSecureConnection = $False
[Int32]$portNumber = 8530
$today = (get-date).ToString('MM/dd/yy')
$OutFile = ".\DeclinedSupersededUpdates$today.txt"

# Load .NET assembly

[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
# Connect to WSUS Server
$updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($Computer,$useSecureConnection,$portNumber)
write-host "<<<Connected sucessfully >>>" -foregroundcolor "yellow"
$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$Updates = $updateServer.GetUpdates($updatescope ) |where {$_.IsSuperseded -eq 'True'} |sort ArrivalDate
$count = 0
foreach ($Update in $Updates)
{ 
[string]$date = $update.ArrivalDate
[string]$title = $update.Title
[string]$Bulletin = $update.SecurityBulletins
[string]$URLS = $update.AdditionalInformationUrls
"{0} {1} {2} {3} {4}" -f "Superseded Update: ",$date, $Title, $Bulletin, $Urls |out-file -filepath $outfile -encoding Ascii -append
$update.Decline()
$count=$count + 1
} # end of foreach update
"{0} {1} {2}" -f $count, "superseded updates declined", $today |out-file -FilePath $OutFile -Encoding Ascii -Append

[/pre]

I have not run that first script in a few years. I wish I had a WSUS server to run against to refresh my memory. But I think I was able to just report on a single update group by specifying it on the command line. The default is “All Computers”. Here I have a fictitious group called “2008 Servers”. Yes this could have been written more cleanly, but I was a noob at the time.

.\Report-WsusUpdatesByGroupServers.ps1 “2008 Servers” |Sort-object Computername | Export-Csv -notype |out-file .\MyApprovedUpdatesForGroup.csv

If you have no computers in an update group, you can not have approved updates for that group.