I was working on some updates to our unified reporting solution for Windows Updates (ie WUfB + MEMCM) and I wanted to figure out simply from the OS build number whether a Windows 10 workstation has the latest cumulative update installed. The only reliable and useable static list I could find for Windows 10 build numbers is Microsoft’s Windows 10 Update History web page, so I decided to build a PowerShell script that parses the page to get current patch info.
The script below can be used to report which OS build a Windows 10 workstation is currently on as well as which update is the latest update available to the device. It can also report on all Windows updates published for the version of Windows 10 a workstation is currently on.
Run the script as is to show you:
- Current OS version
- Current OS Edition
- Current OS Build number
- The installed update that corresponds to that build number, as well as the KB number and a link to the info page
- The latest available update for the OS version
Get-CurrentPatchInfo

Compare the latest available update with the currently installed one to know if the OS is up-to-date.
If there are Preview or Out-of-band updates available that are more recent than the one you have installed, you can exclude those from being reported as a latest available update, so you can just focus on the cumulative updates.
Get-CurrentPatchInfo -ExcludePreview -ExcludeOutofBand
You can also list all Windows updates that Microsoft have published for your OS version like so:
Get-CurrentPatchInfo -ListAvailable

Again focus on just the cumulative updates if you want by excluding Preview and Out-of-band updates from the list:
Get-CurrentPatchInfo -ListAvailable -ExcludePreview -ExcludeOutofBand

Obviously the script does require internet access and I’ve tested it on PowerShell 5.1 and 7.1.
| [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('—',' – ') | |
| 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('—',' – '), | |
| "KB" + $CurrentPatch.href.Split('/')[-1], | |
| "https://support.microsoft.com" + $CurrentPatch.href, | |
| $LatestAvailablePatch.outerHTML.Split('>')[1].Replace('</a','').Replace('—',' – '), | |
| "KB" + $LatestAvailablePatch.href.Split('/')[-1], | |
| "https://support.microsoft.com" + $LatestAvailablePatch.href | |
| ) | |
| Return $Table |
2 thoughts on “Get the current patch level for Windows 10 with PowerShell”
Comments are closed.