How to check Updates installed with Powershell.

David Paris VicenteInfrastructure Designer
Published:
Updated:
Note: You need at least Powershell version 3 to run this script, and PSRemoting enabled in your Windows Server 2008 and above versions. In case you don't have enabled the PSRemoting you can just use the function created in this article.

In this past week I had to check the updates installed on all of our Windows servers (W2K3, W2k8 and W2K12). This would be easily done if they were just a few of them but this was not the case.

So I started digging a way of doing this with Powershell. At first, I found an IUpdateSession interface and after reading it I concluded that this could help me gather the info that I needed.

The only requirements are:
Minimum Supported Client: Windows XP, Windows 2000 Professional SP3
Minimum Supported Server: W2k3, Windows 2000 SP3

For further information regarding this interface I advise you to check it here. The first thing we need to do is to create a comObject and check the properties and Methods of Microsoft.Update.Session. For that we are going to use the get-member cmdlet:
PS H:\Powershell> New-Object -ComObject Microsoft.Update.Session |gm
                      
                         TypeName: System.__ComObject#{918efd1e-b5d8-4c90-8540-aeb9bdc56f9d}
                      
                      Name                       MemberType Definition                                                   
                      ----                       ---------- ----------                                                   
                      CreateUpdateDownloader     Method     IUpdateDownloader CreateUpdateDownloader ()                  
                      CreateUpdateInstaller      Method     IUpdateInstaller CreateUpdateInstaller ()                    
                      CreateUpdateSearcher       Method     IUpdateSearcher CreateUpdateSearcher ()                      
                      CreateUpdateServiceManager Method     IUpdateServiceManager2 CreateUpdateServiceManager ()         
                      QueryHistory               Method     IUpdateHistoryEntryCollection QueryHistory (string, int, int)
                      ClientApplicationID        Property   string ClientApplicationID () {get} {set}                    
                      ReadOnly                   Property   bool ReadOnly () {get}                                       
                      UserLocale                 Property   uint UserLocale () {get} {set}                               
                      WebProxy                   Property   IWebProxy WebProxy () {get} {set}                            
                      
                      PS H:\Powershell> 
                      

Open in new window


As we can see there are several methods but we'll just use these two:

CreateUpdateSearcher       Method     IUpdateSearcher CreateUpdateSearcher ()    
                      QueryHistory               Method     IUpdateHistoryEntryCollection QueryHistory (string, int, int)
                      

Open in new window


We will use a variable to catch all the information from that new object.
$obj= New-Object -ComObject Microsoft.Update.Session
                      

Open in new window

We also want to store the CreateUpdateSearcher method inside a variable.

$obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      

Open in new window

Now, let's see what is stored in the $Search variable and check its properties and methods,

PS H:\Powershell> $Search
                      
                      CanAutomaticallyUpgradeService      : False
                      ClientApplicationID                 : 
                      IncludePotentiallySupersededUpdates : False
                      ServerSelection                     : 0
                      Online                              : True
                      ServiceID                           : 00000000-0000-0000-0000-000000000000
                      IgnoreDownloadPriority              : False
                      SearchScope                         : 0
                      
                      PS H:\Powershell> 
                      

Open in new window


As we can see, none of the information is relevant for what we want to accomplish, so we look at it with the get-member cmdlet,
PS H:\Powershell> $Search|gm
                      
                         TypeName: System.__ComObject#{04c6895d-eaf2-4034-97f3-311de9be413a}
                      
                      Name                                MemberType Definition                                              
                      ----                                ---------- ----------                                              
                      BeginSearch                         Method     ISearchJob BeginSearch (string, IUnknown, Variant)      
                      EndSearch                           Method     ISearchResult EndSearch (ISearchJob)                    
                      EscapeString                        Method     string EscapeString (string)                            
                      GetTotalHistoryCount                Method     int GetTotalHistoryCount ()                             
                      QueryHistory                        Method     IUpdateHistoryEntryCollection QueryHistory (int, int)   
                      Search                              Method     ISearchResult Search (string)                           
                      CanAutomaticallyUpgradeService      Property   bool CanAutomaticallyUpgradeService () {get} {set}      
                      ClientApplicationID                 Property   string ClientApplicationID () {get} {set}               
                      IgnoreDownloadPriority              Property   bool IgnoreDownloadPriority () {get} {set}              
                      IncludePotentiallySupersededUpdates Property   bool IncludePotentiallySupersededUpdates () {get} {set} 
                      Online                              Property   bool Online () {get} {set}                              
                      SearchScope                         Property   SearchScope SearchScope () {get} {set}                  
                      ServerSelection                     Property   ServerSelection ServerSelection () {get} {set}          
                      ServiceID                           Property   string ServiceID () {get} {set}                         
                      
                      PS H:\Powershell> 
                      

Open in new window


We add GetTotalHistoryCount Method to our script and run all the code lines that we already have, and call the HistoryCount Variable.

$obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      $HistoryCount = $Search.GetTotalHistoryCount()
                      
                      PS H:\Powershell> $HistoryCount
                      149
                      

Open in new window


We can see that my computer has 149 updates; yours will have a different value.

But this doesn't show you which are the updates installed, just how many. If you recall at the beginning  we created the comObject for Microsoft.Update.Session and one of its methods is the QueryHistory, so we add this method to our code and run it. 

