March 9th, 2009

Hey, Scripting Guy! How Can I List All Updates That Have Been Added to a Computer?

Hey, Scripting Guy! Question

Hey, Scripting Guy! We have Windows Update configured on all our workstations at work. Automatically, the workstations check for new updates, and download and install the updates that are required. This happens without user intervention, or from intervention on the part of our small and overworked IT department. Here is the problem. The pointy-headed boss (PHB) came floating into our office late Friday afternoon and asked “How do you know all the workstations are up to date?” I said, because we have Windows Update configured on all the workstations.” He said, “Can you display a list of all the updates that have ever been applied to that computer?” I said, “D’oh!” So, Scripting Guy, can you hook me up with a script to list all the updates that have been added to a computer?

– JU

SpacerHey, Scripting Guy! Answer

Hi JU,

I just hate not having an answer when the PHB comes floating by. Usually, I just make something up, because I figure he will not really know the difference anyway. Luckily, Windows Update has an API we can use to obtain information regarding updates that have been applied to the system.

This week we will be looking at using the Windows Update API to work with Windows Update. The Windows Update API is documented on MSDN. There is also a good collection of VBScripts that use the Windows Update API in the Script Center Script Repository. For information about manually configuring Windows Update on workstations, refer to this page. These scripts use Windows PowerShell. The Windows PowerShell getting started page has basic information for learning about Windows PowerShell and about downloading Windows PowerShell.

The script we wrote is called Get-MicrosoftUpdates.ps1 and it is seen here (you can also see a VBScript version of today’s script):.

Function Get-MicrosoftUpdates
{ 
  Param(
        $NumberOfUpdates,
        [switch]$all
       )
  $Session = New-Object -ComObject Microsoft.Update.Session
  $Searcher = $Session.CreateUpdateSearcher()
  if($all)
    {
      $HistoryCount = $Searcher.GetTotalHistoryCount()
      $Searcher.QueryHistory(1,$HistoryCount)
    }
  Else { $Searcher.QueryHistory(1,$NumberOfUpdates) }
} #end Get-MicrosoftUpdates

Get-MicrosoftUpdates

The first thing we do in the script is create a function named Get-MicrosoftUpdates. To create a function in Windows PowerShell, we use the Function keyword, assign a name, and open and close the script block by using two curly brackets. The basic pattern is seen here:

Function FunctionName
{
# Function code goes here
} #end of the function

Here is the portion of our script that creates the function and assigns a name to it:

Function Get-MicrosoftUpdates
{

Now we create two command parameters. To do this, we use the Param keyword. The pattern we use to include parameters in a function is the same pattern as the one we use for a script. We use the Param keyword, open a set of parentheses, separate each parameter with a comma, and then close the set of parentheses. This pattern is seen here:

Param(Parametername, additionalParameterName)

In this script we use two parameters. The first parameter is called –NumberOfUpdates. The value supplied to this parameter when calling the function will be stored in the $NumberOfUpdates variable. The second parameter is a switched parameter named –all. A switched parameter does not receive a value when it is used—rather, it only has effect when it is present. When the –all parameter is not present, the script does not return all the updates. The parameter section of the Get-MicrosoftUpdates function is seen here:

Param(
        $NumberOfUpdates,
        [switch]$all
       )

It is time to create an instance of the Microsoft Update Session object (technically known as the IUpdateSession interface). The Microsoft Update Session object is a COM object, and can be created by using the New-Object cmdlet with the –ComObject parameter. It is not necessary to place quotation marks around the program ID Microsoft.Update.Session when using the New-Object cmdlet. We store the returned object in the $session variable, as seen here:

$Session = New-Object -ComObject Microsoft.Update.Session

The Session object has a number of methods and properties available, which are listed in Table 1.

Table 1 Members of the Microsoft Update Session object
Name Type Definition

CreateUpdateDownloader

Method

IUpdateDownloader CreateUpdateDownload

CreateUpdateInstaller

Method

IUpdateInstaller CreateUpdateInstaller ()

CreateUpdateSearcher

Method

IUpdateSearcher CreateUpdateSearcher ()

CreateUpdateServiceManager

Method

IUpdateServiceManager2 CreateUpdateSer

QueryHistory

Method

IUpdateHistoryEntryCollection QueryHis

ClientApplicationID

Property

string ClientApplicationID () {get} {s

ReadOnly

Property

bool ReadOnly () {get}

UserLocale

Property

uint UserLocale () {get} {set}

WebProxy

Property

IWebProxy WebProxy () {get} {set}

Now we need to create an UpdateSearcher object. To create an Update Searcher object, we use the CreateUpdateSearcher method from the Session object. We store the Searcher object in the variable $Searcher as seen here:

$Searcher = $Session.CreateUpdateSearcher()

Then we need to determine if the function was called with the –all switch or not. If the function was called with the –all switch, the $all variable will be present. If it was not used, the $all variable will not exist. We use the if statement to determine if the $all variable is present. An example of using the if statement to test for the presence of a variable is seen here:

PS C:\> $all = $true
PS C:\> if($all) {‘$all was found’}
$all was found

If we want to see if the $all variable is not present, we can use the not (!) operator as shown here:

PS C:\> $all = $false
PS C:\> if(!$all) {‘$all was not found’}
$all was not found

In our script, we use the if statement and look for the $all variable. If we find it, we use the GetTotalHistoryCount property from the Searcher object to retrieve the total number of updates that have been applied to the system. We need this information because the QueryHistory method of the Searcher object needs a starting point and an ending point. If we want to get all the updates, we start at one and go until we have reached the total number of updates applied to the system. This is seen here:

if($all)
    {
      $HistoryCount = $Searcher.GetTotalHistoryCount()
      $Searcher.QueryHistory(1,$HistoryCount)
    }

If the script was not run with the –all switched parameter, we will be retrieving a specific number of updates from the system. The total number of updates to be retrieved is passed to the function via the –NumberOfUpdates parameter and will be stored in the $NumberOfUpdates variable. This section of the script is seen here:

Else { $Searcher.QueryHistory(1,$NumberOfUpdates) }
} #end Get-MicrosoftUpdates

To retrieve all the update information, you call the Get-MicrosoftUpdates function with the –all parameter:

Get-MicrosoftUpdates –all

When we call the function with the –all parameter, we are treated with an output similar to the one seen here:

Image of the output produced by the script

 

If we call the function with the –NumberOfUpdates parameter set to 1, we retrieve the most recent update that was applied to the system. The syntax for this is seen here:

Get-MicrosoftUpdates –NumberOfUpdates 1

When we do this, we are treated with the output seen here:

Image of the output produced by the script

 

If we decide we would like to have a text file that contains all of the update information, we only need to use the redirection arrows as shown here when we call the function:

Get-MicrosoftUpdates -all >> c:\fso\updates.txt ; notepad c:\fso\updates.txt

Well, JU, that is all there is to querying the update history for Windows Update. If you were to compare the VBScript version and the Windows PowerShell version, you would notice we receive a nice bonus when using Windows PowerShell in that we do not need to use a wscript.echo kind of line for each of the properties in which we are interested. We used the extra lines of code to create a function and to allow the ability to choose how many updates to report. Hope you have a great day, and we will see you tomorrow as Windows Update Week continues. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Author

0 comments

Discussion are closed.