Earlier this year, I wrote about how to show and change Windows Update settings on a machine using PowerShell. But sometimes you need to know more about a Windows update than you can see in those scripts or in the Windows user interface, for example the UpdateID. This PowerShell script will print key information about one or more udpates. Run it from a Remote Management tool or directly on the machine you are investigating.
Provide as the first parameter a list of one or more numeric KB IDs that you want to view, separated by commas without spaces. For example:
.\WindowsUpdate.ShowDetails 2952664,2976978,3035583
.\WindowsUpdate.ShowDetails 3097877
Update 5 August 2016
The script now allows specifying updates by their 36-character UpdateID as well as by the KB number. Do not include the {curly brackets} when specifying an UpdateID. For example:
.\WindowsUpdate.ShowDetails a720f788-2503-42a9-88ad-68feffee6818
Update 25 May 2018
Added driver info fields.
Sample output:
Update August 3, 2020
Added AutoSelectOnWebSites field, documented here.
Here’s the script. Copy and paste it to a file, e.g. WindowsUpdate.ShowDetails.ps1.
<# .Synopsis Print details about one or more updates identified by KB number. Copyright (c) 2020 by MCB Systems. All rights reserved. Free for personal or commercial use. May not be sold. No warranties. Use at your own risk. .Notes Name: MCB.WindowsUpdate.ShowDetails.ps1 Author: Mark Berry, MCB Systems Created: 11/12/2015 Last Edit: 08/03/2020 Changes: 11/20/2015 Add AutoSelection and AutoDownload fields. 08/05/2016 Allow searching by 36-character UpdateID as well as by KB number. Do not include the {curly brackets} when specifying an UpdateID. 03/31/2018 Add driver info fields. 08/03/2020 Add AutoSelectOnWebSites field. Documented here: https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search #> param( # This parameter takes an array of KB Numbers or UpdateIDs. Supply the numbers # separated by commas but no spaces, e.g. 2952664,2976978,3035583,F9164872-3E27-4410-B4FC-038814549BB1. [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] [String[]]$UpdateNumbers="", # The following $LogFile parameter is required by LogigNow Remote Management # and can be omitted when running the script directly. [Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true)] [String]$LogFile="" ) [Boolean]$ErrFound = $false $ComputerName = $env:COMPUTERNAME Foreach ($UpdateNumber in $UpdateNumbers) { if ($UpdateNumber.length -ne 36) { # If it's not a 36-character UpdateID, check if $UpdateNumber is numeric try { 0 + $UpdateNumber | Out-Null } catch{ "Parameter error: '$UpdateNumber' is not allowed. Specify one or more KBNumbers or 36-character UpdateIDs separated" "by commas but no spaces. Do not precede KBNumbers with 'KB' and do not enclose UpdateIDs in {curly brackets}." "" "Script execution failed" $ExitCode = 1001 # Cause script to report failure in GFI dashboard "" "Local Machine Time: " + (Get-Date -Format G) "Exit Code: " + $ExitCode Exit $ExitCode } } } "Computer Name: " + $ComputerName "" "-------------------------------------------------------------------------------" "Step 1: Check whether update(s) are installed." " This section only shows updates for which you specifed a KBNumber." " Updates for which you provided an UpdateID cannot be listed here." "-------------------------------------------------------------------------------" #--------------------------------------------------------------------------------- # Check if update installed # Adapted from http://techibee.com/powershell/powershell-uninstall-windows-hotfixesupdates/1084 #--------------------------------------------------------------------------------- # Note that the list returned by wmic includes the "KB" prefix but wusa wants the number only $hotfixes = Get-WmiObject -ComputerName $ComputerName -Class Win32_QuickFixEngineering | select hotfixid Foreach ($UpdateNumber in $UpdateNumbers) { if ($UpdateNumber.length -eq 36) { Write-Host "Skipping $UpdateNumber specified as UpdateID." } else { $KBID = "KB"+$UpdateNumber if($hotfixes -match $KBID) { Write-host "Update $UpdateNumber is installed." } else { Write-Host "Update $UpdateNumber is not installed." } } } # Foreach $UpdateNumber #--------------------------------------------------------------------------------- # Print update status per Windows Update # Adapted from http://superuser.com/a/922921/171670. #--------------------------------------------------------------------------------- "" "-------------------------------------------------------------------------------" "Step 2: Print status of update(s)" "-------------------------------------------------------------------------------" "Searching online for updates applicable to this machine, whether installed or " "not, including superseded updates. This may take some time--please wait..." try { #Get all updates in $SearchResult. $UpdateSession = New-Object -ComObject Microsoft.Update.Session $UpdateSearcher = $UpdateSession.CreateUpdateSearcher() # If the update has been re-released, it may supersede a previous update. $UpdateSearcher.IncludePotentiallySupersededUpdates = $true # Available search criteria: https://msdn.microsoft.com/en-us/library/windows/desktop/aa386526%28v=vs.85%29.aspx $SearchResult = $UpdateSearcher.Search("IsInstalled=0 or IsInstalled=1") # include whether installed or not "Update list download complete." # For debugging: select one update by searching for string in title # $Update = $SearchResult.updates | Where-Object{$_.Title -match "3097877"} # We use Foreach below so we can search through (potentially multiple) KBArticleIDs per update Foreach ($UpdateNumber in $UpdateNumbers) { [Boolean]$UpdateListed = $false # refers to the $UpdateNumber from the parameter list "" "Checking for update $UpdateNumber" "--------------------------------------------------------" Foreach ($Update in $SearchResult.updates) { [Boolean]$ShowUpdate = $false # refers to the $Update from the search result if ($Update.Identity.UpdateID -eq $UpdateNumber) { $ShowUpdate = $true # We want to show details on this specific update from the search result } Foreach ($KBArticleID in $Update.KBArticleIDs) { # Next line is for debugging # Write-Host "$KBArticleID, $($Update.IsHidden), $($Update.title)" if ($KBArticleID -eq $UpdateNumber) { $ShowUpdate = $true # We want to show details on this specific update from the search result } # if $KBArticleID -eq $UpdateNumber } # Foreach $KBArticleID if ($ShowUpdate) { $UpdateListed = $true # We listed details for at least one $Update matching $UpdateNumber Write-Host "" Write-Host " KBArticleIDs: $($Update.KBArticleIDs)" Write-Host " Title: $($Update.Title)" Write-Host " UpdateID: $($Update.Identity.UpdateID)" Write-Host " RevisionNumber: $($Update.Identity.RevisionNumber)" Write-Host "LastDeploymentChangeTime: $($Update.LastDeploymentChangeTime.ToString())" Write-Host " MsrcSeverity: $($Update.MsrcSeverity)" Write-Host " IsDownloaded: $($Update.IsDownloaded)" Write-Host " IsHidden: $($Update.IsHidden)" Write-Host " IsInstalled: $($Update.IsInstalled)" Write-Host " IsMandatory: $($Update.IsMandatory)" Write-Host " IsPresent: $($Update.IsPresent)" Write-Host " BrowseOnly: $($Update.BrowseOnly)" Write-Host " IsUninstallable: $($Update.IsUninstallable)" Write-Host " MinDownloadSize: $($Update.MinDownloadSize)" Write-Host " MaxDownloadSize: $($Update.MaxDownloadSize)" Write-Host " RebootRequired: $($Update.RebootRequired)" Write-Host " AutoSelectOnWebSites: $($Update.AutoSelectOnWebSites)" Write-Host " AutoSelection: $($Update.AutoSelection)" Write-Host " AutoDownload: $($Update.AutoDownload)" Write-Host " SecurityBulletinIDs: $($Update.SecurityBulletinIDs)" Write-Host " SupersededUpdateIDs:" Foreach ($SupUpdateID in $Update.SupersededUpdateIDs) { Write-Host " $SupUpdateID" } # Foreach $SupUpdateID Write-Host "" Write-Host " The following fields are only available for driver updates:" Write-Host " DriverClass: $($Update.DriverClass)" Write-Host " DriverHardwareID: $($Update.DriverHardwareID)" Write-Host " DriverManufacturer: $($Update.DriverManufacturer)" Write-Host " DriverModel: $($Update.DriverModel)" Write-Host " DriverProvider: $($Update.DriverProvider)" Write-Host " DriverVerDate: $($Update.DriverVerDate)" Write-Host " DriverClass: $($Update.DriverClass)" } # If ($ShowUpdate) } # Foreach $Update if ($UpdateListed -eq $false) { Write-Host "" Write-Host "Update $UpdateNumber was not found searching Windows Update" } "----------------------------------------------------------------------------------" } # Foreach $UpdateNumber "" "For information on the AutoSelection and AutoDownload fields, see:" "http://www.mcbsys.com/blog/2015/11/important-microsoft-update-not-auto-installed/" "" "Script execution succeeded" $ExitCode = 0 } catch { "" $error[0] "" "Hiding update(s) failed" $ExitCode = 1001 # Cause script to report failure in MaxFocus RM dashboard } "" "Local Machine Time: " + (Get-Date -Format G) "Exit Code: " + $ExitCode Exit $ExitCode
Pingback: Important Microsoft Update Not Auto-Installed | MCB Systems