Automating vSphere License Compliance Audits with VCF PowerCLI
April 1, 2026 · 12 min read
Broadcom changed the compliance rules and the tooling at the same time. If you're still running quarterly manual audits — or worse, relying on the old VMware.PowerCLI module — you're behind on both counts.
Since April 10, 2025, every VMware product purchase carries a 72-core minimum per license instance (up from 16). The 72-core minimum was partially reversed for renewals after customer pushback, but it still applies to all new orders. Add to that a 20% penalty for late renewals and Broadcom's telemetry actively phoning home on vSphere+ and cloud-connected deployments, and the cost of being out of compliance at renewal has gone up significantly. (CRN reporting from March 2025)
The script I'm running pulls core counts, license keys, and host inventory from every production cluster, flags any host with an eval license or no assigned key, and exports a timestamped CSV. Takes 30 seconds on 40 hosts.
First: Update Your Module
VMware.PowerCLI was deprecated in June 2025 (version 13.3.0 was the last release). The replacement is VCF.PowerCLI, which Broadcom signed with a Broadcom certificate — not the old VMware one. If you're getting certificate warnings during install, that's why.
# Remove the old module if present
Get-Module -Name VMware.PowerCLI -ListAvailable |
Uninstall-Module -Force -AllVersions
# Install the current module
Install-Module -Name VCF.PowerCLI -Scope AllUsers -SkipPublisherCheck
Import-Module VCF.PowerCLI
# Verify
Get-Module VCF.PowerCLI | Select-Object Name, Version
If Install-Module fails with a publisher check error even with -SkipPublisherCheck, you're likely running an older PSGallery root cert. Update your PowerShell PackageManagement module first:
Install-Module -Name PackageManagement -Force -AllowClobber
What We're Actually Checking
With Broadcom's subscription model, there are three things you need to know about every host:
- Is it running an eval license? Eval keys are
00000-00000-00000-00000-00000. If you have hosts on eval in production you've got a problem. - What license key is assigned? You need this for reconciliation against your Broadcom contract.
- How many physical cores does this host have? Broadcom licenses per core. Your contracted core count needs to cover all physical cores across licensed hosts. The 72-core-per-product minimum applies to new orders (it was partially relaxed for renewals).
There is no PowerCLI cmdlet that directly queries Broadcom's licensing backend and returns a subscription compliance status. Anyone who tells you otherwise is either hallucinating or referring to a feature that doesn't exist in the public tooling. What you can do — and what Broadcom's own audit process does — is inventory your deployed core counts and compare them to your contract.
The Script
Connect first:
$vcenter = "vcenter.yourdomain.local"
$credential = Get-Credential -Message "vCenter credentials"
Connect-VIServer -Server $vcenter -Credential $credential
The account needs at minimum read access on the cluster and host objects. The built-in Read-Only role is sufficient for the inventory and license key queries below. You don't need admin rights for a read-only compliance audit.
Core Count and License Inventory
$reportData = @()
# Scope to production clusters only — adjust the filter to match your naming
$clusters = Get-Cluster | Where-Object { $_.Name -like "*Prod*" -or $_.Name -like "*Production*" }
foreach ($cluster in $clusters) {
$hosts = Get-VMHost -Location $cluster | Where-Object { $_.ConnectionState -eq "Connected" }
foreach ($vmHost in $hosts) {
$licenseKey = $vmHost.LicenseKey
$coreCount = $vmHost.NumCpu # physical CPU threads; for physical cores see below
# NumCpu returns logical processors. For physical core count:
$view = $vmHost | Get-View
$physCores = ($view.Hardware.CpuInfo.NumCpuCores)
$sockets = ($view.Hardware.CpuInfo.NumCpuPackages)
$isEval = ($licenseKey -eq "00000-00000-00000-00000-00000")
$reportData += [PSCustomObject]@{
Cluster = $cluster.Name
HostName = $vmHost.Name
ESXiVersion = $vmHost.Version
LicenseKey = if ($isEval) { "EVAL - NOT LICENSED" } else { $licenseKey }
PhysicalCores = $physCores
Sockets = $sockets
Status = if ($isEval) { "CRITICAL: Eval License" }
elseif (-not $licenseKey) { "CRITICAL: No Key Assigned" }
else { "Licensed" }
CheckedAt = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
}
}
}
A few notes on the core counting:
$vmHost.NumCpureturns the total logical processor count (cores × HT threads). Do not use this for licensing.$view.Hardware.CpuInfo.NumCpuCoresreturns physical cores. This is what Broadcom counts.NumCpuPackagesis the socket count. With Intel Xeon Scalable and AMD EPYC, you'll typically see 2 sockets with 16–64 physical cores each. Know your socket/core split before going into a renewal conversation.
Add the 72-Core Floor Check
# Group by cluster to get total licensed core count
$clusterSummary = $reportData |
Where-Object { $_.Status -eq "Licensed" } |
Group-Object -Property Cluster |
ForEach-Object {
$totalCores = ($_.Group | Measure-Object -Property PhysicalCores -Sum).Sum
[PSCustomObject]@{
Cluster = $_.Name
LicensedHosts = $_.Count
TotalPhysCores = $totalCores
MeetsMinimum = if ($totalCores -ge 72) { "Yes" } else { "WARNING: Below 72-core minimum" }
}
}
$clusterSummary | Format-Table -AutoSize
The 72-core minimum applies per product purchase on new orders (it was partially relaxed for renewals), not per cluster — but running this check per cluster gives you the data you need if Broadcom asks for a breakdown by workload grouping.
Export and Alert
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
$reportPath = "C:\Logs\vSphere_License_Audit_$ts.csv"
$reportData | Export-Csv -Path $reportPath -NoTypeInformation -Encoding UTF8
# Alert summary to console
$criticalHosts = $reportData | Where-Object { $_.Status -like "CRITICAL*" }
if ($criticalHosts.Count -gt 0) {
Write-Host "CRITICAL: $($criticalHosts.Count) host(s) need attention:" -ForegroundColor Red
$criticalHosts | Select-Object HostName, LicenseKey, Status | Format-Table -AutoSize
} else {
Write-Host "All $($reportData.Count) hosts have assigned license keys." -ForegroundColor Green
}
Write-Host "Full report: $reportPath"
If you want email or Teams alerting, wire up Send-MailMessage or a webhook call where the Write-Host lines are. I use a Teams webhook in prod — the JSON payload is about 10 lines, webhook endpoint comes from your Teams channel connector settings.
Scheduling It
I run this daily at 6 AM via Windows Task Scheduler on a jump host that has access to vCenter. The script writes a dated CSV to a network share that my manager can pull if Broadcom ever asks for a usage report.
# One-liner to create the scheduled task — adjust paths to match your environment
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -File C:\Scripts\vsphere-license-audit.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "06:00AM"
Register-ScheduledTask -TaskName "vSphere License Audit" `
-Action $action -Trigger $trigger -RunLevel Highest
Don't alert on every run. If all hosts are licensed, you want silence. Alert only on CRITICAL status (eval key, no key). If you alert on everything, the ops team will route it to /dev/null within a week.
Troubleshooting
Install-Module VCF.PowerCLI fails with "No match was found"
Your PowerShellGet version doesn't support the Broadcom-signed package. Run Install-Module -Name PowerShellGet -Force, restart your PowerShell session, then retry.
Connect-VIServer returns "Cannot complete login due to an incorrect user name or password"
The SSO domain in the username matters. administrator@vsphere.local is the default, but if your vCenter is joined to AD, use your AD credentials in domain\user format instead.
Get-View returns null for Hardware.CpuInfo
This happens when the host is in maintenance mode or disconnected. The script's Where-Object { $_.ConnectionState -eq "Connected" } filter should catch this, but if a host disconnects mid-run, wrap the Get-View call in a try/catch.
CSV opens in Excel with all data in one column
Excel's delimiter detection breaks on some regional settings. Open Excel → Data → From Text/CSV → import the file and specify comma as the delimiter. Or use -UseCulture on Export-Csv to match your system's list separator.
The license key shows as all zeros on a host you know is licensed
The key is written to the host when vCenter assigns it. If the host temporarily lost connectivity to vCenter and was re-added, the key assignment doesn't always re-sync automatically. Re-assign the license from the vCenter license manager UI to force the write.
What This Doesn't Cover
This script tells you what's deployed and what keys are assigned. It does not:
- Verify that your assigned keys are valid against Broadcom's backend (that requires the Broadcom Customer Portal or a support case)
- Check vSAN capacity licensing separately — vSAN has its own per-TiB licensing under VCF that you need to audit with
Get-VsanClusterConfiguration - Cover NSX licensing — NSX Manager has its own license status under System → Licenses
If you're running VCF with SDDC Manager, SDDC Manager's Administration → Licensing view shows the consolidated picture across vSphere, vSAN, and NSX in one place. Worth checking there first before running individual component scripts.
Stay ahead of the VMware changes
We're publishing detailed comparison guides, migration walkthroughs, and cost calculators. Get them in your inbox.
Written by Rob Notaro
Senior infrastructure engineer specializing in VMware, Horizon VDI, and enterprise virtualization. Currently deploying Horizon 2512 and VCF in production environments.