WSUS: Approving and Declining Updates with PowerShell

Now that we have looked at viewing all of the updates on WSUS, we will now look at approving and declining those updates.  This can be a little bit tricky as you need to also know what Computer Target Group you want to approve each update for.  With that, lets take a quick look at how to locate the computer groups in WSUS.

Lets first make the connection to the WSUS server and then we can look at finding those groups:

$wsusserver = 'dc1'
#Load required assemblies
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($wsusserver,$False)

Untitled

Now to get the groups.  Using the $wsus variable, we see that there is a method called GetComputerTargetGroups() which we will use to list out all of the groups with their associated ID’s.

$wsus.GetComputerTargetGroups()

Untitled

As you can see, I have 3 groups in WSUS. The 2 default groups: Unassigned Computers and All Computers along with a group I added called Domain Servers. Now that we know how to get the groups, we can take a look at approving updates for a specific group.

First I am going to select just 1 update to approve.

$update = $wsus.GetUpdates() | Select -last 1

Untitled

Looking at the IsApproved property, it is currently set to False, meaning it has yet to be approved for installation.

So we know that this update has not been approved yet and we need to approve it for the Domain Servers target group. So…how do we do this?  First we need to look at the Approve() method under the $update variable to find out what type of data it accepts.

Untitled

We can see there are 2 ways of approving this patch:

  1. Supply the Action and Group
  2. Supply the Action, Group and a deadline

Let’s focus on the first way of approving the update.

Looks easy enough, just have to do $update.approve(“Install”,”Domain Server”) and we should be set…

Untitled

Hmm… now that is something we don’t need to see.  Looking back at the required values for the method, you will see the type of value that is expected for the method.

I can use the Action required type to find out what the accepted data is:

[Microsoft.UpdateServices.Administration.UpdateApprovalAction] | gm -static

Untitled

We see that there are 4 different values to choose from: All, Install, NotApproved, Uninstall

But wait, didn’t we try Install already and it failed? Yes, we did because we presented it as a string type, not as the type that was required.  so in order to accomplish this we do the following:

