Working with WSUS, I sometimes find myself declining the exact same type of updates each month after Patch Tuesday. Not surprisingly, a common trend of those updates involve having the word ‘’Itanium” somewhere in the update title. Instead of having to mess with clicking through the UI and finding all of these annoying updates, and as there are no automated declining rules available in WSUS, I think a more automated approach is necessary using the APIs and PowerShell.
Honestly, there really isn’t a whole lot of code required to make this happen. The key piece is that you need to have the WSUS Administrator console installed (for Win2K8R2 and below) or the UpdateServices module available (Win2K12 and above).
I will break down the code below and at the very end have all of it available to copy to create. My idea behind this is to just make a scheduled job that can be used to run every second Wednesday (after Patch Tuesday) to automatically decline all of these unneeded updates.
Param (
[string]$UpdateServer = 'DC1',
[int]$Port = 80,
[bool]$Secure = $False
)
This is my main parameters that are configurable based on your environment. Here I decide server I will connect to, the port that is open on the server and if the connection is secure.
If (-Not (Import-Module UpdateServices -PassThru)) {
Add-Type -Path `
"$Env:ProgramFiles\Update Services\Api\Microsoft.UpdateServices.Administration.dll" -PassThru
}
A check is made for the UpdateServices module by actually attempting to import the module. I call –Passthru so an object is outputted which can then be used in the If statement. If no object is outputted, then it is assumed that the module doesn’t exist, the OS doesn’t support the module, etc… and then attempts to load the assembly from a known good location.
$Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::` GetUpdateServer($UpdateServer,$Secure,$Port)
Finally, a connection is made to the WSUS server using the parameters specified.
$approveState = 'Microsoft.UpdateServices.Administration.ApprovedStates' -as [type]
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope -Property @{
TextIncludes = 'itanium'
ApprovedStates = $approveState::NotApproved,
$approveState::LatestRevisionApproved,
$approveState::HasStaleUpdateApprovals
}
Here I begin to piece together the filter that will be used with the query for updates. I create an object that holds the ApprovedStates enumeration which will make it easier to find what I can use with the creation of the UpdateScope object. Speaking of the UpdateScope object, this is the filtering piece that I will include with my query. I make sure that I specify itanium as for the TextIncludes propery as well as the ApprovedStates. Because I want to make sure that all non-approved and all non-declined updates have been found, I add the necessary ApprovedStates to the object.
$wsus.GetUpdates($updateScope) | ForEach {
Write-Verbose ("Declining {0}" -f $_.Title) -Verbose
$_.Decline()
}
Lastly, I can now finally begin declining all of these updates that have been found by my query. Fortunately, all I need to do is call the Decline() method associated with each update object.
You can download the source code for this below and modify it to suit your needs before deploying it in your environment as a scheduled job!
In my case, I will use PowerShell to create my scheduled job.
$triggerParam = @{
At = "12:00 AM"
DaysOfWeek = 'Wednesday'
WeeksInterval = 1
Weekly = $True
}
$trigger = New-JobTrigger @triggerParam
$JobParam = @{
Trigger = $trigger
FilePath = 'C:\DeclineItanium.ps1'
Name = 'DeclineItaniumUpdates'
}
Register-ScheduledJob @JobParam
Source Code
Param (
[string]$UpdateServer = 'DC1',
[int]$Port = 80,
[bool]$Secure = $False
)
If (-Not (Import-Module UpdateServices -PassThru)) {
Add-Type -Path "$Env:ProgramFiles\Update Services\Api\Microsoft.UpdateServices.Administration.dll" -PassThru
}
$Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::`
GetUpdateServer($UpdateServer,$Secure,$Port)
$approveState = 'Microsoft.UpdateServices.Administration.ApprovedStates' -as [type]
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope -Property @{
TextIncludes = 'itanium'
ApprovedStates = $approveState::NotApproved,
$approveState::LatestRevisionApproved,
$approveState::HasStaleUpdateApprovals
}
$wsus.GetUpdates($updateScope) | ForEach {
Write-Verbose ("Declining {0}" -f $_.Title) -Verbose
$_.Decline()
}
