Check if a Windows Update is installed

The script checks if a Windows Update is installed, using Get-WMIObject commandlet and WMI information under 'win32_quickfixengineering' and 'win32_ReliabilityRecords'.

About Win32_ReliabilityRecords:
They are enabled by default on Windows 7 but Group Policy has to be used to enable them on the server side. See Computer Settings – Administrative Templates – Windows Components – Windows Reliability Analysis.

MSDN Win32_ReliabilityRecords class https://msdn.microsoft.com/en-us/library/ee706630(v=vs.85).aspx
Version 1.12.57
Created on 2015-02-21
Modified on 2016-04-05
Created by ajal
Downloads: 519

The Script Copy Script Copied to clipboard
#requires -version 2.0

# ¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨
#
#    Author: © Ajdin Aliu
#    Date  : 09.02.2015
#    Goal  : Get installed Windows Update
#
# ¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨¨°º©o¿,,¿o©º°¨



<#
Version  | Date        | Description of Change
---------+-------------+------------------------------------------------------
0.1      | 09.02.2015  | Initial Version
0.2      | 21.02.2015  | use Get-WMIObject instead of Get-HotFix - exception if not found
0.3      | 22.03.2015  | alternative source for update information in Win32_ReliabilityRecords, Error-Handling & verbose output

#>

<#
.SYNOPSIS
 Check if a Windows Update is installed on a system
.DESCRIPTION
 The script checks if a Windows Update is installed, using Get-WMIObject commandlet and WMI information under 'Win32_QuickFixEngineering'. This provider is also used by Get-HotFix cmdlet.
 If no records found in Win32_QuickFixEngineering, then it tries to find records in Win32_ReliabilityRecords containing HotFixID. 
.EXAMPLE
 Get-WmiObject -query "select * from win32_quickfixengineering WHERE HotFixID = 'kb2992611'" -Computername server
 gwmi -cl Win32_ReliabilityRecords -Computername Server | where { $_.message -match "kb2992611"}
.INPUTS
 Computername,HotFixID
.OUTPUTS
 Update installed state, shows some Update Details if Update is found on system
.NOTES
 Requirements 
    - PowerShell 2.0 or greater required
 - Limitations: 
  - Win32_QuickFixEngineering:    
   - returns only the updates supplied by Component Based Servicing (CBS) - See MSDN article
   - prefered source > faster, but does not contain always all details about updates, that may be present in Win32_ReliabilityRecords
  - Win32_ReliabilityRecords:
   - To access information from this WMI class, the group policy Configure Reliability WMI Providers must be enabled (disabled on server OS by default). See See MSDN article
   - can contain records about failed installations and uninstallations
  
.LINK 
 TechNet Library Get-WMIObject https://technet.microsoft.com/en-us/library/hh849824%28v=wps.620%29.aspx
 TechNet Library Get-HotFix https://technet.microsoft.com/en-us/library/hh849836(v=wps.620).aspx
 MSDN Win32_QuickFixEngineering class https://msdn.microsoft.com/en-us/library/aa394391%28v=vs.85%29.aspx
 MSDN Win32_ReliabilityRecords class https://msdn.microsoft.com/en-us/library/ee706630(v=vs.85).aspx
 TechNet Wiki http://social.technet.microsoft.com/wiki/contents/articles/4197.how-to-list-all-of-the-windows-and-software-updates-applied-to-a-computer.aspx
 MS Customer Service and Support Information https://support.microsoft.com/kb/888535
 See Security Bulletins 2014 for important updates https://technet.microsoft.com/en-us/library/security/dn553321.aspx
#>


$ErrorActionPreference = "Stop" #Treating All Errors as Terminating
#$VerbosePreference = "Continue" #Verbose Output
$UpdateDetails = $null
$CmpName = $args[0]
$HotFixID = $args[1]
$bFound = $False

#check for arguments
If (!$HotFixID -OR !$CmpName){
 #Usage
 Write-Host "HotFixID and Computername required!" 
 EXIT 1
}

