August 22nd, 2011

Use PowerShell to Easily Find Information About Hotfixes

Doctor Scripto
Scripter

Summary: Learn how to use Windows PowerShell to easily find information about Windows Update hotfixes.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have a problem, and I am hoping that you can help me. I have been using the Get-Hotfix cmdlet, but unfortunately, it seems to miss some system updates. I desperately need to perform an audit of our systems, but when I use Get-Hotfix, it does not return half of the updates I can see in Control Panel. Therefore, I cannot have confidence in the values that are returned. Is there something I am missing? Help me, oh great Scripting Guy!

—JM

 

Hey, Scripting Guy! AnswerHello JM,

Microsoft Scripting Guy Ed Wilson here. When I was preparing for my talk for the TechReady conference on troubleshooting Windows 7 reliability issues, I noticed that the Win32_ReliabilityRecords WMI class returns information from the Microsoft-Windows-WindowsUpdateClient source. It dawned on me that I could query the WMI class for that source of information. As I investigated further, I saw that the productname field included the name of the update. This opens up all kinds of possibilities.

Before I get too carried away, I need to first investigate the Get-HotFix cmdlet. I send it to the Get-Member cmdlet, and see that it wraps the Win32_QuickFixEngineering WMI class, as shown here:

PS C:\Users\ed.IAMMRED> Get-HotFix | gm

   TypeName: System.Management.ManagementObject#root\cimv2\Win32_QuickFixEngineering

 

Name                           MemberType                 Definition                                                     

Caption                         Property                        System.String Caption {get;set;}                               

CSName                        Property                        System.String CSName {get;set;}                                

Description                    Property                        System.String Description {get;set;}                            

FixComments                 Property                        System.String FixComments {get;set;}                           

HotFixID                        Property                        System.String HotFixID {get;set;}                              

InstallDate                     Property                        System.String InstallDate {get;set;}                           

InstalledBy                     Property                        System.String InstalledBy {get;set;}                           

Name                           Property                        System.String Name {get;set;}                                  

ServicePackInEffect         Property                        System.String ServicePackInEffect {get;set;}                   

Status                            Property                        System.String Status {get;set;}                                

__CLASS                         Property                        System.String __CLASS {get;set;}                               

__DERIVATION                Property                        System.String[] __DERIVATION {get;set;}                        

__DYNASTY                    Property                        System.String __DYNASTY {get;set;}                             

__GENUS                       Property                        System.Int32 __GENUS {get;set;}                                

__NAMESPACE               Property                        System.String __NAMESPACE {get;set;}                           

__PATH                          Property                        System.String __PATH {get;set;}                                 

__PROPERTY_COUNT       Property                        System.Int32 __PROPERTY_COUNT {get;set;}                       

__RELPATH                     Property                        System.String __RELPATH {get;set;}                             

__SERVER                       Property                        System.String __SERVER {get;set;}                              

__SUPERCLASS               Property                        System.String __SUPERCLASS {get;set;}                          

PSStatus                        PropertySet                   PSStatus {__PATH, Status}                                       

ConvertFromDateTime    ScriptMethod                System.Object ConvertFromDateTime();                           

ConvertToDateTime       ScriptMethod                System.Object ConvertToDateTime();                             

