Use PowerShell to Find Missing Updates on WSUS Client Computers

Summary: Learn how to use the computer target scope with Windows PowerShell to find WSUS client computers that are missing updates.

Microsoft Scripting Guy, Ed Wilson, is here. We are halfway through WSUS Week and some really good stuff from Boe Prox. You can see Boe’s biography in the Day 1 blog. In case you need to catch up with the series on Windows Software Update Services (WSUS), the following blogs will get you up to speed:

Day 1: Introduction to WSUS and PowerShell

Day 2: Use PowerShell to Perform Basic Administrative Tasks on WSUS

Day 3: Approve or Decline WSUS Updates by Using PowerShell

Now, here is Boe…

Over the past few days, I have been showing you some basic administration examples of what you can do by using Windows PowerShell to manage a WSUS server. During the course of some of these examples, I alluded to some methods that required a Computer Target Scope object. Well, today is the day that I get to show you how you can build a Computer Target Scope object and use that with some of the existing objects we have already created.

“What is the Computer Target Scope?” you ask? The Computer Target Scope is, as the name implies, a scope that that can be used to filter a list of clients. For more information about this class, see ComputerTargetScope Class on MSDN.

Creating the Computer Target Scope object

The first thing we need to do is create the scope object, which we can then use in some of the methods we have seen. To do this will require us to create the new object from the Microsoft.UpdateServices.Administration.ComputerTargetScope class.

$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

Simple enough to do, and we can choose to leave the default properties that are already set for this object if we want to.

Image of command output

So as a default object, this will reference all clients on the WSUS server. Fortunately, you can edit most of these properties to narrow down the clients that you want to use. Here is a list of the editable properties:



Gets or sets the installation states to exclude.



Gets or sets the earliest reported status time.



Gets or sets the earliest last synchronization time to search for.



Gets or sets the update installation states to search for.



Gets or sets whether or not clients of a downstream server, not clients of this server, should be included.



Gets or sets whether the ComputerTargetGroups property should include descendant groups.



Gets or sets a name to search for.



Gets or sets the operating system family for which to search.



Gets or sets the latest last reported status time to search for.



Gets or sets the latest last synchronization time to search for.

Working with the Computer Target Scope

Now, if you remember from the previous posts, there are some methods from the Update object (Microsoft.UpdateServices.Internal.BaseApi.Update) and from the WSUS object (Microsoft.UpdateServices.Internal.BaseApi.UpdateServer) that require a computer scope object to work.

Let’s take a look at some of these methods from the respective objects and see what we are able to pull.


#Connect to the WSUS Server and create the wsus object

$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer('dc1',$False)

#Create a computer scope object

$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

#Find all clients using the computer target scope


Image of command output

By leaving the default properties, we will pull every client from the WSUS server.

Another method that we can use, which provides a report on the computers that match the scope filter is GetComputerStatus(). This method requires that you have a computer scope object and that you define a Microsoft.UpdateServices.Administration.UpdateSources object, which consists of All, Microsoft Update, or Other. Let’s give it a look.

$Wsus.GetComputerStatus($computerscope,[ Microsoft.UpdateServices.Administration.UpdateSources]::All)

Image of command output

You might be wondering why we are seeing mostly 0s here. If you look closely, you can see that only the areas where it mentions the computer targets are populated. This is by design for this object’s method because we only specified to get the status of the computers that match the scope filter.

Now, looking at the update object’s method, I can see a couple of methods that are available and require the computer scope.


This will give us a summary of whether the clients that are specified in the scope require the update.

$updates = $wsus.SearchUpdates('Update for Windows Server 2003 (KB938759)')

$update = $updates[0]



UnknownCount                : 0

NotApplicableCount          : 2

NotInstalledCount           : 0

DownloadedCount             : 1

InstalledCount              : 0

InstalledPendingRebootCount : 0

FailedCount                 : 0

IsSummedAcrossAllUpdates    : False

UpdateId                    : c2cdd066-7a03-4e7f-976c-139b5de943ed

ComputerTargetGroupId       : 00000000-0000-0000-0000-000000000000

ComputerTargetId            :

LastUpdated                 : 12/10/2011 7:08:29 AM

