WSUS – Programatic Access

Windows Server Update Service – great service, poor interface. Ever try to manage computers in bulk with the WSUS GUI? You can’t… there are limited filtering and search options, and the GUI hangs a lot when performing group operations. Surely there is a better way…

Maybe, at least if you are a programmer. If not, then there at least is another way, if not better.

.NET to the rescue…

Use the “Microsoft.UpdateServices.Administration” Reflection Assembly to expose WSUS .NET objects to PowerShell, and you are limited only by your PS-foo.

My task last night was to add a list of computer objects (obtained using “dsquery” to a named group in WSUS.  Because I wanted to save time, I used Google to get some base code to work with. The code below is derived largely from the good work found here:

Ultimately, I am not sure if this saved time, because troubleshooting other people’s code generally takes about twice as long a fixing your own.

Anyway, the following script will get the job done. It requires an input file (srvlist.txt) with one computer name per line. You will need to add your WSUS server, port number, SSL boolean value, and WSUS target group to make the script run.

#Script to add machines to a WSUS group automatically:
#The script needs Admin credentials and the WSUS Administration Console installed on the machine where it runs
#Initialize Variables
	$wsusGroup = [string] "ServerGroupC"
	$wsusParentGroup = [string] "All Computers"
	$date = get-date
	$date = [string] $ + $date.month + $date.year + $date.hour + $date.minute
	$succeslog = [string] ".\logs\" + $date + "_success.log"
	$errorlog = [string] ".\logs\" + $date + "_errors.log"
	$WindowsUpdateServer= [string] ""
	$useSecureConnection = [bool] $true
	$portNumber = [int] "443"

#Instantiate Objects:
	#Required WSUS Assembly – auto installed with WSUS Administration Tools
	if (!$wsus) {
		$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WindowsUpdateServer,$useSecureConnection,$portNumber)
	$serverList = Get-Content ".\srvlist.txt"
	$updateGroups = $Wsus.GetComputerTargetGroups()
	$updateGroup = $UpdateGroups | Where-Object{$_.Name -eq $wsusgroup} | Where-Object{$_.getparenttargetgroup().name -eq $wsusparentgroup}
	$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope
	$computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::All
	$computers = $wsus.GetComputerTargets($computerScope)
	$wsusServers = @()
	$WsusServersShortNames = @()

#Create arrays:
# $wsusServer = Array of WSUS Computer objects
# $wsusServerShortName = Array strings, with one server RDN per line
Write-Host "Collecting Server List from WSUS…"
$computers | foreach-object {
	$wsusServer = $_.FullDomainName
	#cut off DNS suffix and store shortname
	$wsusServerShortName = $WsusServer.split(‘.’)[0]
	$wsusServers += $WsusServer
	$wsusServersShortNames += $wsusServerShortName
} #End ForEach $computers

#loop to add servers to group
ForEach ($server in $serverList)  {
		#Check if server Netbios name is present in WSUS, if present move to group – if not log an error
		$wsusComputer = $wsusServersShortNames | Where-Object {$_ -eq $server.Trim()} #Checks for a match in WSUS for the current server in the import list.
		If ($wsusComputer) {
			$searchStr = [string] $server.Trim() + "\." #String representing a RegEx match for the relative part of the server FQDN
			$wsusComputer1 = $wsusServers | where-object {$_ -match $searchStr } #Get a WSUS computer object representing the current server in the import list.
			If ($wsusComputer1.getType().Name -match "string") { #Current $wsusComptuer1 must be a [string] object, or next step will fail.
				Write-Host "$wsusComputer1 will be added to $($ group"
				$computer = $wsus.GetComputerTargetByName($wsusComputer1)
				out-file -append -inputobject "$Server added to $($ group" -filepath $succeslog
			Else {
				#More than one server was matched in WSUS – this will happen if your regEx is not properly formed.
				write-host "count $($wsusComputer1.count)"
				Out-File -append -inputobject "$werver has ambiguous name – check server in WSUS and add to group manually" -filepath $errorlog
		} #End If $wsusComputer
	Else {
		Write-Host "$Server not found in WSUS"
		out-file -append -inputobject "$Server not found in WSUS" -filepath $errorlog
} #End ForEach $server