
Picking Up Where We Left Off
If you’ve been following along with the Zero to VCAP series, we just wrapped up configuring eight Cisco UCS B200 blades with direct-attached Fibre Channel storage from the NetApp ASA A30 — a full FlexPod Cisco Validated Design (CVD) build leveraging NetApp ASA A30 all-flash storage. The blades are racked, zoned, booted, and ESXi is up across all eight hosts.
That part always feels good.
But before you let the VCF 9.0 installer touch your hosts, there’s one step that will either save your deployment… or quietly break it.
Security hardening, time synchronization, and consistent DNS across every host in the environment.
Skip this, and you’re not failing fast — you’re failing halfway through bring-up when it hurts the most.
Why This Step Matters
This isn’t optional for me.
Whether it’s a customer engagement, a lab build, or part of my Zero to VCAP journey, every ESXi host gets the same baseline before anything else touches them.
- Consistent DNS
- Consistent NTP
- Consistent security configuration
If even one host drifts, you’ll find out at the worst possible time.
⚠️ Real-world lesson learned
I’ve seen VCF deployments fail mid-bring-up because:
- One host had incorrect DNS
- Another had NTP drift
- A third didn’t meet security baseline
Everything looked fine… until it didn’t.
The Script: BestPractices_Security_Hardening.ps1
This is the script I use to enforce a clean, repeatable ESXi baseline before VCF deployments.
This version combines:
- DNS configuration
- NTP configuration
- Advanced ESXi security hardening
All into a single workflow.
This is not a “nice to have” script — this is a baseline.
I run this script on every environment I build — customer deployments, lab setups, and this VCF implementation is no different.
Consistency across hosts isn’t optional. It’s the difference between a smooth deployment and chasing issues later.
What the Script Actually Does
This script standardizes your entire ESXi host baseline in a single run.
🔹 1. NTP Configuration
- Prompts for NTP servers (defaults provided)
- Removes existing entries
- Applies consistent NTP across all hosts
- Ensures service is running and set to start automatically
👉 Eliminates time drift issues that break VCF bring-up
🔹 2. DNS Configuration
- Prompts for DNS servers and domain name
- Applies consistent DNS configuration to all hosts
- Ensures all hosts resolve correctly
👉 Prevents certificate and validation failures
🔹 3. Advanced Security Hardening (14 Settings)
Applies and verifies key ESXi advanced settings including:
- Account lockout policies
- Password complexity
- Shell timeout controls
- Memory salting
- MOB disablement
- TLS / protocol hardening
- Execution restrictions
👉 Aligns with CIS Benchmark and VMware Security Configuration Guide
🔹 4. Dry Run Mode (This is Huge)
Before making any changes, the script runs in dry mode.
- Shows current vs desired state
- Makes zero changes
- Lets you validate everything first
👉 This is your safety net
🔹 5. Verification + API Fallback
After applying settings:
- Script reads values back to confirm success
- Falls back to API methods if needed
👉 Ensures nothing silently fails
🔹 6. HTML + CSV Reporting
Every run generates:
- HTML dashboard with KPI summary
- Per-host results table
- CSV export for tracking
👉 This becomes your documentation
Running the Script (Real Example)
From VS Code:
cd .\VMware\ESXi\PowerShell\Hardening\
.\BestPractices_Security_Hardening.ps1
Step 1 — Safety Notice and Dry Run Prompt
The script starts with a safety notice and recommends running in dry mode first.
Say yes.

Step 2 — Connection Selection
You are prompted to select how to target hosts:
- vCenter
- Target all hosts or a specific cluster
- Standalone ESXi host(s)
- Enter one or multiple hosts (comma-separated)
- hosts.csv file
- Provide a CSV with hosts listed in a
Hostcolumn
- Provide a CSV with hosts listed in a

For this deployment, I’m using Option 2 — Standalone ESXi host(s).
At this stage, there is no vCenter deployed yet, so I’m connecting directly to each ESXi host.
In my environment, the ESXi hosts follow a consistent naming convention:
dc3-hst-esxi01 – dc3-hst-esxi08
Since the script expects a comma-separated list, I enter them like this:
dc3-hst-esxi01,dc3-hst-esxi02,dc3-hst-esxi03,dc3-hst-esxi04,dc3-hst-esxi05,dc3-hst-esxi06,dc3-hst-esxi07,dc3-hst-esxi08
This allows the script to run across all hosts in a single pass and ensures a consistent baseline before VCF bring-up begins.
💡 Pro Tip
Using consistent host naming conventions like this makes automation significantly easier and reduces the risk of targeting the wrong systems during deployment.
Step 3 — Log Directory
Choose where logs and reports will be stored.