InstalledOn                    ScriptProperty               System.Object InstalledOn {get=if ([environment]::osversion.v…

 

The problem is that only certain types of updates are picked up by Win32_QuickFixEngineering. I examine the number of records that are recorded on my system by piping the results to Measure-Object. The command and associated output are shown here:

PS C:\Users\ed.IAMMRED> Get-HotFix | Measure-Object

 

Count    : 55

Average  :

Sum      :

Maximum  :

Minimum  :

Property :

 

On my system, the Get-Hotfix cmdlet returns 55 updates. I am not going to go through the process of trying to see which updates appear and which ones are not visible, but I want to compare the results with what I obtain by querying the Win32_ReliabilityRecords WMI class. The command and associated output are shown here:

PS C:\Users\ed.IAMMRED> gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

Measure-Object 

 

Count    : 180

Average  :

Sum      :

Maximum  :

Minimum  :

Property :

 

To explore the type of data returned from the Win32_ReliabilityRecords WMI class, I perform a quick query and focus only on records with a source from the *updateClient. This query is shown here:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'”

The query and associated output are shown in the following figure.

Image of query and associated output

A number of properties are available from the Win32_ReliabilityRecords WMI class. The timegenerated property displays the date/time value in WMI’s infamous UTC time fashion. Luckily, Windows PowerShell adds a ConvertToDateTime method to WMI objects, and therefore it can be used to convert the UTC time to something a bit more readable. The user property records the user who installed the updates, and the productname property lists the actual update. In many cases the user will be NT Authority\System, so the user property may not be the most useful property to retrieve. The productname name tends to be really long, and to take up a decent amount of screen real estate when it is displayed. The Select-Object returns an object that can be further processed, but unfortunately, it does not maximize screen output. Consider using one of the Format* cmdlets to create an easier display to read. In the following code, I grab all of the Win32_ReliabilityRecords that come from the Microsoft-Windows-WindowsUpdateClient source, and I use Select to choose the Timegenerated, User, and ProductName properties. I also use a hash table to create a customized display, a column head of Date instead of TimeGenerated, and a datetime display that is easy to read. The code is shown here:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

select @{LABEL = “date”;EXPRESSION = {$_.ConvertToDateTime($_.timegenerated)}},

user, productname

 

The code and the associated output are shown in the following figure.

Image of code and associated output

If the installation of an update fails, it appears as an installation failure in the message property. In addition to the indication of failure, the reason for the failed installation also appears. It is therefore a good idea to filter for a message that will match the word failure. Regular expressions would be a great tool to use here, but a simple match (which uses regular expressions) will also work. Here is the code I used to find failed updates:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

where { $_.message -match ‘failure’ } |

select -ExpandProperty message

 

The code and associated output are shown in the following figure.

Image of code and associated output

I decided to modify the output so that I could more easily read the date and the update that failed. I used the same basic code that formats the output for the date, but added another column heading for failed update and I kept the Where-Object that looks for the word failure in the message property. Here is the revised code:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

where { $_.message -match ‘failure’ } |

select @{LABEL = “date”;EXPRESSION = {$_.ConvertToDateTime($_.timegenerated)}},

@{LABEL = “failed update”; EXPRESSION = { $_.productname }}| FT -AutoSize –Wrap

 

The revised code and the associated output are shown in the following figure.

Image of revised code and associated output

I decide to hone in on a specific failed update. I modify the Where-Object so that I am not looking for the specific word failed, but instead am looking for the specific update number. The modified query is shown here:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

where { $_.message -match ‘KB973688’ } |

select @{LABEL = “date”;EXPRESSION = {$_.ConvertToDateTime($_.timegenerated)}},

@{LABEL = “update”; EXPRESSION = { $_.productname }}| FT -AutoSize –Wrap

 

The code and associated output are shown in the following figure.

Image of code and associated output

From the preceding figure, I can see that the update appears twice. The second attempt is a few minutes after the first attempt, but the productname property does not indicate success or failure. For this, I need to go back and query the message property. The modified code is shown here:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

where { $_.message -match ‘KB973688’ } |

select -expand message

 

The code and associated output are shown in the following figure.

Image of code and associated output

Hmmm, so it seems that at least one of my failed updates actually installed. I decide to modify my query once again. This time, I use a compound Where-Object (where is the alias) to look for both updates by KB number. I get rid of the Select-Object (select is alias) cmdlet in favor of the Format-Table cmdlet (ft is the alias) so that I have a better display of output. I use both the autosize and the wrap parameters for Format-Table. In addition, I decide to use the message property instead of just the productname property because it includes both the product name and the installation status. Here is the revised query:

gwmi -cl win32_reliabilityRecords `

-filter “sourcename = ‘Microsoft-Windows-WindowsUpdateClient'” |

where { $_.message -match ‘KB973688’ -OR $_.message-Match ‘KB954430’} |

FT @{LABEL = “date”;EXPRESSION = {$_.ConvertToDateTime($_.timegenerated)}},

message -autosize –wrap

 

The code and the associated output are shown in the following figure.

Image of code and associated output

 

JM that is all there is to using the reliability provider to obtain information about Windows Update hotfixes. 

Note   For more information about using the Reliability provider to troubleshoot Windows systems, check out these Hey, Scripting Guy! Blog posts.

I invite you to check back tomorrow for more Windows PowerShell goodness.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.