<

How to check Updates installed with Powershell.

Published on
5,787 Points
1,887 Views
9 Endorsements
Last Modified:
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
Comment
3 Comments
LVL 16

Expert Comment

by:Dale Harris
This is awesome! Thanks for the write up and look forward to being able to use this!
0
LVL 6

Expert Comment

by:Pedro Gama
Thanks Vicente! Your script has been really helpful! Keep up the good work!

PG
0
LVL 2

Expert Comment

by:MilesLogan
This is cool ! thank you for sharing ..
0

Featured Post

Top Threats of Q1 & How to Defend Against Them

WEBINAR: Join WatchGuard CTO and our Threat Research Team on Aug. 2nd to hear the findings from our Q1 Internet Security Report! Learn more about the top threats detected in the first quarter and how you can defend your business against them!

Join & Write a Comment

Screencast - Getting to Know the Pipeline
Did you know PowerShell can save you time with SaaS platforms? Simply leverage RESTfulAPIs to build your own PowerShell modules. These will kill repetitive tickets and tabs, using the command Invoke-RestMethod. Tune into this webinar to learn how…

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month