#Define the actions available for approving a patch
$all = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::All
$install = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install
$NotApproved = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::NotApproved
$Uninstall = [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Uninstall

Excellent, now looking back at what is required for the groups, we can tell that a simple string type will not suffice and that we need the actual object for groups.  Since we only want the one group, Domain Servers, we will need to only grab that group.

#List all available groups and their respective IDs
$wsus.GetComputerTargetGroups()
#Pick a group to approve an update for
$group = $wsus.GetComputerTargetGroups() | ? {$_.Name -eq "Domain Servers"}

Untitled

Ok, now we only have the Domain Servers group to approve our update for. By the way, the “?” being used is short-hand for Where-Object.

Lets give this another shot now:

#Approve the update
$update.Approve($install,$group)

Untitled

Success this time around.  As you can see, once you approve the update, you get some additional output to verify that your update was approved.  From here, you can tell when the update will be made available to clients for download by looking at the GoLiveTime property. In this case, the update will be made available on 10/16/2010 9:12:33 PM. Another interesting thing to note is the AdministratorName property, which tells you who approved the update. Also note that the Deadline property shows a timestamp of 12/31/9999 11:59:59 PM, which is because we did not specify a deadline.

To specify a deadline, you need to configure the deadline by using the Get-Date cmdlet or the [datetime] .NET accelerator. For this, I will set a deadline for Oct. 20 at 5pm.

#Configure Deadline
$deadline = [datetime]"10/20/2010 5:00PM"
#Approve the update with deadling
$update.Approve($install,$group,$deadline)

Untitled

Now the Deadline property shows 10/20/2010 5:00:00 PM.

If you want to see the Approval for an update, you can use the GetUpdateApprovals() method.

$update.GetUpdateApprovals()

Untitled

The one thing that I see here that might be confusing is the ComputerTargetGroupId which is the group that is update has been approved for. There are a couple of ways you can find out which group this translates to. Either using the code near the beginning of this post to list out all of the groups and locate the correct one:

$wsus.GetComputerTargetGroups() | ? {$_.ID -eq "76a6de42-3d93-4bbc-a8a4-76de3cc0c58f"}

Untitled

Or I have a function that is included in my WSUS module that I am still working on that will also perform the task.

function Convert-WSUSTargetGroup {
<#
.SYNOPSIS
    Converts the ID to a friendl name or friendly name to an ID
.DESCRIPTION
    Converts the ID to a friendl name or friendly name to an ID
.PARAMETER wsusserver
    Name of WSUS server to connect to.
.PARAMETER id
    Determines the name of the group using the supplied ID.
.PARAMETER name
    Determines the ID of the group using the supplied name.
.NOTES
    Name: Convert-WSUSTargetGroup
    Author: Boe Prox
    DateCreated: 24SEPT2010
.LINK
    https://boeprox.wordpress.org
.EXAMPLE
 Convert-WSUSTargetGroup -wsusserver 'server1' -name 'All Computers'
#>
[cmdletbinding(
	DefaultParameterSetName = 'name',
	ConfirmImpact = 'low'
)]
    Param(
        [Parameter(
            Mandatory = $True,
            Position = 0,
            ValueFromPipeline = $True)]
            [string]$wsusserver,
        [Parameter(
            Mandatory = $False,
            Position = 1,
            ParameterSetName = 'id',
            ValueFromPipeline = $False)]
            [string]$id,
        [Parameter(
            Mandatory = $False,
            Position = 2,
            ParameterSetName = 'name',
            ValueFromPipeline = $False)]
            [string]$name
            )
#Load required assemblies
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
#Connect to WSUS server
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($wsusserver,$False)
If ($name) {
    Try {
        Write-Verbose "Searching for ID via name"
        $group = $wsus.GetComputerTargetGroups() | ? {$_.Name -eq $name}
        $group | Select -ExpandProperty ID
        Continue
        }
    Catch {
        Write-Error "Unable to locate $($name)."
        }
    }
If ($id) {
    Try {
        Write-Verbose "Searching for name via ID"
        $group = $wsus.GetComputerTargetGroups() | ? {$_.ID -eq $id}
        $group | Select -ExpandProperty Name
        Continue
        }
    Catch {
        Write-Error "Unable to locate $($id)."
        }
    }
}

Function in action:

Untitled

This code snippet will report every update that has been approved and will list out the name of the update, deadline, Admin that approved it and the group that it was approved for:

$updates = $wsus.GetUpdates() | ? {$_.IsApproved -eq "True"}
$report = @()
ForEach ($update in $updates) {
    $approval = $update.GetUpdateApprovals() | % {
            $id = $_.ComputerTargetGroupId
            $temp = "" | Select Title, Group, Deadline, ApprovedBy, AvailableForDownload
            $temp.Title = $update.Title
            $temp.Deadline = $_.Deadline
            $temp.ApprovedBy = $_.AdministratorName
            $temp.AvailableForDownload = $_.GoLiveTime
            $temp.Group = $wsus.GetcomputerTargetGroups() | ? {$_.ID -eq $id} | Select -expand Name
            $report += $temp
        }
    }
$report

Untitled

Declining an update is much easier and requires nothing more than a boolean operation.

$update.Decline($True)

Untitled

Now we have declined this update. Pretty simple, eh?

As you can see, you can approve and decline updates using PowerShell and view all of the groups that have been created in WSUS with just a small amount of code.

This entry was posted in powershell, WSUS and tagged , , , , . Bookmark the permalink.

3 Responses to WSUS: Approving and Declining Updates with PowerShell

  1. Vincent says:

    Hi,

    I tried your solution and got an error message at the beginning of my script.

    Here is the error message:

    Exception lors de l’appel de « GetUpdateServer » avec « 3 » argument(s) : « Une exception a été levée par l’initialiseu
    r de type pour ‘Microsoft.UpdateServices.Internal.Constants’. »
    Au niveau de C:\Scripts\Connection_wsus.ps1 : 4 Caractère : 78
    + $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer <<<< ($wsusserver,$False)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Have you an idea of the origin of this message ?

    Thanks,

    Vincent

    • Dimitri says:

      Did you configure you WSUS with SSL?
      If this is the case, you should type:
      $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer <<<< ($wsusserver,$True,$portnumber)
      where $portnumber is 8531 or 81
      I had an issue like that the first time I play with Powershell and WSUS.
      Regards

  2. Pingback: Tweets that mention WSUS: Approving and Declining Updates with PowerShell | Learn Powershell | Achieve More -- Topsy.com

Leave a comment