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:

  1. Identify the installed PCI devices

  2. Look up every device in the Broadcom Compatibility Guide

  3. Compare support for the current ESXi version and the target version

  4. Check recommended driver and firmware combinations

  5. Verify whether the CPU is still supported

  6. 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:

  1. Connects to the specified vCenter Server

  2. Retrieves all clusters and connected ESXi hosts

  3. Collects CPU model information per host

  4. Matches the CPU against the Broadcom Compatibility Guide CPU list

  5. Checks CPU support for both ESXi 8.0 U3 and ESXi 9.0

  6. Uses Get-EsxCli -V2 to retrieve installed PCI hardware such as:

    • Network adapters

    • Ethernet controllers

    • Storage controllers

    • RAID adapters

    • SCSI adapters

    • Fibre Channel adapters

  7. Queries the Broadcom Compatibility Guide for each device and target ESXi version

  8. Extracts supported driver, driver version and firmware information

  9. Compares current and target compatibility

  10. Generates a detailed CSV report per cluster

  11. 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

Related articles

  • Hybrid Cloud
  • Cloud Native
  • Dev Enablement
  • Platform Engineering
  • Implementation and Adoption
  • Digital Workspace
  • Application Management Services
  • Data Center Modernization
  • Managed Cloud Platform
  • Public Cloud Landing Zones
  • Sovereign Cloud
Visit our knowledge hub
Visit our knowledge hub
Kabir Ali IT Consultant

Let's talk!

Knowledge is key for our existence. This knowledge we use for disruptive innovation and changing organizations. Are you ready for change?

"*" indicates required fields

First name*
Last name*
This field is hidden when viewing the form