27 April, 2013

List details of installed hotfixes remotely - OS

Hotfixing again. In one of the previous articles, I wrote about how to enumerate the list of installed patches on remote hosts and then find out the differences. The only caveat is that Get-Hotfix cmdlet (which basically uses WMI class Win32_QuickFixEngineering) doesn't contain too much information on the particular hotfix itself apart from the KB number.

However, the Windows Update Agent (WUA) has an API which can be access from PowerShell via COM (Microsoft.Update.Session) and can be called remotely to get almost all fields of an installed patch that you can see on the GUI:

An installed hotfix shown on the GUI of WUA

















But then it doesn't give you some useful data, e.g. who installed that fix, which can be found in the data read from WMI:

An installed hotfix listed by Get-Hotfix or Win32_QuickFixEngineering














Fortunately, you can get the data from the WUA API and WMI as well and merge them easily in PowerShell.
First things first, getting the list of fixes from WUA and store it in $HFDetails:
$HFobj = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$srv))
$objSearcher= $HFobj.CreateUpdateSearcher()
$allupdates = $objSearcher.GetTotalHistoryCount()
$HFDetails = $objSearcher.QueryHistory(0,$allupdates)

Then get the list of fixes from WMI:
Get-HotFix -ComputerName $srv | %{

Create an object with properties we are interested in and want to record from the two data sets:
$obj = "" | select ComputerName,HotfixID,InstalledOn,InstalledBy,Title,Description

The HotfixID, InstalledOn, InstalledBy fields come from the WMI data so I can add them to my object straight away:
$obj.HotfixID = $_.Hotfixid
$obj.InstalledOn = $_.Installedon
$obj.InstalledBy = $_.Installedby

Let's stop here a bit. There's a way to define a psobject with the list of properties and give them value at the same time, so why would I define it in one line and then add value to each attribute afterwards. The only reason is the order of attributes. When you define a psobject with a hash table, the order it displays the properties afterwards is random:
$obj = New-Object PSObject -Property @{ComputerName=$srv;HotfixID=$_.HotfixID...

Anyway, so we have 2 things we want from the WUA API. The title of the patch and the Description of it, which basically means finding the KB number in the WUA dataset and read the title and the Description:
$obj.Description = ($HFDetails | ?{$_.Title -imatch $obj.HotfixID}).description
$obj.Title = ($HFDetails | ?{$_.Title -imatch $obj.HotfixID}).Title

The full script is below (can be combined with the hotfix comparing script), taking the list of hosts from the pipe and recording the ComputerName as well. Sample output:










Full script:
 

 
 $hostlist = @($Input)

    
 foreach($srv in $hostlist){  
      $HFobj = $HFDetails = $allupdates = $objSearcher = $null  
      $HFobj = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$srv))  
      $objSearcher= $HFobj.CreateUpdateSearcher()  
      $allupdates = $objSearcher.GetTotalHistoryCount()  
      $HFDetails = $objSearcher.QueryHistory(0,$allupdates)  
   
      Get-HotFix -ComputerName $srv | %{  
           $obj = "" | select ComputerName,HotfixID,InstalledOn,InstalledBy,Title,Description  
           $obj.ComputerName=$srv  
           $obj.HotfixID = $_.Hotfixid  
           $obj.InstalledOn = $_.Installedon  
           $obj.InstalledBy = $_.Installedby  
           $obj.Description = ($HFDetails | ?{$_.Title -imatch $obj.HotfixID}).description  
           $obj.Title = ($HFDetails | ?{$_.Title -imatch $obj.HotfixID}).Title  
           $obj  
      }   
 }  

May the Force...
t

1 comment:

  1. Thanks for the post! I'm trying to find a way to export this to a CSV. Any suggestions?

    ReplyDelete