TIP : After writing the code lines in the script pane in Powershell ISE and after selecting all the code lines, you can hit the F8 key Powershell as it will compile and run automatically.
$obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      $HistoryCount = $Search.GetTotalHistoryCount()
                      
                      $Search.QueryHistory(0, $HistoryCount)
                      

Open in new window


If you run the script, it will show you all the information regarding all the installed updates. Due to the volume of information, I'm not including here a screenshot, but as you can see, you have all the info related with the updates.

In my case I want to choose the last five updates, so I'm going to tweak the QueryHistory method and change the history count to 5.
$obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      $HistoryCount = $Search.GetTotalHistoryCount()
                      
                      $Search.QueryHistory(0, 5)
                      

Open in new window


Then run the Script again, and check the result.

At this stage we can create a function with a condition to show all the updates or just a few.
function Get-MsUpdates{
                      
                      param($nupdates,[Parameter(Mandatory=$true)][string]$HostName)
                      
                      $obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      $HistoryCount = $Search.GetTotalHistoryCount()
                      
                          if($nupdates -eq $null){
                          $Search.QueryHistory(0, $HistoryCount)
                          }else
                          {
                              $Search.QueryHistory(0, $nupdates)
                          }
                      }
                      

Open in new window


Now, if you run the function
PS H:\Powershell> Get-MsUpdates -HostName localhost
                      

Open in new window

This will show you all the updates installed  or, if you want to filter, you just have to use -nupdates option, something like this,

PS H:\Powershell> Get-MsUpdates -nupdates 5 -HostName localhost
                      

Open in new window

And it will show you the last five updates.

Now we can see all the updates through Powershell Scripting, but we don't need all that information. We also want to run this script in all servers, so we will need a few more code lines.
 
function Get-MsUpdates{
                      
                      param($nupdates,[Parameter(Mandatory=$true)][string]$HostName)
                      
                      $obj= New-Object -ComObject Microsoft.Update.Session
                      $Search= $obj.CreateUpdateSearcher()
                      $HistoryCount = $Search.GetTotalHistoryCount()
                      
                          if($nupdates -eq $null){
                          $Search.QueryHistory(0, $HistoryCount)
                          }else
                          {
                              $Search.QueryHistory(0, $nupdates)
                          }
                      }
                      
                      #What this will do, will get the machine names from a file, check the updates on Windows Server 2003 and above and create a log with teh checked servers
                      #And Errors that may occur
                      
                      #In my case I'm getting credentials from a file and pass this credentials to the commandas below
                      $pass= Get-Content '.\cred.txt' |ConvertTo-SecureString
                      $user= 'dparisfe'
                      $credentials= New-Object -TypeName System.Management.Automation.pscredential -ArgumentList $user,$pass
                      
                      
                      write-host "Insert the number of updates to Search or Press [Enter] to all updates?" -Foregroundcolor Green
                      [int]$Num=read-host
                      
                      if ($Num -eq 0 ){
                            Write-Host "You choosed 0 or pressed the [Enter] Key, this will show you all updates." -Foregroundcolor Green
                           $Num= 10000
                      }
                      
                      
                      $File=Get-Content -Path '.\My_hosts.txt' #Change this to pointing to your file Path
                      $date=get-date -format d
                      
                          foreach ($Hosts in $file)
                          {
                              $Computername=$Hosts
                                $Object = New-Object -TypeName PSObject
                                Invoke-Command -ComputerName $Computername -Credential $credentials -scriptblock ${function:get-MsUpdates} -ArgumentList $Num, $Computername |Select-Object Date,@{expression={$COMPUTERNAME};Label="Host"},@{name="Operation"; expression={switch($_.operation){1 {"Installation"}; 2 {"Uninstallation"}; 3 {"Other"}}}},@{name="Status"; expression={switch($_.resultcode){1 {"In Progress"}; 2 {"Succeeded"}; 3 {"Succeeded With Errors"};4 {"Failed"}; 5 {"Aborted"}}}},@{name="Title";expression={[regex]::Match($_.Title,'(KB[0-9]{6,7})').Value}}|FT
                              }
                          }
                         
                          
                      

Open in new window


Save it and give the script a name. In my case it will  be MSupdate.ps1. From PS command line we call the MSupdate.ps1
PS H:\Powershell> .\MSUpdate.ps1
                      Insert the number of updates to Search or Press [Enter] to all updates?
                      5
                      
                      Date                            Host                            Operation                       Status                          Title                          
                      ----                            ----                            ---------                       ------                          -----                          
                      08/01/2015 22:44:11             BCN-C77MM12                     Installation                    Succeeded                       KB2819745                      
                      08/12/2014 15:29:43             BCN-C77MM12                     Installation                    Succeeded                       KB2506143                      
                      04/12/2014 8:20:20              BCN-C77MM12                     Installation                    Succeeded                       KB2837579                      
                      04/12/2014 8:20:10              BCN-C77MM12                     Installation                    Succeeded                       KB2878284                      
                      04/12/2014 8:19:59              BCN-C77MM12                     Installation                    Succeeded                       KB2687567                      
                      
                      
                      
                      PS H:\Powershell> 
                      

Open in new window


After this you can tweak it a little more and send it to a file or email.
 
9
3,037 Views
David Paris VicenteInfrastructure Designer

Comments (3)

Dale HarrisSenior Solutions Engineer

Commented:
This is awesome! Thanks for the write up and look forward to being able to use this!
Pedro GamaCitrix Admin

Commented:
Thanks Vicente! Your script has been really helpful! Keep up the good work!

PG
This is cool ! thank you for sharing ..

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.