Category Archives: wsus

WSUS 3.0 Cleaning out redundant computers

Following on from my last post about WSUS 3.0 and Powershell another thing which bugged me about the WSUS 3.0 GUI is the Cleanup Wizard. This is a really useful tool for keeping your WSUS deployment running efficiently.

It includes the ability to clean out computers which haven’t synched with the WSUS server for over 30 days – unfortunately 30 days is the default value which can’t be changed in the GUI. Arrgh! I’ve wanted to run this tool for a long time, but 30 days is way too short and I wanted to be able to specify my own time frame, e.g. 200 days.

Luckily I met Marc Shepard at Teched EMEA and during a Q&A session for WSUS I asked why it wasn’t possible to change the 30 day value. This developed into a discussion along the lines that the WSUS team didn’t wish to promote removing lots of computers from WSUS – I can’t remember exactly why now, I think it was along the lines of preventing lots of computers which were actually still alive synching back into WSUS. (Apologies if this is not the correct reason)

Anyway, even though we had a slight difference of opinion about this (I want to remove old computers so that the monthly patch compliance reports are more accurate), Marc kindly agreed to send me over a Powershell script which would run the cleanup computer part of the wizard under the caveat that this was not their recommended method for maintenance.

So here it is, this version will give you a list of computers who have not synched over the specified number of days:

[reflection.assembly]::LoadWithPartialName(Microsoft.UpdateServices.Administration) | out-null

$days = read-host Please enter the number of days since Last Sync you wish to query for
$ts = new-object TimeSpan($days,0,0,0)

$updateServer = WSUSServername
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($updateServer,$false)

$computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerScope.ToLastSyncTime = [DateTime]::UtcNow.Subtract($ts)
$wsus.GetComputerTargets($computerScope) | sort fulldomainname | ft fulldomainname,lastsynctime

If you wish to remove them then simply change the last line to:

$wsus.GetComputerTargets($computerScope) | foreach-object {$_.Delete();}

I have added both of these scripts and the ApproveMultipleUpdates scripts from the last post to the WSUS PowerGUI Powerpack.

Also keep an eye on the WSUS section of the MS Script Center Marc is hoping to soon publish some more Powershell scripts for managing WSUS.

WSUS 3.0: Approving Multiple Updates for a Specific Computer with Powershell

One of the best uses I have found for Powershell is for plugging gaps in holes left by GUI admin tools which don’t do everything that you want. Prior to Powershell you would typically have had to wait for the next service pack / full release / possibly ever before you had the functionality that you wanted.

I had an example of this recently with the GUI tool for WSUS 3.0. Essentially I was kicking off a project where we were going to target a particular group of machines for patching and the first step was to run a report for specific machines and then approve the updates to what WSUS calls a ComputerTargetGroup.

The problem with this is that although WSUS can provide you with a report which shows which updates are required for a specific machine, there is no way in the GUI that you can approve all of those updates in one go. Since it takes 5 clicks per approval, you only have to get into the 10’s of updates before this goes beyond tedious.

I knew there were some sample scripts for WSUS and Powershell on the Script Center so I headed over there and checked out some of the scripts. (This initial investigation led to the creation of the PowerGUI Powerpack for WSUS – fairly basic, but it was great way to learn what sort of things would be available)

So I then spent some time working on a script to approve multiple updates for a specific computer which is shown below. I’d love to say that I put this all togther myself, but really it is another illustration of how helpful people within the Powershell community are. Shay Levi was incredibly helpful putting the initial work of this script together, we got most of the way there, but it got left at the point where I could retrieve as objects the list of updates required for the computer, but couldn’t figure out how to approve them for a particular computer group.

Fortunately at Teched I went to a couple of sessions on WSUS 3.0 run by Program Manager Marc Shepard who contributes to the WSUS team blog. I went to see Marc at the ‘Ask The Experts’ stand inbetween the two sessions he was running. He seemed genuinely pleased to find someone with a particular request for the product (I guess it’s free so hey that must be a tricky product to be a Program Manager for 😉 ), took on my unfinished Powershell script and started coding away.

By the time I got to the next session Marc had a working script for me – there is no better recommendation for going to Teched than this!

The script is below. Before running the ApproveMultipleUpdates script you need to establish three things:

  • WSUS Server Name
  • Full DNS name of the computer you wish to query
  • The Computer Group Target ID for the group you wish to make the approval to. You can find this either by using the PowerGUI Powerback or the code below:

Get-ComputerTargetGroups.ps1

[void][reflection.assembly]::LoadWithPartialName(Microsoft.UpdateServices.Administration)
$updateServer = WSUSServername
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($updateServer,$false)

$wsus.GetComputerTargetGroups()

ApproveMultipleUpdates.ps1

[void][reflection.assembly]::LoadWithPartialName(Microsoft.UpdateServices.Administration)

$updateServer = WSUSServername
$machineName = Read-Host Please enter the full DNS name of the computer you wish to approve updates for

$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($updateServer,$false)

$updateScope = new-object Microsoft.UpdateServices.Administration.UpdateScope

$updateScope.includedInstallationStates = NotInstalled

$com = $wsus.GetComputerTargetByName($machineName)

$groupid= Read-Host Please enter the Computer Group Target ID

$group = $wsus.GetComputerTargetGroup($groupid)
$action = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install

$updates = $com.GetUpdateInstallationInfoPerUpdate($updateScope)
$updates | foreach-object {$uid = $_.UpdateId; $u = $wsus.GetUpdate($uid); $u.Title; $u.Approve($action,$group);}

This is going to save us hours of work – big thanks to the guys who helped me out!

(I think a version of this script should be making its way onto the MS Script Center at some point too)