Problem
When planning an upgrade from VCF 5.2 to VCF 9.0, one of the biggest unknowns is usually not the upgrade workflow itself.
It is the hardware underneath it.
Even when the current environment is running perfectly fine on ESXi 8.0 U3, that does not automatically mean the hosts are ready for ESXi 9.0. In many environments, the real questions are:
-
Are the installed NICs, HBAs and storage controllers still supported?
-
Is the current firmware level still valid for the target ESXi release?
-
Are the CPUs supported for the next major version?
-
Can you upgrade directly, or do you first need a firmware change?
You can of course check this manually in the Broadcom Compatibility Guide, but once you have multiple clusters and hosts that quickly becomes a repetitive and time-consuming job.
And even worse, it becomes very easy to miss something.
Troubleshooting
The traditional approach is straightforward, but not very scalable.
For each host you would need to:
-
Identify the installed PCI devices
-
Look up every device in the Broadcom Compatibility Guide
-
Compare support for the current ESXi version and the target version
-
Check recommended driver and firmware combinations
-
Verify whether the CPU is still supported
-
Repeat the same process for every host in every cluster
In a small environment this is manageable.
In a larger environment, especially during a VCF lifecycle project, this quickly turns into a lot of manual validation work. It is also difficult to create a clean overview that tells you which hosts need firmware updates before an upgrade and which ones can continue without additional remediation.
That was the reason for building this script.
Solution
To simplify the validation process, I created an ESXi Upgrade Compatibility Tool.
The script connects to vCenter, enumerates all connected hosts in all clusters, reads their hardware inventory, and compares that information against the Broadcom Compatibility Guide for both:
-
ESXi 8.0 U3
-
ESXi 9.0
It also performs a CPU compatibility check, which is an important addition when preparing for a major version upgrade.
At the end, the script generates two CSV reports:
-
A detailed compatibility report
-
A firmware overlap and upgrade strategy report
This makes it much easier to determine whether a host can move forward directly, or whether a firmware update is required first.
Script Functionality
The script automates the following workflow:
-
Connects to the specified vCenter Server
-
Retrieves all clusters and connected ESXi hosts
-
Collects CPU model information per host
-
Matches the CPU against the Broadcom Compatibility Guide CPU list
-
Checks CPU support for both ESXi 8.0 U3 and ESXi 9.0
-
Uses
Get-EsxCli -V2to retrieve installed PCI hardware such as:-
Network adapters
-
Ethernet controllers
-
Storage controllers
-
RAID adapters
-
SCSI adapters
-
Fibre Channel adapters
-
-
Queries the Broadcom Compatibility Guide for each device and target ESXi version
-
Extracts supported driver, driver version and firmware information
-
Compares current and target compatibility
-
Generates a detailed CSV report per cluster
-
Generates a second report showing whether firmware overlap exists between 8.0 U3 and 9.0
This second report is especially useful because it helps answer the practical question:
Can I keep the current firmware during the upgrade, or do I need to update it first?
Why the Firmware Overlap Report Matters
The most useful part of this script is not just whether a device is supported.
It is the strategy report.
For regular PCI devices, the script compares the firmware versions listed for ESXi 8.0 U3 and ESXi 9.0. If the same firmware version appears in both support matrices, the report marks that as a common firmware version.
That means you may be able to move forward without changing firmware first.
If there is no overlap, the report flags that device as requiring a firmware change before or during the upgrade planning.
For CPUs, the script handles this differently. A CPU is either supported or not supported for ESXi 9.0. If it is not supported, the strategy report clearly marks that host as not upgradeable from a CPU perspective.
Usage Notes
There is currently one important manual step in the script.
On line 158 you need to specify your own vCenter FQDN:
Connect-VIServer -Server "XXXXX"
So before running the script, replace "XXXXX" with your actual vCenter hostname.
In hindsight, this should have been an input parameter instead of a hardcoded value. That would make the script cleaner and easier to reuse across environments. For now, it is a quick adjustment before execution.
Example Output
The script generates two CSV files per cluster.
1. Compatibility Report
This report contains the detailed hardware comparison for each host and ESXi version, including:
-
Host name
-
ESXi version
-
Device name
-
Driver name
-
Driver version
-
Firmware version
-
Broadcom Compatibility Guide link
2. Firmware Upgrade Strategy Report
This report focuses on the upgrade path and tells you:
-
Which firmware versions overlap between 8.0 U3 and 9.0
-
Whether a firmware update is likely needed
-
Whether the CPU is supported for 9.0
That means you not only get raw compatibility data, but also a more practical answer to the actual upgrade question.
Real-World Implementation
Scenario: validating hardware readiness for a future move from VCF 5.2 to VCF 9.0.
Before using the script:
-
Compatibility checks had to be performed manually
-
CPU validation required separate lookups
-
Firmware planning was difficult to visualize
-
Results were scattered across notes, screenshots and browser tabs
After using the script:
-
Host compatibility could be reviewed cluster by cluster
-
CPU support was included automatically
-
Firmware overlap became visible in a single CSV report
-
Upgrade preparation became much more structured
This is especially useful in environments where lifecycle planning starts well before the actual upgrade window.
Benefits
Using this script provides several advantages:
-
Reduces manual compatibility validation work
-
Includes both hardware and CPU checks
-
Helps determine whether firmware changes are required
-
Creates reusable documentation in CSV format
-
Makes upgrade planning more predictable
-
Scales much better across multiple clusters
-
Provides direct links back to the Broadcom Compatibility Guide
Final Thoughts
An upgrade from ESXi 8.0 U3 to 9.0 is not just about whether the installer will run.
It is also about whether the underlying platform is still supported, and whether the current firmware and CPU combination make sense for the target state.
This script helps answer those questions in a much more efficient way by combining:
-
vCenter inventory data
-
PCI hardware discovery
-
CPU validation
-
Broadcom Compatibility Guide lookups
-
Firmware overlap analysis
Instead of checking every host manually, you get a clear report that helps shape your upgrade strategy.
And that is exactly the kind of information you want before starting a VCF lifecycle transition.
Complete Script
# ==============================================================================================
# ESXi Upgrade Compatibility Tool (8.0 U3 -> 9.x) - Inclusief CPU & Correcte Strategie
# ==============================================================================================
function Get-ClusterHosts {
param([string]$ClusterName)
$Cluster = Get-Cluster -Name $ClusterName -ErrorAction SilentlyContinue
if (-not $Cluster) {
Write-Error "Cluster '$ClusterName' niet gevonden!"
return $null
}
return Get-VMHost -Location $Cluster | Where-Object { $_.ConnectionState -eq "Connected" }
}
function Get-VCGComparison {
param(
[string]$VID, [string]$DID, [string]$SVID, [string]$SDID,
[string]$DeviceName, [string]$Ver, [string]$HostName
)
$Uri = "https://compatibilityguide.broadcom.com/compguide/programs/viewResults?limit=10&page=1"
$BodyObj = @{
programId = "io"
filters = @(
@{ displayKey = "vid"; filterValues = @($VID) },
@{ displayKey = "did"; filterValues = @($DID) },
@{ displayKey = "svid"; filterValues = @($SVID) },
@{ displayKey = "maxSsid"; filterValues = @($SDID) },
@{ displayKey = "productReleaseVersion"; filterValues = @("ESXi $Ver") }
)
keyword = @()
date = @{ startDate = $null; endDate = $null }
}
$JsonBody = $BodyObj | ConvertTo-Json -Depth 10
try {
$SearchRes = Invoke-RestMethod -Uri $Uri -Method Post -Body $JsonBody -Headers @{"content-type"="application/json";"user-persona"="live"} -TimeoutSec 15
if ($SearchRes.data.count -gt 0) {
$ProdID = $SearchRes.data.fieldValues.uuid[0]
$EscapedVer = [uri]::EscapeDataString("ESXi $Ver")
$DetailUri = "https://compatibilityguide.broadcom.com/compguide/programs/viewDetails?programId=io&id=$ProdID&filterBy=$EscapedVer"
$Details = Invoke-RestMethod -Uri $DetailUri -Method Post -Body "" -Headers @{"user-persona"="live"; "accept"="application/json"}
return $Details.data.details.subsections.fieldValues | ForEach-Object {
[PSCustomObject]@{
HostName = $HostName
ESXiVersion = $Ver
Device = $DeviceName
DriverName = $_.driverName
DriverVersion = $_.driverVersion
Firmware = ($_.firmwareVersion + " " + $_.additionalFirmwareVersion).Trim()
BCL_Link = "https://compatibilityguide.broadcom.com/detail.php?deviceid=$ProdID"
}
}
} else {
return [PSCustomObject]@{
HostName = $HostName
ESXiVersion = $Ver
Device = $DeviceName
DriverName = "--- NOT SUPPORTED ---"
DriverVersion = "N/A"
Firmware = "N/A"
BCL_Link = "N/A"
}
}
} catch {
return $null
}
}
function Get-VCGCPUStatus {
param([string]$CpuId, [string]$Ver, [string]$HostName, [string]$FullCpuName)
$DetailUri = "https://compatibilityguide.broadcom.com/compguide/programs/viewDetails?programId=cpu&id=$CpuId"
try {
$Details = Invoke-RestMethod -Uri $DetailUri -Method Post -Body "" -Headers @{"user-persona"="live"; "accept"="application/json"}
$SupportedReleaseField = $Details.data.details.subsections | Where-Object { $_.order -eq 2 } | ForEach-Object { $_.fieldValues }
if (-not $SupportedReleaseField) {
$SupportedReleaseField = $Details.data.details.subsections.fields | Where-Object { $_.displayKey -eq "esxi" } | Select-Object -ExpandProperty fieldValues
}
$IsSupported = $SupportedReleaseField -match $Ver
$Status = if ($IsSupported) { "SUPPORTED" } else { "--- NOT SUPPORTED ---" }
return [PSCustomObject]@{
HostName = $HostName
ESXiVersion = $Ver
Device = "CPU: $FullCpuName"
DriverName = $Status
DriverVersion = "N/A"
Firmware = "N/A"
BCL_Link = "https://compatibilityguide.broadcom.com/detail?program=cpu&productId=$CpuId&persona=live"
}
} catch {
return $null
}
}
function Export-CompatibilityReport {
param([System.Collections.ArrayList]$ReportData, [string]$ClusterName)
$Timestamp = Get-Date -Format "yyyyMMdd_HHmm"
$FileName = "ESXi_Upgrade_Check_$($ClusterName)_$($Timestamp).csv"
$ReportData | Export-Csv -Path $FileName -NoTypeInformation -Delimiter ";" -Encoding UTF8
Write-Host "`n[OK] Rapport opgeslagen: $FileName" -ForegroundColor Green
}
# --- AANGEPASTE OVERLAP LOGICA VOOR CPU ---
function Export-FirmwareOverlapReport {
param($ReportData, [string]$ClusterName)
$OverlapResults = $ReportData | Group-Object HostName, Device | ForEach-Object {
$DeviceEntries = $_.Group
$DeviceName = $DeviceEntries[0].Device
# Check of dit een CPU entry is
if ($DeviceName -like "CPU:*") {
$TargetStatus = $DeviceEntries | Where-Object { $_.ESXiVersion -eq "9.0" } | Select-Object -ExpandProperty DriverName
$IsSupported = ($TargetStatus -eq "SUPPORTED")
[PSCustomObject]@{
HostName = $DeviceEntries[0].HostName
Device = $DeviceName
CommonFirmware = "N/A (CPU Check)"
UpgradeNeeded = if ($IsSupported) { "No - CPU is Supported" } else { "YES - CPU NOT SUPPORTED FOR 9.0" }
BCL_Link = $DeviceEntries[0].BCL_Link
}
}
else {
# Originele Hardware Logica
$FW_v8 = $DeviceEntries | Where-Object { $_.ESXiVersion -eq "8.0 U3" } | ForEach-Object { $_.Firmware -split " " } | Select-Object -Unique
$FW_v9 = $DeviceEntries | Where-Object { $_.ESXiVersion -eq "9.0" } | ForEach-Object { $_.Firmware -split " " } | Select-Object -Unique
$CommonFirmware = $FW_v8 | Where-Object { $FW_v9 -contains $_ -and $_ -ne "N/A" }
[PSCustomObject]@{
HostName = $DeviceEntries[0].HostName
Device = $DeviceName
CommonFirmware = if ($CommonFirmware) { $CommonFirmware -join ", " } else { "NO OVERLAP FOUND" }
UpgradeNeeded = if ($CommonFirmware) { "No - Common FW available" } else { "Yes - Firmware change required" }
BCL_Link = $DeviceEntries[0].BCL_Link
}
}
}
$Timestamp = Get-Date -Format "yyyyMMdd_HHmm"
$FileName = "Firmware_Upgrade_Strategy_$($ClusterName)_$($Timestamp).csv"
$OverlapResults | Export-Csv -Path $FileName -NoTypeInformation -Delimiter ";" -Encoding UTF8
Write-Host "[OK] Strategie rapport opgeslagen: $FileName" -ForegroundColor Cyan
}
# --- MAIN EXECUTION ---
Connect-VIServer -Server "XXXXX"
Write-Host "Ophalen VCG CPU Masterlijst..." -ForegroundColor Gray
$CpuBodyObj = @{ programId = "cpu"; filters = @(); keyword = @(); date = @{ startDate = $null; endDate = $null } } | ConvertTo-Json
try {
$GlobalCPUList = (Invoke-RestMethod -Uri "https://compatibilityguide.broadcom.com/compguide/programs/viewResults?limit=500&page=1" -Method Post -Body $CpuBodyObj -Headers @{"content-type"="application/json";"user-persona"="live"}).data.fieldValues
} catch {
Write-Error "Kon CPU Masterlijst niet ophalen."
}
$Clusters = Get-Cluster
foreach ($cluster in $Clusters) {
$ClusterName = $cluster.Name
$TargetVersions = @("8.0 U3", "9.0")
$Hosts = Get-ClusterHosts -ClusterName $ClusterName
if ($Hosts) {
$FullReport = foreach ($ESXiHost in $Hosts) {
Write-Host "`n>>> Processing Host: $($ESXiHost.Name)" -ForegroundColor Cyan
# --- CPU CHECK ---
$FullCpuName = $ESXiHost.ExtensionData.Summary.Hardware.CpuModel
$SearchTerm = ($FullCpuName -replace "(R)|(TM)|CPU|@.*$|Processor|Intel|AMD", "").Trim()
$Words = $SearchTerm -split " " | Where-Object { $_.Length -gt 2 }
$MatchedCpu = $null
if ($GlobalCPUList) {
foreach ($Series in $GlobalCPUList) {
$MatchCount = 0
foreach ($Word in $Words) { if ($Series.cpuSeries.name -like "*$Word*") { $MatchCount++ } }
if ($MatchCount -ge 1) { $MatchedCpu = $Series; break }
}
}
foreach ($Ver in $TargetVersions) {
if ($MatchedCpu) {
Write-Host " Checking $Ver for CPU: $SearchTerm..." -NoNewline
$CpuRes = Get-VCGCPUStatus -CpuId $MatchedCpu.uuid -Ver $Ver -HostName $ESXiHost.Name -FullCpuName $FullCpuName
if ($CpuRes) {
$StatusColor = if ($CpuRes.DriverName -eq "SUPPORTED") { "Green" } else { "Red" }
Write-Host " [$($CpuRes.DriverName)]" -ForegroundColor $StatusColor
$CpuRes
}
}
}
# --- HARDWARE CHECK ---
$esxcli = Get-EsxCli -VMHost $ESXiHost -V2
$HardwarePCIList = $esxcli.hardware.pci.list.Invoke()
$UniqueHardwareList = $HardwarePCIList | Where-Object {
$_.DeviceClassName -match "Network|Ethernet|Storage|RAID|SCSI|Fibre Channel" -and
$_.DeviceClassName -notmatch "Bridge|Peripheral|Hub"
} | Group-Object VendorID, DeviceID, SubVendorID, SubDeviceID | ForEach-Object { $_.Group[0] }
foreach ($Hw in $UniqueHardwareList) {
$VID = ("{0:X4}" -f [int]$Hw.VendorID).ToLower()
$DID = ("{0:X4}" -f [int]$Hw.DeviceID).ToLower()
$SVID = ("{0:X4}" -f [int]$Hw.SubVendorID).ToLower()
$SDID = ("{0:X4}" -f [int]$Hw.SubDeviceID).ToLower()
foreach ($Ver in $TargetVersions) {
Write-Host " Checking $Ver for $($Hw.DeviceName)..." -NoNewline
$Res = Get-VCGComparison -VID $VID -DID $DID -SVID $SVID -SDID $SDID -DeviceName $Hw.DeviceName -Ver $Ver -HostName $ESXiHost.Name
if ($Res) { Write-Host " [OK]" -ForegroundColor Green; $Res } else { Write-Host " [NO DATA]" -ForegroundColor Yellow }
}
}
}
if ($FullReport) {
Export-CompatibilityReport -ReportData $FullReport -ClusterName $ClusterName
Export-FirmwareOverlapReport -ReportData $FullReport -ClusterName $ClusterName
}
}
}
Disconnect-VIServer -Server * -Confirm:$false
The original article was posted on: whatkabirwrites.nl