Find Pending Updates via the SCCM Client Agent With PowerShell

One of the nice things about SCCM is that you can use it along with WSUS to push out software updates for your operating system. an even better thing is that the API is accessible via PowerShell. There are several other areas within the SCCM Client that you can access and work with using PowerShell, but for this case I am focusing solely on the UpdatesDeployment Interface that handles all of the patches being pushed out to the clients from SCCM. In case you haven’t noticed, the Windows Update Agent does not play any role when you are using the SCCM Client agent.

So where do we begin with connecting to the SCCM Client? We need to find the COM object that corresponds to the interface. In this case, it is the UDA.CCMUpdatesDeployment COM object.

$SCCMUpdate = New-Object -ComObject UDA.CCMUpdatesDeployment
$SCCMUpdate | Get-Member

image

Edit: Make sure that you are running this on the 32-bit PowerShell session and not on the 64-bit session, otherwise the COM object creation will fail. Thanks to Jen Egil Ring (Blog | Twitter) for pointing this out!

I as hoping for a remote way of accomplishing this connection similar to what I did with the windows update agent COM object, but unfortunately, I was unable to get it to work.

[activator]::CreateInstance([type]::GetTypeFromProgID("UDA.CCMUpdatesDeployment",$Env:Computername))

So for the time being, this works locally only, or if you are using PowerShell remoting.

But back to the picture above. As you can see, there are 8 methods that we can use to work with the UpdateDeployment obejct. The only method that I am concerned with here is the EnmerateUpdates() method. Using this we can find out what, if any, updates are available for installation and their current status according to the client. This method requires a few things to be supplied with it in order for the update enumeration to be successful.

We need the specific UpdateAction (this is a integer value 2 = Install; 3 = Uninstall), a boolean value to state whether to show updates based on the mode of the client, which in the case of the client I am using, the modes is quiet. Lastly, a reference is used for the progress of the update job. More information available about the EnumerateUpdates method is available here.

$SCCMUpdate.EnumerateUpdates
$updates = $SCCMUpdate.EnumerateUpdates(2,$True,[ref]"progress")
$updates | Get-Member

image

The update collection only has 2 methods, both of which I will show. It is a good idea to use the GetCount method just to see if there are able updates available.

$updates.GetCount()

image

Here we have 12 updates available for installation via the SCCM Client. So the question is, what updates are available? Fortunately, the GetUpdate() method is available to use to get this information. If you notice, the method requires an integer (each index for the collection) to see the update object.

Lets check out the first update, which is the 0 index for the collection.

$update = $updates.GetUpdate(0)
$updates | Get-Member

image

A lot of methods here that we need to use to view all of the properties for the update object. Some of the methods have specific values that need to be supplied in order to accurately pull information. Here is the code I used to to get the information along with how I handled each method that required data to be supplied.

$statusHash = [hashtable]@{
    0 = 'JobStateNone'
    1 = 'JobStateAvailable'
    2 = 'JobStateSubmitted'
    3 = 'JobStateDetecting'
    4 = 'JobStateDownloadingCIDef'
    5 = 'JobStateDownloadingSdmPkg'
    6 = 'JobStatePreDownload'
    7 = 'JobStateDownloading'
    8 = 'JobStateWaitInstall'
    9 = 'JobStateInstalling'
    10 = 'JobStatePendingSoftReboot'
    11 = 'JobStatePendingHardReboot'
    12 = 'JobStateWaitReboot'
    13 = 'JobStateVerifying'
    14 = 'JobStateInstallComplete'
    15 = 'JobStateStateError'
    16 = 'JobStateWaitServiceWindo'
}

[ref]$status=$Null
[ref]$Complete=$Null
[ref]$Errors=$Null
$UpdateObject = New-Object PSObject -Property @{
    KB = $update.GetArticleID()
    BulletinID = {Try {$update.GetBulletinID()} Catch {}}.invoke()
    DownloadSize = $update.GetDownloadSize()
    EnforcementDeadline = $update.GetEnforcementDeadline()
    ExclusiveUpdateOption = $update.GetExclusiveUpdateOption()
    ID = $update.GetID()
    InfoLink = $update.GetInfoLink(1033)
    Manufacture = $update.GetManufacturer(1033)
    Name = $update.GetName(1033)
    NotificationOption = $update.GetNotificationOption()
    Progress = $update.GetProgress($status,$Complete,$Errors)
    UpdateStatus = $statusHash[$status.value]
    ErrorCode = $Errors.Value
    RebootDeadling = $update.GetRebootDeadline()
    State = $update.GetState()
    Summary = $update.GetSummary(1033)
}
$UpdateObject.PSTypeNames.Insert(0,'SCCMUpdate.Update')
$UpdateObject

