Skip to content

Instantly share code, notes, and snippets.

@SMSAgentSoftware
Last active March 20, 2025 09:47
Show Gist options
  • Select an option

  • Save SMSAgentSoftware/79fb091a4b7806378fc0daa826dbfb47 to your computer and use it in GitHub Desktop.

Select an option

Save SMSAgentSoftware/79fb091a4b7806378fc0daa826dbfb47 to your computer and use it in GitHub Desktop.
Gets the current software update level of a Windows 10/11 workstation and compares with the latest available updates. Can also list all available updates for the current build.
[CmdletBinding()]
Param(
[switch]$ListAllAvailable,
[switch]$ExcludePreview,
[switch]$ExcludeOutofBand
)
$ProgressPreference = 'SilentlyContinue'
Function Get-MyWindowsVersion {
[CmdletBinding()]
Param
(
$ComputerName = $env:COMPUTERNAME
)
$Table = New-Object System.Data.DataTable
$Table.Columns.AddRange(@("ComputerName","Windows edition","Version","Build number"))
$ProductName = Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption | Select -ExpandProperty Caption
Try
{
$DisplayVersion = (Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name DisplayVersion -ErrorAction Stop)
}
Catch
{
$DisplayVersion = "N/A"
}
$CurrentBuild = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name CurrentBuild
$UBR = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR
$OSVersion = $CurrentBuild + "." + $UBR
$TempTable = New-Object System.Data.DataTable
$TempTable.Columns.AddRange(@("ComputerName","Windows edition","Version","Build number"))
[void]$TempTable.Rows.Add($env:COMPUTERNAME,$ProductName,$DisplayVersion,$OSVersion)
Return $TempTable
}
Function Convert-ParsedArray {
Param($Array)
$ArrayList = New-Object System.Collections.ArrayList
foreach ($item in $Array)
{
[void]$ArrayList.Add([PSCustomObject]@{
Update = $item.outerHTML.Split('>')[1].Replace('</a','').Replace('&#x2014;',' - ')
KB = "KB" + $item.href.Split('/')[-1]
InfoURL = "https://support.microsoft.com" + $item.href
OSBuild = [int]$item.outerHTML.Split('.')[-1].Split(')')[0] # Just for sorting
})
}
Return $ArrayList
}
# Get Windows info
$CurrentWindowsVersion = Get-MyWindowsVersion -ErrorAction Stop
# Set the correct URL for W11 or W10
If ($CurrentWindowsVersion.'Build number' -like "2*")
{
$URI = "https://aka.ms/Windows11UpdateHistory"
}
If ($CurrentWindowsVersion.'Build number' -like "1*")
{
$URI = "https://support.microsoft.com/en-gb/topic/windows-10-update-history-7dd3071a-3906-fa2c-c342-f7f86728a6e3"
}
# Retrieve the web pages
If ($PSVersionTable.PSVersion.Major -ge 6)
{
$Response = Invoke-WebRequest -Uri $URI -ErrorAction Stop
}
else
{
$Response = Invoke-WebRequest -Uri $URI -UseBasicParsing -ErrorAction Stop
}
# Pull the version data from the HTML
If (!($Response.Links))
{ throw "Response was not parsed as HTML"}
$VersionDataRaw = $Response.Links | where {$_.outerHTML -match "supLeftNavLink" -and $_.outerHTML -match "KB"}
# Pull all the update info if requested
If ($ListAllAvailable)
{
If ($ExcludePreview -and $ExcludeOutofBand)
{
$AllAvailable = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Preview" -and $_.outerHTML -notmatch "Out-of-band"}
}
ElseIf ($ExcludePreview)
{
$AllAvailable = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Preview"}
}
ElseIf ($ExcludeOutofBand)
{
$AllAvailable = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Out-of-band"}
}
Else
{
$AllAvailable = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0]}
}
$UniqueList = (Convert-ParsedArray -Array $AllAvailable) | Select -Property * -Unique | Sort OSBuild -Descending
$Table = New-Object System.Data.DataTable
[void]$Table.Columns.AddRange(@('Update','KB','InfoURL'))
foreach ($Update in $UniqueList)
{
[void]$Table.Rows.Add(
$Update.Update,
$Update.KB,
$Update.InfoURL
)
}
Return $Table
}
# Get the latest patch info
$CurrentPatch = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'} | Select -First 1
If ($ExcludePreview -and $ExcludeOutofBand)
{
$LatestAvailablePatch = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Out-of-band" -and $_.outerHTML -notmatch "Preview"} | Select -First 1
}
ElseIf ($ExcludePreview)
{
$LatestAvailablePatch = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Preview"} | Select -First 1
}
ElseIf ($ExcludeOutofBand)
{
$LatestAvailablePatch = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0] -and $_.outerHTML -notmatch "Out-of-band"} | Select -First 1
}
Else
{
$LatestAvailablePatch = $VersionDataRaw | where {$_.outerHTML -match $CurrentWindowsVersion.'Build number'.Split('.')[0]} | Select -First 1
}
# Add the data to a table
$Table = New-Object System.Data.DataTable
[void]$Table.Columns.AddRange(@('OSVersion','OSEdition','OSBuild','CurrentInstalledUpdate','CurrentInstalledUpdateKB','CurrentInstalledUpdateInfoURL','LatestAvailableUpdate','LastestAvailableUpdateKB','LastestAvailableUpdateInfoURL'))
[void]$Table.Rows.Add(
$CurrentWindowsVersion.Version,
$CurrentWindowsVersion.'Windows edition',
$CurrentWindowsVersion.'Build number',
$CurrentPatch.outerHTML.Split('>')[1].Replace('</a','').Replace('&#x2014;',' - '),
"KB" + $CurrentPatch.href.Split('/')[-1],
"https://support.microsoft.com" + $CurrentPatch.href,
$LatestAvailablePatch.outerHTML.Split('>')[1].Replace('</a','').Replace('&#x2014;',' - '),
"KB" + $LatestAvailablePatch.href.Split('/')[-1],
"https://support.microsoft.com" + $LatestAvailablePatch.href
)
Return $Table
@AxelLimousin

