Summary: Learn how to use Windows PowerShell to easily find information about Windows Update hotfixes.
Hey, 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
Hello 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.
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.
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.
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.
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.
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.
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.
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
0 comments