Step 4 — NTP Configuration Prompt
Enter your NTP servers or use defaults.

Step 5 — DNS Configuration Prompt
Enter:
- Primary DNS
- Optional secondary DNS
- Domain name

Step 6 — Credentials
Provide credentials for ESXi hosts.

Step 7 — Host Discovery
The script connects to each host and builds the working list.

Step 8 — Dry Run Output
The script evaluates all hosts and compares current vs desired state.


Step 9 — Review HTML Report
Review before applying changes.

Step 10 — Apply Mode
Run again in apply mode to enforce settings.

Step 11 — Final HTML Report
Final validation and documentation output.

How This All Fits Together
Before moving into final validation, here’s the flow I follow every time.
At a High Level
- Build ESXi hosts
- Run script (dry run)
- Review report
- Run script (apply)
- Validate output
- Proceed to VCF bring-up
Pre-VCF 9.0 Checklist
| Item | Expected State |
|---|---|
| NTP | Consistent |
| DNS | Forward + reverse working |
| Security | Applied |
| Hosts | No drift |
| Reports | Clean |
Advanced Security Settings — What They Do and Why They Matter
The advanced settings applied by the script are based on VMware / Broadcom security guidance and the CIS Benchmark for ESXi. These settings are designed to reduce attack surface, enforce secure access, and ensure consistent behavior across all hosts before VCF bring-up.
🔐 Account Lockout and Access Control
- Security.AccountLockFailures = 5
Locks a local account after five failed login attempts, helping prevent brute-force attacks. - Security.AccountUnlockTime = 900
Automatically unlocks accounts after 15 minutes, balancing usability and security.
🔑 Password Policy
- Security.PasswordHistory = 5
Prevents reuse of recent passwords, enforcing proper credential rotation. - Security.PasswordQualityControl
Enforces strong password policies, including minimum length and complexity rules.
🧠 Memory and VM Security
- Mem.ShareForceSalting = 2
Prevents memory sharing attacks by isolating memory pages between virtual machines.
🔒 Host Access and Interfaces
- Config.HostAgent.plugins.solo.enableMob = false
Disables the Managed Object Browser to reduce exposure of internal APIs.
🖥️ Shell and Session Controls
- UserVars.ESXiShellTimeOut
Automatically disables the ESXi shell after inactivity. - UserVars.ESXiShellInteractiveTimeOut
Logs out inactive shell sessions. - UserVars.DcuiTimeOut
Logs out inactive console sessions.
📡 Logging and Visibility
- Config.HostAgent.log.level = info
Provides balanced logging for troubleshooting without excessive log growth.
🔐 Protocol and Execution Hardening
- UserVars.ESXiVPsDisabledProtocols
Disables insecure or legacy protocols. - VMkernel.Boot.execInstalledOnly = true
Ensures only trusted, signed binaries are executed.
📊 Telemetry and UI Behavior
- UserVars.HostClientCEIPOptIn = 2
Disables telemetry data collection. - UserVars.SuppressShellWarning = 1
Suppresses UI warnings during automation workflows.
Flexible Execution — Automated or Manual
By default, the script applies all recommended settings automatically to enforce a consistent baseline quickly.
However, I’ve built in logic to run the advanced settings section in manual mode, allowing you to:
- Review each setting individually
- Compare current vs recommended values
- Choose whether to apply or override
This is especially useful when working with security teams, compliance requirements, or testing configurations in a lab.
👉 You get the best of both worlds — automation for consistency and speed, and manual control when needed
Final Thoughts
When everything is green, you’re not just ready.
You’re setting yourself up for a clean VCF bring-up.
And that’s the difference between:
- A smooth deployment
- And chasing issues later
This is how I do it across all environments.
Teaching to fish. 🎣
Get the Script
Humbledgeeks Github
https://github.com/humbledgeeks/infra-automation
What’s Next
Next up: VCF 9.0 Cloud Builder and bring-up JSON.