By looking at the data provided, I can see that only 1 client out of the 3 require this update and that it has already been downloaded to that client. This is a nice way of providing a report of a specific update’s status for clients. But the problem is…which client requires the update? I will show you how to use the GetUpdateInstallationInfoPerComputerTarget() method on the Update object.


Image of command output

Although it does tell you which client ID requires the update, it’s not what I would call “humanly readable” by any means. But this is Windows PowerShell, after all, and we can certainly make this better for us to read.

$update.GetUpdateInstallationInfoPerComputerTarget($ComputerScope) |

 Select @{L='Client';E={$wsus.GetComputerTarget(([guid]$_.ComputerTargetId)).FulldomainName}},




Image of command output

Much better! Now we have something that not only tells us which client, but actually gives us the name of the client without giving us a GUID to try to guess with. I also translated the Target Group ID and the Update ID so that everything is much easier to read.

Well, that wraps it up for today. Tomorrow I will jump into working with the Update Scope object and performing queries that use that object.


Boe, thank you for another great blog about using the WSUS object model. WSUS Week will continue tomorrow.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (15)

  1. Boe Prox says:


    Figures as soon as I say that it cannot be done, I find out how to do it.

    $ComputerScope=New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
    $Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($Computername,$UseSSL,$Port)
    $TargetGroupHash = @{}
    $wsus.GetComputerTargetGroups() | ForEach {
    $TargetGroupHash[$_.Name] = $_
    $ComputerScope.ComputerTargetGroups.Add($TargetGroupHash[‘Unassigned Computers’])

  2. Boe Prox says:

    This can be done by first using my previous post here to filter for only servers and collecting the GUID of each computer (ID property). Then, using the article where I talk about using the GetSummariesPerComputerTarget() method, we can generate the update summary and begin filtering out non servers by checking it against our collection of servers. This should give you what you are looking for.

    #Load assemblies


    #Connect to WSUS

    $Global:wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer('j23',$False)

    #Create Scope objects

    $computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

    $updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope

    #Gather only servers

    $ServersId = @($wsus.GetComputerTargets($computerscope) | Where {

       $_.OSDescription -like "*Server*"

    } | Select -expand Id)

    #Get Update Summary

    $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | Where {

       #Filter out non servers

       $ServersId -Contains $_.ComputerTargetID

    } | ForEach {

       New-Object PSObject -Property @{

           ComputerTarget = ($wsus.GetComputerTarget([guid]$_.ComputerTargetId)).FullDomainName

           NeededCount = ($_.DownloadedCount + $_.NotInstalledCount)

           DownloadedCount = $_.DownloadedCount

           NotApplicableCount = $_.NotApplicableCount

           NotInstalledCount = $_.NotInstalledCount

           InstalledCount = $_.InstalledCount

           FailedCount = $_.FailedCount



    Hope this helps…

  3. Boe Prox says:

    As far as I know, this is not possible.

  4. Boe Prox says:

    Hi Davy,

    Glad you have enjoyed my series on WSUS! Unfortunately, the ComputerScope does not lend itself very well to identifying only servers in WSUS, you would have better luck with using a generic search and filter by OSDescription.

    $wsus.GetComputerTargets() | Where {$_.OSDescription -like "*server*"}

    Or if you have Target Groups with a name containing server, for example:

    $wsus.GetComputerTargetGroups() | Where {$ -Like '*Server*'} | ForEach {$_.GetComputerTargets()}

    Hope this helps…

  5. Boe Prox says:

    @kicho That can be accomplished using the following code: #Load assemblies [void][system.reflection.assembly]::LoadWithPartialName(‘Microsoft.UpdateServices.Administration’) #Connect to WSUS $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer(”,$False)
    $computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope #Threshold here is to report anything over 30 days old, but can be adjusted to fit your requirements $computerscope.ToLastReportedStatusTime = (Get-Date).AddDays(-30) $Wsus.GetComputerTargets($computerscope)
    | ForEach { If ($_.LastReportedStatusTime -eq ‘1/1/0001 12:00:00 AM’) { $status = ‘NeverReported’ } Else { $status = (New-TimeSpan -Start $_.LastReportedStatusTime -End (Get-Date)).Days } [pscustomobject]@{ Computername = $_.FullDomainName IP = $_.IPAddress
    LastReportedStatus = $_.LastReportedStatusTime DaysOld = $status } }

  6. Davy says:

    Hi Boe,

    Thumbs up for the great blogs!

    Is it possible that the computerscope only contains servers? What command would get that result?


  7. Davy says:

    Thanks for your reply.

    What I wanted to achive is that I could get a list of our servers that have updates waiting and the number of updates.

    But I can't seem to get it done.

    Any tips?

  8. kircho says:

    Hi, First of all – Great job. It’s really nice to see things arranged and explained. Second, there is a report I would like to get from my WSUS. Unfortunately I couldn’t find it in WSUS console. I hope that you could help me. I want to perform on a regular
    basis a report about clients that have failed to report to the server. Currently I saw a lot of computers that didn’t report, and we are talking for arround 300 PCs in different OUs in one domain. I just need information about hostnames, IPs, and how many
    days. Is it possible to be achieved?

  9. Boby says:

    Hi All, thanks Boe for those explanation, there are very usefull!
    I’m trying to change ComputerTargetGroups of “Computer Target Scope” object but i can’t.
    I would like to filter to a different target group, like “unassigned computers”, is that possible?



  10. Robert says:

    This is great! I need some help. I need a report to see how many computers have had internet explorer 10 installed with the list of computernames. Is that possible? Can you tell me how?

    Thank you

  11. Robert says:

    Wouldn’t that be awesome though? Thanks for your response.

  12. Angelo74 says:


    First of all: THANK YOU (!!!) for this great Blogs. They are very useful an helped me a lot with my Project.
    But now to my Problem:
    I know this is a very old Thread, but is it possible to include Windows 7 Clients? I have a Script,which shows me every Client who need Updates,except of Windows 7 Clients. Is someone here,who could help me?



  13. Peter says:

    Hi Boe,

    i try to get additional Information about Computer objects like ComputerTargetGroupNames in WSUS but can’t find the correct query. Any ideas? Actually i get every WSUS Group but i only want the belonging Group to very Client.

    Kind regards

    #Load assemblies


    #Create Scope objects

    $computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope

    $updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope

    #$groupscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetCollection

    #Gather groups

    #$GroupId = @($wsus.GetComputerTargetGroup($groupscope))

    #Gather only servers

    $ServersId = @($wsus.GetComputerTargets($computerscope) | Where {

    $_.OSDescription -like "*Server*"

    } | Select -expand Id)

    #Get Update Summary

    $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | Where {

    #Filter out non servers

    $ServersId -Contains $_.ComputerTargetID

    } | ForEach {

    New-Object PSObject -Property @{

    ComputerTarget = ($wsus.GetComputerTarget([guid]$_.ComputerTargetId)).FullDomainName

    ComputerTargetGroupIDs = ($wsus.GetComputerTarget([guid]$_.ComputerTargetId)).ComputerTargetGroupIds

    ComputerTargetGroupNames = ($wsus.GetComputerTargetGroups())

    NeededCount = ($_.DownloadedCount + $_.NotInstalledCount)

    #DownloadedCount = $_.DownloadedCount

    NotInstalledCount = $_.NotInstalledCount

    #InstalledCount = $_.InstalledCount


  14. Dan_IT says:

    This is awesome…thank you very much. Question, I’d like to identify the computers that are less then a percentage installed with updates (say 95%). I’ve got the following so far, but how can I filter it by percent?
    $computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
    $updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
    $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | ForEach {
    New-Object PSObject -Property @{
    ComputerTarget = ($wsus.GetComputerTarget([guid]$_.ComputerTargetId)).FullDomainName
    NeededCount = ($_.DownloadedCount + $_.NotInstalledCount)
    DownloadedCount = $_.DownloadedCount
    NotApplicableCount = $_.NotApplicableCount
    NotInstalledCount = $_.NotInstalledCount
    InstalledCount = $_.InstalledCount
    FailedCount = $_.FailedCount
    percent = (($_.NotApplicableCount – $_.InstalledCount) / $_.NotApplicableCount * 100)

  15. John_Curtiss says:

    the following would be a valuable report:

    all workstations that are missing updates *that have been approved for them* in WSUS.

    so if workstation1 needs five updates, but none of them have been Approved for workstation1, I don’t want workstation1 in the output.

    if workstation2 needs seven updates, and two of them have been Approved for workstation2, I want workstation2 in the output.

    even better would be a list of the needed+approved updates.

Skip to main content