image

With that, you can see all of the information about that update object. Pretty handy to know if you are curious as to what is waiting to be installed on your client.

Let’s dive into a couple of the methods that have some extra requirements so we know better about what is going on. For instance, the Progress method requires some references to Status,Completion and any Errors. More information about the Progress method is here.

[ref]$status=$Null
[ref]$Complete=$Null
[ref]$Errors=$Null
$update.GetProgress($status,$Complete,$Errors)
$Status
$Complete
$Errors

image

Some simple translation for the Status code via a hash table:

$statusHash = [hashtable]@{
    0 = 'JobStateNone'
    1 = 'JobStateAvailable'
    2 = 'JobStateSubmitted'
    3 = 'JobStateDetecting'
    4 = 'JobStateDownloadingCIDef'
    5 = 'JobStateDownloadingSdmPkg'
    6 = 'JobStatePreDownload'
    7 = 'JobStateDownloading'
    8 = 'JobStateWaitInstall'
    9 = 'JobStateInstalling'
    10 = 'JobStatePendingSoftReboot'
    11 = 'JobStatePendingHardReboot'
    12 = 'JobStateWaitReboot'
    13 = 'JobStateVerifying'
    14 = 'JobStateInstallComplete'
    15 = 'JobStateStateError'
    16 = 'JobStateWaitServiceWindo'
}

Some other methods require the proper language code in order to get the best information. Language ID codes available here. In this case, 1033 is for English – United States.

$update.GetSummary(1033)
$update.GetInfoLink(1033)
$update.GetManufacturer(1033)
$update.GetName(1033)

The GetBulletinID() method does not always have a value to it and will throw an error if you are not careful. So in this case I use some Try/Catch to handle that error.

{Try {$update.GetBulletinID()} Catch {}}.invoke()

To make life simpler, I wrote a function to perform the task without little effort. I named it Get-SCCMClientUpdate and it is available for download on the Script Repository and the download link will be available below. An example of it is here:

Get-SCCMUpdate -ShowHidden | 
Format-Table Name,KB,BulletinID,EnforcementDeadline,UpdateStatus

image

In my testing I was unable to validate how well the Uninstall value being supplied with the –UpdateAction parameter. This could be just due to how the update deployments are being handled, but if anyone else can validate this, then please do so and post in the comments.

Download Link

Technet Script Repository

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

12 Responses to Find Pending Updates via the SCCM Client Agent With PowerShell

  1. Travis says:

    Any possibility of updating this for Config Mgr 2012 R2?

  2. maxflipz@live.com says:

    @boe What about this (GWMI -ComputerName $server -query “SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState = ‘0’” -namespace “ROOT\ccm\ClientSDK”).Count will show updates from SCCM that are in Compliance State 0 (missing)

  3. Luke says:

    Hi, can you please update the article to state that this is for 2007 only. The COM object you are referring does not exist in 2012.

    Thanks!

  4. Pingback: Automating the System Center Configuration Manager 2012 client | blog.powershell.no

  5. Nick says:

    So I am running Windows 8 with SC 2012 SP1 and I cannot even get started with this scripts.
    When I run the following on my Windows 8 Client Computer
    $SCCMUpdate = New-Object -ComObject UDA.CCMUpdatesDeployment

    It creates basically a blank com object with no real methods.
    Was UDA changed in the current release or maybe with windows 8?

    Example is below.
    $SCCMUpdate | Get-Member

    TypeName: System.__ComObject

    Name MemberType Definition
    —- ———- ———-
    CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
    Equals Method bool Equals(System.Object obj)
    GetHashCode Method int GetHashCode()
    GetLifetimeService Method System.Object GetLifetimeService()
    GetType Method type GetType()
    InitializeLifetimeService Method System.Object InitializeLifetimeService()
    ToString Method string ToString()

    Thanks,
    nick

    • Raz says:

      Hi, I get the same Methods here as well, I don’t have the enumerateupdates method, so this wont work for me. I run this on both Windows 7 and Server 2008 R2. Can anyone point me in the right direction here please? this would be a very useful script for me.
      Thanks
      Raz

  6. nick says:

    Hi ,

    Excellent scripts.

    Any chance of adding to it so it can be ran remotely ?

    Regards
    Nick

  7. Pingback: Installing Updates Via The SCCM Client | Learn Powershell | Achieve More

  8. Pingback: SCCM: Software Updates Client–automation « MS Tech BLOG

Leave a comment