#using Win32_QuickFixEngineering
try { 
 Write-Host "Looking for Update in Win32_QuickFixEngineering..."
 #$MyUpdate = Get-HotFix -ID $HotFixID -Computername $CmpName
 $MyUpdate = Get-WmiObject -Query "select * from win32_quickfixengineering WHERE HotFixID = '$($HotFixID)'" -Computername $CmpName 
 If ($MyUpdate -ne $null){
  Write-Host ">> Update found in Win32_QuickFixEngineering."
  $bFound = $True
  # QFEObject:    System.Management.ManagementObject#root\cimv2\Win32_QuickFixEngineering
  $MyUpdateType = $MyUpdate | Get-Member | Select -ExpandProperty TypeName -Unique  
  $UpdateDetails = $MyUpdate | ForEach {
   [PSCustomObject] @{
    Source   = $MyUpdateType
    UpdateID   = $_.HotFixID
    SourceName  = $_.SourceName
    Description = $_.Description
    Details  = $_.FixComments
    InstalledBy = $_.InstalledBy
    #InstalledOn = $_.InstalledOn
   }
  }   
 } Else {
  Write-Host ">> Update not found in Win32_QuickFixEngineering."
 }
}
catch { 
 Write-Host "WARN: Could not get Updatelist from Win32_QuickFixEngineering. Check if system is online and you have appropriate permissions!"
 Exit 1
}
finally {
 If ($Error[0]){
  Write-Host "Exception Details for QFE query:"
  Write-Host "Exception: $($Error[0].Exception.Message)"
  Write-Host "ExceptionType: $($Error[0].Exception.GetType().Fullname)"
  Exit 1
 }
}

If (!$bFound){
 #using Win32_ReliabilityRecords
 try {
  Write-Host "Looking for Update in Win32_ReliabilityRecords..."  
  #$MyUpdate = gwmi -cl Win32_ReliabilityRecords -Computername $CmpName | where { ($_.message -NOTmatch "fail" -OR $_.message -NOTmatch "fehl") -AND $_.message -match "$($HotFixID)"} #| select -last 1
  $MyUpdate = Get-WmiObject -Class Win32_ReliabilityRecords -Computername $CmpName | Where { $_.message -match "$($HotFixID)"} #| select -last 1
  
  If ($MyUpdate -ne $null){
   Write-Host ">> Update found in Win32_ReliabilityRecords."
   $bFound = $True  
   # ReliabilityObject:  System.Management.ManagementObject#root\cimv2\Win32_ReliabilityRecords
   $MyUpdateType = $MyUpdate | Get-Member | Select -ExpandProperty TypeName -Unique
   $UpdateDetails = $MyUpdate | ForEach {
    [PSCustomObject] @{
     Source   = $MyUpdateType
     UpdateID = $_.ProductName
     SourceName = $_.SourceName
     Description = $_.ProductName
     Details  = $_.Message
     InstalledBy = $_.user
     InstalledOn = $_.ConvertToDateTime($_.TimeGenerated)
    }
   }  
  } Else {
   Write-Host ">> Update not found in Win32_ReliabilityRecords."
  }
 }
 catch {
  Write-Host "WARN: Could not get Updatelist from Win32_ReliabilityRecords. Check if system is online, [Win32_ReliabilityRecords] provider is loaded and you have appropriate permissions!!"
 }
    finally {
        If ($Error[0]){   
   Write-Host "Exception Details for ReliabilityRecords query:"
   Write-Host "Exception: $($Error[0].Exception.Message)"
   Write-Host "ExceptionType: $($Error[0].Exception.GetType().Fullname)"
  }
    }
}

If ($bFound) {
 foreach ($UpdateDetail in $UpdateDetails){
  Write-Host "Update Details:"
  Write-Host "=================================================="
  $UpdateDetail
  Write-Host ""
  If ($UpdateDetail.Source.Equals("System.Management.ManagementObject#root\cimv2\Win32_ReliabilityRecords")){
   #Win32_ReliabilityRecords can also contain unsuccessfull installations of updates.
   Write-Host "UpdateDetails for [ $HotFixID ] found. Check UpdateDetails if installed successfully!"
   Write-Host ""
   Write-Host ""
  } else{
   Write-Host "Update [ $HotFixID ] is installed."
  }
 }

} else {
 Write-Host ""
 If ($Error[0]){
  Write-Host "Could not query all providers! See Output for more details!"
 }else{
  Write-Host "Update [$HotFixID] not found."
 }
}