AxelLimousin commented Jul 25, 2021

Copy link
Copy Markdown

Hi Trevor,
Could be useful to keep only the date on the Update property : Update = ([DateTime]($item.outerHTML.Split('>')[1]).Split('&#x')[0]).ToShortDateString().

@bezik46

bezik46 commented May 15, 2023

Copy link
Copy Markdown

It would be great if BIOS version could be added

@ejespino1127

Copy link
Copy Markdown

Hi, I got an error when running the cmdlet:

PS C:\Users\sicopadmin\workspaces\powershell> .\Get-CurrentPatchInfo -ExcludePreview -ExcludeOutofBand
InvalidOperation: C:\Users\sicopadmin\workspaces\powershell\Get-CurrentPatchInfo.ps1:121
Line |
121 | [void]$Table.Rows.Add(
| ~~~~~~~~~~~~~~~~~~~~~~
| You cannot call a method on a null-valued expression.
PS C:\Users\sicopadmin\workspaces\powershell>

Any advice on how to fix this error from happen again?

@Naveen-Kanakaraj

Copy link
Copy Markdown

Hi, I got an error when running the cmdlet:

PS C:\Users\sicopadmin\workspaces\powershell> .\Get-CurrentPatchInfo -ExcludePreview -ExcludeOutofBand InvalidOperation: C:\Users\sicopadmin\workspaces\powershell\Get-CurrentPatchInfo.ps1:121 Line | 121 | [void]$Table.Rows.Add( | ~~~~~~~~~~~~~~~~~~~~~~ | You cannot call a method on a null-valued expression. PS C:\Users\sicopadmin\workspaces\powershell>

Any advice on how to fix this error from happen again?

That is because its not a windows 10 probably
here is my fix, replace these lines with line number 8 and it will work (only for windows 11 and 10)

$Winver=Get-ComputerInfo | Select OsName

If($winver.'OsName' -like "Microsoft Windows 11*"){$URI = "https://aka.ms/Windows11UpdateHistory" <#Windows 11 release history#> }
Elseif($winver.'OsName' -like "Microsoft Windows 10*"){$URI = "https://aka.ms/WindowsUpdateHistory" <#Windows 10 release history#> }

@Romascopa

Copy link
Copy Markdown

So if $CurrentPatch is $null/empty, what does this mean?

@Naveen-Kanakaraj

Naveen-Kanakaraj commented Feb 2, 2024

Copy link
Copy Markdown

As per my understanding...

if the Device build version (example 22621.3085) does not match the list of builds in the website "https://aka.ms/WindowsUpdateHistory" (check the left pane) there is no record of the build to match it against a patch, so we get a null value error

one more update
for window 11 device you have to use this URL: "https://aka.ms/WindowsUpdateHistory"
and for windows 10 change it to: https://support.microsoft.com/en-us/topic/windows-10-update-history-8127c2c6-6edf-4fdf-8b9f-0f7be1ef3562

$Winver=Get-ComputerInfo | Select OsName

If($winver.'OsName' -like "Microsoft Windows 11*"){$URI = "https://aka.ms/WindowsUpdateHistory" <#Windows 11 release history#> }
Elseif($winver.'OsName' -like "Microsoft Windows 10*"){$URI = "https://support.microsoft.com/en-us/topic/windows-10-update-history-8127c2c6-6edf-4fdf-8b9f-0f7be1ef3562" <#Windows 10 release history#> }

@SMSAgentSoftware

Copy link
Copy Markdown
Author

Thanks for the feedback and comments!

I have updated the code with the following changes:

  • Added the correct URLs for update history which are now different between W10/11
  • Pull OSEdition from WMI instead of registry (required for Windows 11)
  • Dropped ReleaseId for DisplayVersion for OSVersion (ie 23H2 etc)
  • Improved the extraction of the OSBuild in the parsed array to allow for proper sorting
  • Fixed issue where only 1 update might be returned when using the -ListAvailable switch

@Romascopa

Romascopa commented Feb 2, 2024 via email

Copy link
Copy Markdown

@mad2xlc

mad2xlc commented Sep 4, 2024

Copy link
Copy Markdown

Hi, I got an error when running the cmdlet:

PS C:\Users\sicopadmin\workspaces\powershell> .\Get-CurrentPatchInfo -ExcludePreview -ExcludeOutofBand InvalidOperation: C:\Users\sicopadmin\workspaces\powershell\Get-CurrentPatchInfo.ps1:121 Line | 121 | [void]$Table.Rows.Add( | ~~~~~~~~~~~~~~~~~~~~~~ | You cannot call a method on a null-valued expression. PS C:\Users\sicopadmin\workspaces\powershell>

Any advice on how to fix this error from happen again?

same here. @ejespino1127 were you able to fix it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment