A PowerShell HTML health-check report for VMware Cloud Foundation 9 / vSphere 9.
VCF Checker is based on Alan Renouf's vCheck and rebuilt for PowerShell 7 + VCF.PowerCLI 9.1, cross-platform (Windows / Linux / macOS). It runs as a scheduled task and emails a single, readable report that shows only the things that need attention. Empty sections don't appear.
Current release
v9.0.5. Per-tag history inCHANGELOG.md; framework review and the post-9.0 roadmap inARCHITECTURE.md.
| Navigation |
|---|
| Requirements |
| Installing |
| Plugin Profiles |
| What is checked |
| Plugins |
| Styles |
| Jobs & Settings |
| Origin & Credits |
- PowerShell 7.6+ (cross-platform; Windows PowerShell 5.1 is not supported)
- VCF.PowerCLI 9.1:
Install-PSResource VCF.PowerCLI(the Broadcom rebrand ofVMware.PowerCLI). The engine itself imports only the Core/Storage/Vds/Cis.Core modules for fast startup; anything else autoloads on demand. - A VMware Cloud Foundation 9.x / vSphere 9 environment. Deprecated 9.x surfaces (Enhanced Linked Mode, the vSAN Management SDK, techpreview appliance APIs) are not used. For multiple vCenters (including vCenter Groups), run one VCF Checker per vCenter.
-
Install PowerShell 7.6+ and VCF.PowerCLI:
Install-PSResource VCF.PowerCLI -
Copy the VCF Checker files to the desired location.
-
Configure the connection. Either edit
GlobalVariables.ps1andPlugins/00 Initialize/000 Connection Plugin for vCenter.ps1, or (preferred for unattended runs and clean git state) set environment variables:$env:VCHECK_SERVER = 'vcenter.example.local' $env:VCHECK_USER = 'administrator@vsphere.local' $env:VCHECK_PASSWORD = '<password>'
-
Run it:
pwsh ./vCheck.ps1(add-configfor the setup wizard). Schedule via cron / systemd timer (Linux) or Task Scheduler (Windows) for the daily email.
Every plugin declares $PluginTags; named profiles in Profiles.psd1
select which plugins run. Pick a profile per run:
pwsh ./vCheck.ps1 -PluginProfile quick # CLI (wins) …
$PluginProfile = "security" # … or the setting in GlobalVariables.ps1| Profile | Contents |
|---|---|
health (default) |
actionable operational problems: the daily report |
full |
every enabled plugin, including informational sections |
security |
hardening + compliance posture (lockdown, SSH, certs, VIBs, users…) |
capacity |
space, overcommitment, limits, vSAN capacity |
events |
event-history scans (vMotions, HA restarts, VM removals…) |
inventory |
informational/audit dumps (build numbers, hardware, services) |
quick |
health minus the expensive plugins (roughly half the runtime) |
ops |
the VCF Operations sections only (see below); needs Operations configured |
Connection and disconnect plugins always run. Disabling a plugin outright (the hard
switch) is still done by appending .disabled to its filename.
~110 active plugins across these categories (see the Plugins/ tree; each plugin is
a small, editable PowerShell script):
- vCenter: error/warning events, sessions, VCSA appliance health, storage, services, time sync, local users and password policy, build/version mapping
- Cluster: HA configuration and restarts, DRS rules, vLCM image compliance, slot sizes, datastore visibility, s/vMotion history
- Host: hardware status, dead LUN paths, multipath/NTP/syslog/swapfile/power policy configuration, certificates, reboot-required, network redundancy, inode usage
- Datastore: free space, overallocation, sDRS, maintenance mode, vSAN configuration / capacity / component limits (OSA and ESA aware)
- Network: vSwitch/portgroup security policies, free ports, NIC error counters
- VM: snapshots (age, size, phantom, consolidation), tools, CPU ready/usage, swapping/ballooning, EVC, removable media, limits/reservations, logging, hardware version, misnamed VMs, and more
- Hardening: SNMP, SSH, remote logging, secure boot, trusted VIBs, execution policy
- Solutions: vSphere Replication RPO violations (disabled unless VR is deployed)
- Operations (optional, off by default): verdicts borrowed from VCF Operations: its own service health, active alerts joined back to the vCenter objects they are about, monitoring coverage gaps, capacity forecasts, and reclaimable waste with a cost figure (see VCF Operations)
VCF Checker asks vCenter "what is the configuration right now?" and applies its own
thresholds. VCF Operations has already done the analysis: time-series, dynamic thresholds,
symptom correlation, a Broadcom-maintained rule engine. This track queries Operations for
verdicts, not inventory, and joins them back to the vCenter objects the report is
already about. Full research and lab measurements are in OPERATIONS.md.
It is off by default. With no Operations server configured, nothing is imported, nothing
is connected, and the report is byte-for-byte what it was. To enable it, set the server in
Plugins/00 Initialize/005 Connection Plugin for VCF Operations.ps1:
# Start of Settings
$VcfOpsServer = "vcf-ops.example.local" # blank disables the whole track
$VcfOpsUser = "admin" # an Operations user, NOT the vCenter SSO account
# End of SettingsThe password comes from $env:VCHECK_OPS_PASSWORD (prompted only if unset, so scheduled runs
work unattended). VCHECK_OPS_SERVER, VCHECK_OPS_USER and VCHECK_OPS_AUTHSOURCE override
the settings the same way VCHECK_SERVER/VCHECK_USER do for vCenter.
| What it adds | Operations' own service health; active alerts joined to vCenter objects; monitoring-coverage gaps; capacity headroom and time-remaining forecasts; reclaimable waste with a cost figure; and the datastores where vCheck's own thresholds and Operations' forecast disagree |
| Cost | ~6s for the whole track, of which ~5s is importing VMware.Sdk.Vcf.Ops; every individual query is sub-second (measured on VCF Operations 9.1) |
| Scope | one vCenter. Operations is fleet-wide, so resources are filtered to the connected vCenter's InstanceUuid; genuinely fleet-wide alerts are labelled as such |
| Safety | read-only by construction: VcfOps.ps1 will only call cmdlets on an explicit read allowlist, and no plugin talks to the SDK directly |
| Requires | VMware.Sdk.Vcf.Ops (ships with VCF.PowerCLI 9.1) and a reachable, licensed VCF Operations instance |
The Operations plugins are tagged ops and slow, so they are part of health and full,
excluded from quick, and are the entire content of the ops profile. When the active profile
selects none of them the connection is skipped too, so quick pays nothing for having
Operations configured.
A plugin is a .ps1 under Plugins/<NN Category>/ named NNN Short Title.ps1
(three digits, step 5; number order = execution order). It writes finding objects to
stdout and declares metadata. See CONTRIBUTING.md for the rules
(inventory reuse, batching, problems-only ethos).
Your plugin must contain a settings section (may be empty). Each setting is a comment line (the wizard prompt) followed by the variable:
# Start of Settings
# Set the warning threshold in percent
$Threshold = 75
# End of Settings
$Title - display name (clean, no category prefix - the category renders as a chip)
$Header - section header in the report ([count] is replaced with the row count)
$Comments - one-line description shown under the header
$Display - "Table", "List" or "None"
$Author - author name(s)
$PluginVersion - version number
$PluginCategory - category (matches the folder: vCenter, Cluster, Hosts, Datastore, Network, VM, Hardening, ...)
$PluginTags - comma-separated profile tags: health, security, capacity, events, inventory, slow, ops
# Start of Settings
# End of Settings
# generate report content here; objects written to stdout become the section rows
@{"Plugin"="Awesome"}
$Title = "Plugin Template"
$Header = "Plugin Template: [count]"
$Comments = "Comment about this awesome plugin"
$Display = "List"
$Author = "Plugin Author"
$PluginVersion = 1.0
$PluginCategory = "VM"
$PluginTags = "health"
Plugins can define $TableFormat rules to colour cells/rows by value. The variable is
a hashtable keyed by column name; each value is an array of rules mapping a comparison
to a formatting instruction (Row/Cell, then attribute|value):
$TableFormat = @{"PercentFree" = @(@{ "-le 25" = "Row,class|warning" },
@{ "-le 15" = "Row,class|critical" });
"CapacityGB" = @(@{ "-lt 500" = "Cell,style|background-color: silver" })}
The style's semantic classes are ok, warning, critical. Using them also drives
the severity sorting, the scorecard and the TOC dots.
Eight themes ship, all fluid full-width and email-safe (inline styles, table layout,
system-font fallbacks, dark-mode color-scheme meta so clients don't re-invert dark
themes), with a verdict banner, severity scorecard, category-grouped TOC, top-accent
severity bars, and long-table folding. Select one with -Style <Name> (CLI, wins) or
$Style in GlobalVariables.ps1:
| Style | Mode | Look |
|---|---|---|
Midnight (default) |
dark | near-black slate, electric-cyan accent |
Default |
light | "Mission Control": console-navy chrome, signal-cyan |
Clarity |
light | VMware Clarity: action-blue, cool grays, Clarity City type |
ClarityDark |
dark | VMware Clarity: vSphere-Client dark mode |
Graphite |
dark | true-neutral charcoal, quiet blue accent |
Indigo |
dark | deep indigo/violet, modern SaaS |
Arctic |
dark | Nord-inspired soft cool slate |
Ember |
dark | warm charcoal + copper accent |
pwsh ./vCheck.ps1 -Style GraphiteLayouts are a separate axis from themes: a theme sets the palette, a layout sets the
structure (TOC style, plugin-table shape, skeleton). Select with -Layout <name> or
$ReportLayout in GlobalVariables.ps1; any theme combines with any layout:
| Layout | TOC | Plugin tables | Best for |
|---|---|---|---|
classic (default) |
grouped pills | full tables | the standard report |
dashboard |
Category|Crit|Warn|Total index grid |
2-column card grid | at-a-glance triage |
pwsh ./vCheck.ps1 -Style Graphite -Layout dashboardArchitecture: all rendering lives in Styles/_layouts/. _common.ps1 holds the
chrome + shared helpers, one file per layout overrides the body. Each theme's Style.ps1
is just a colour/font token block that dot-sources the selected layout. A new theme is
one token block; a new layout is one Get-LayoutMain. Drop a Header.png next to a
theme's Style.ps1 to brand the report.
Plugin visualizations: a plugin can render an email-safe chart (donut/pie/bar/stacked/
gauge/heat/sparkline) on top of its table by setting $Chart. Charts inherit the active
theme; donut/pie are rasterised to a PNG in pure PowerShell (no native libs). See
CHARTS.md for the contract.
Each plugin result passed to the style carries: Title, Author, Version, Details, Display, TableFormat, Header, Comments, TimeToRun, Category.
The -job parameter takes an XML config selecting an alternate settings file and an
explicit plugin list:
<vCheck>
<globalVariables>GlobalVariables.ps1</globalVariables>
<plugins path="Plugins">
<plugin>000 Connection Plugin for vCenter.ps1</plugin>
<plugin>010 Datastore Information.ps1</plugin>
<plugin>990 Disconnect.ps1</plugin>
</plugins>
</vCheck>
For most cases, prefer plugin profiles. Job XMLs remain useful for fully custom plugin sets.
vCheckUtils.ps1 provides Export-vCheckSettings / Import-vCheckSettings to carry
your configured thresholds between builds via a CSV:
PS> . .\vCheckUtils.ps1
PS> Export-vCheckSettings -outfile E:\MyvCheckSettings.csv # in the old build
PS> Import-vCheckSettings -csvfile E:\MyvCheckSettings.csv # in the new build
VCF Checker is based on vCheck-vSphere
by Alan Renouf and its many contributors. The report engine, the plugin model and a large
part of the plugin set descend from that project, and plugin authors are still credited in
each plugin's $Author. It is no longer a fork in the git sense: it shares no history with
upstream and moves on its own (PowerShell 7 + VCF 9 only, a reworked plugin set validated
against a live VCF 9.1 environment, a new report renderer, plugin profiles and charts).
Maintained by Dario Dörflinger (@virtualFrog), with development sponsored by soulTec. Released under the MIT license, which keeps the original vCheck copyright notice (LICENSE.md).