Last active
January 22, 2023 12:23
-
-
Save MyITGuy/d4f6dbd1b4bcbdba7de97505ae64cbd2 to your computer and use it in GitHub Desktop.
PowerShell: Get-MicrosoftUpdates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$MicrosoftUpdates = Get-MicrosoftUpdates -IncludeDISM | |
$GetHotfixOnlyUpdates = $MicrosoftUpdates | ? {$_.Source.Count -eq 1 -and $_.Source -contains 'Get-Hotfix'} | |
$MicrosoftUpdateOnlyUpdates = $MicrosoftUpdates | ? {$_.Source.Count -eq 1 -and $_.Source -contains 'MicrosoftUpdate'} | |
$DismOnlyUpdates = $MicrosoftUpdates | ? {$_.Source.Count -eq 1 -and $_.Source -contains 'DISM'} | |
$GetHotfixUpdates = $MicrosoftUpdates | ? {$_.Source -contains 'Get-Hotfix'} | |
$MicrosoftUpdateUpdates = $MicrosoftUpdates | ? {$_.Source -contains 'MicrosoftUpdate'} | |
$DismUpdates = $MicrosoftUpdates | ? {$_.Source -contains 'DISM'} | |
$MissingFromGetHotfix = $MicrosoftUpdates | ? {$_.Source -notcontains 'Get-Hotfix'} | |
$MissingFromMicrosoftUpdate = $MicrosoftUpdates | ? {$_.Source -notcontains 'MicrosoftUpdate'} | |
$MissingFromDism = $MicrosoftUpdates | ? {$_.Source -notcontains 'DISM'} | |
#GetHotfixOnlyUpdates do show in Add/Remove Programs | |
#MicrosoftUpdateOnlyUpdates do not show in Add/Remove Programs | |
#DismOnlyUpdates do not show in Add/Remove Programs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region Get-MicrosoftUpdates | |
function Get-MicrosoftUpdates { | |
[CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName="None")] | |
PARAM( | |
[switch]$IncludeDISM | |
) | |
try { | |
#region Windows Installer Patches | |
$Installer = New-Object -ComObject WindowsInstaller.Installer | |
$szProductCode = [String]::Empty | |
$szUserSid = [String]::Empty | |
$dwContext = 4 | |
$dwFilter = 15 | |
# PatchesEx implements MsiEnumPatchesEx, https://msdn.microsoft.com/en-us/library/aa370100(v=vs.85).aspx | |
$Patches = $Installer.PatchesEx($szProductCode, $szUserSid, $dwContext, $dwFilter) | |
$UseableWindowsInstallerPatchDetails = foreach ($Patch In $Patches) { | |
# Returns a Patch object | |
# Patch object: https://msdn.microsoft.com/en-us/library/windows/desktop/aa370594(v=vs.85).aspx | |
$PatchProperties = [ordered]@{} | |
# PatchProperty, https://msdn.microsoft.com/en-us/library/aa370598(v=vs.85).aspx | |
$PatchProperties.Title = $Patch.PatchProperty('DisplayName') | |
$PatchProperties.HotfixID = $null | |
try { | |
$MatchFound = $PatchProperties.Title -match 'KB\d+(?!^\d)' | |
if ($MatchFound) {$PatchProperties.HotfixID = $Matches[0]} | |
} catch { | |
} | |
try { | |
$PatchProperties.Caption = $Patch.PatchProperty('MoreInfoURL') | |
} catch { | |
$PatchProperties.Caption = $null | |
} | |
$PatchProperties.InstallDate = ([datetime]::ParseExact($Patch.PatchProperty('InstallDate'), "yyyyMMdd", [System.Globalization.CultureInfo]::CurrentCulture)) | |
$PatchProperties.Source = "WindowsInstallerPatch" | |
New-Object -TypeName PSObject -Property $PatchProperties | ? {$_.HotfixID} | |
} | |
#endregion Windows Installer Patches | |
#region Windows Installer Products | |
$Installer = New-Object -ComObject WindowsInstaller.Installer | |
$szProductCode = [String]::Empty | |
$szUserSid = [String]::Empty | |
$dwContext = 4 | |
$dwIndex = 0 | |
# ProductsEx implements MsiEnumProductsEx, https://msdn.microsoft.com/en-us/library/aa370102(v=vs.85).aspx | |
$Products = $Installer.ProductsEx($szProductCode, $szUserSid, $dwContext, $dwIndex) | |
$UseableWindowsInstallerProductDetails = foreach ($Product In $Products) { | |
# Returns a Product object | |
# Product object: https://msdn.microsoft.com/en-us/library/windows/desktop/aa370867(v=vs.85).aspx | |
$ProductProperties = [ordered]@{} | |
# ProductProperty, https://msdn.microsoft.com/en-us/library/aa370598(v=vs.85).aspx | |
$ProductProperties.Title = $Product.InstallProperty('ProductName') | |
$ProductProperties.HotfixID = $null | |
try { | |
$MatchFound = $ProductProperties.Title -match 'KB\d+(?!^\d)' | |
if ($MatchFound) {$ProductProperties.HotfixID = $Matches[0]} | |
} catch { | |
} | |
try { | |
$ProductProperties.InstallDate = ([datetime]::ParseExact($Product.InstallProperty('InstallDate'), "yyyyMMdd", [System.Globalization.CultureInfo]::CurrentCulture)) | |
} catch { | |
$ProductProperties.InstallDate = $null | |
} | |
$ProductProperties.Source = "WindowsInstallerProduct" | |
New-Object -TypeName PSObject -Property $ProductProperties | ? {$_.HotfixID} | |
} | |
#endregion Windows Installer Products | |
#region Microsoft Updates | |
$IUpdateSession = New-Object -ComObject Microsoft.Update.Session | |
$IUpdateSearcher = $IUpdateSession.CreateUpdateSearcher() | |
$HistoryCount = $IUpdateSearcher.GetTotalHistoryCount() | |
$IUpdateHistoryEntryCollection = $IUpdateSearcher.QueryHistory(0, $HistoryCount) | |
# Extract useable data | |
$UseableMicrosoftUpdateDetails = $IUpdateHistoryEntryCollection | % { | |
try { | |
$MatchFound = $_.Title -match 'KB\d+(?!^\d)' | |
if ($MatchFound) {$tmpHotfixId = $Matches[0]} | |
} catch { | |
$tmpHotfixId = [string]::Empty | |
} | |
New-Object -TypeName PSObject -Property @{ | |
InstallDate = ([datetime]$_.Date).ToLocalTime() | |
HotfixID = $tmpHotfixId | |
Title = $_.Title | |
Source = "MicrosoftUpdate" | |
} | |
} | |
#endregion Microsoft Updates | |
#region DISM | |
if ($IncludeDISM) { | |
if ((New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { | |
$DISMDetails = dism.exe /Online /Get-Packages /Format:Table | ? {$_.Contains("|") -and -not $_.StartsWith("-")} | % {($_.Split('|').Trim() -join ',')} | ConvertFrom-Csv | |
$UseableDISMDetails = $DISMDetails | ? {@('Update','Security Update') -contains $_."Release Type" -and $_."Package Identity".StartsWith('Package_for_') -eq $true -and $_."Package Identity".StartsWith('Package_for_RollupFix') -eq $false} | foreach { | |
New-Object -TypeName PSObject -Property @{ | |
InstallDate = ([datetime]$_."Install Time").ToLocalTime() | |
HotfixID = (($_."Package Identity".TrimStart('Package_for_')).split('~'))[0] | |
Source = "DISM" | |
} | |
} | |
} else { | |
Write-Error "IncludeDISM parameter can only be used with accounts holding the Adminstrator role." | |
} | |
} | |
#endregion DISM | |
#region Get-Hotfix | |
# Get installed hotfixes, extract useable data | |
$InstalledHotfixes = Get-HotFix | Select Caption, Description, HotfixID, InstalledBy, @{Name='InstallDate';Expression={$_.InstalledOn}}, @{Name='Source';Expression={'Get-Hotfix'}}, @{Name='Title';Expression={$null}} | |
#endregion Get-Hotfix | |
# Get only hotfix IDs | |
$AllHotfixIDs = @() | |
$AllHotfixIDs += $UseableWindowsInstallerProductDetails | Select -ExpandProperty HotfixID | |
$AllHotfixIDs += $UseableWindowsInstallerPatchDetails | Select -ExpandProperty HotfixID | |
$AllHotfixIDs += $UseableMicrosoftUpdateDetails | Select -ExpandProperty HotfixID | |
$AllHotfixIDs += $UseableDISMDetails | Select -ExpandProperty HotfixID | |
$AllHotfixIDs += $InstalledHotfixes | Select -ExpandProperty HotfixID | |
$AllHotfixIDs = $AllHotfixIDs | Sort -Unique | |
foreach ($SingleHotfixID IN $AllHotfixIDs) { | |
$hash = @{} | |
$hash.ComputerName = $env:COMPUTERNAME | |
$hash.HotfixID = $SingleHotfixID | |
$WindowsInstallerProductDetail = $UseableWindowsInstallerProductDetails | ? {$_.HotfixID -eq $hash.HotfixID} | |
$WindowsInstallerPatchDetail = $UseableWindowsInstallerPatchDetails | ? {$_.HotfixID -eq $hash.HotfixID} | |
$MicrosoftUpdateDetail = $UseableMicrosoftUpdateDetails | ? {$_.HotfixID -eq $hash.HotfixID} | |
$UseableDISMDetail = $UseableDISMDetails | ? {$_.HotfixID -eq $hash.HotfixID} | |
$GetHotfixDetail = $InstalledHotfixes | ? {$_.HotfixID -eq $hash.HotfixID} | |
$hash.Source = @() | |
$hash.InstallDate = $null | |
$hash.Title = $null | |
$hash.Caption = $null | |
$hash.Description = $null | |
$hash.InstalledBy = $null | |
$PrioritizedDetails = @($GetHotfixDetail, $UseableDISMDetail, $MicrosoftUpdateDetail, $WindowsInstallerPatchDetail, $WindowsInstallerProductDetail) | |
foreach ($PrioritizedDetail In $PrioritizedDetails) { | |
if ($PrioritizedDetail.Source) {$hash.Source += $PrioritizedDetail.Source | Sort | Select -Last 1} | |
if (!$hash.InstallDate -and $PrioritizedDetail.InstallDate) {$hash.InstallDate = $PrioritizedDetail.InstallDate | Sort | Select -Last 1} | |
if (!$hash.Title -and $PrioritizedDetail.Title) {$hash.Title = $PrioritizedDetail.Title | Sort | Select -Last 1} | |
if (!$hash.Caption -and $PrioritizedDetail.Caption) {$hash.Caption = $PrioritizedDetail.Caption | Sort | Select -Last 1} | |
if (!$hash.Description -and $PrioritizedDetail.Description) {$hash.Description = $PrioritizedDetail.Description | Sort | Select -Last 1} | |
if (!$hash.InstalledBy -and $PrioritizedDetail.InstalledBy) {$hash.InstalledBy = $PrioritizedDetail.InstalledBy | Sort | Select -Last 1} | |
} | |
New-Object -TypeName PSObject -Property $hash | |
} | |
} catch { | |
throw $_ | |
} finally { | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment