Introduction
Provisioning a VM is only the first step. Guest-level configuration like hostname setup, IP assignment, domain join, and application bootstrapping are often manual, inconsistent, and time-consuming. With PowerCLI, you can automate guest customization both during and after VM deployment.
In this article, we will explore:
- Creating and applying customization specs
- Modifying NIC mappings for static IPs
- Using
Invoke-VMScriptto configure the OS post-deployment - Managing credentials and session reuse securely
My Personal Repository on GitHub
Step 1: Review or Create a Customization Spec
View existing specs:
Get-OSCustomizationSpec
Create a new one in vSphere Client or use PowerCLI:
New-OSCustomizationSpec -Name "Win2019-Auto" `
-OSType Windows `
-FullName "VMware Admin" `
-OrgName "Lab" `
-ProductKey "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" `
-AdminPassword (ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force) `
-TimeZone 035 `
-ChangeSid $true
Step 2: Deploy VM with Customization Spec
New-VM -Name "SQLNode01" `
-Template "Win2019-Base" `
-Datastore "DS01" `
-VMHost "esxi01.lab.local" `
-OSCustomizationSpec "Win2019-Auto"
Step 3: Modify NIC Mapping for Static IPs
$spec = Get-OSCustomizationSpec -Name "Win2019-Auto"
Set-OSCustomizationNicMapping -OSCustomizationSpec $spec `
-Position 1 `
-IpMode UseStaticIP `
-IpAddress "192.168.10.101" `
-SubnetMask "255.255.255.0" `
-DefaultGateway "192.168.10.1"
Step 4: Use Invoke-VMScript for In-Guest Configuration
Example: Create a Directory and Registry Key on a Windows VM
$vm = Get-VM -Name "SQLNode01"
$cred = Get-Credential
Invoke-VMScript -VM $vm -ScriptText 'mkdir C:\Tools; reg add "HKLM\Software\MyCompany" /v Installed /t REG_SZ /d True /f' `
-GuestCredential $cred -ScriptType Bat
Example: Run a Bash Script on a Linux VM
$vm = Get-VM -Name "UbuntuApp01"
$cred = Get-Credential
Invoke-VMScript -VM $vm -ScriptText 'echo "export ENV=dev" >> ~/.bashrc' `
-GuestCredential $cred -ScriptType Bash
Step 5: Pass Parameters to Scripts
You can store custom values in a CSV or hashtable and loop through deployments.
$servers = Import-Csv "C:\Configs\LinuxVMs.csv"
foreach ($vmInfo in $servers) {
$vm = Get-VM -Name $vmInfo.Name
$script = "hostnamectl set-hostname $($vmInfo.Hostname)"
Invoke-VMScript -VM $vm -ScriptText $script -GuestCredential (Get-Credential) -ScriptType Bash
}
Diagram: Guest Customization Automation

Use Case: Automating SQL Server Prep on Windows
$vm = Get-VM -Name "SQL01"
$cred = Get-Credential
Invoke-VMScript -VM $vm `
-ScriptText 'Install-WindowsFeature -Name NET-Framework-45-Core' `
-GuestCredential $cred -ScriptType Powershell
You can expand this to include copying ISOs, mounting media, and unattended setup.
Security Tips
- Always use
SecureStringfor passwords - Avoid hardcoding credentials in scripts
- Use a jump host or dedicated PowerShell session with just-in-time permissions
- Clean up any in-guest temp files created by scripts
Troubleshooting
| Issue | Fix |
|---|---|
Invoke-VMScript returns blank | Check that VMware Tools is running and up-to-date |
| Static IP not applied | Use Set-OSCustomizationNicMapping before deployment |
| Script execution blocked | Adjust execution policy or permissions in guest OS |
| Guest credentials rejected | Ensure the user has remote script permissions and is not UAC-blocked |
What’s Next
In the next article, we will cover:
- Automating VM encryption and TPM setup with PowerCLI
- Assigning KMS policies
- Verifying encryption status and compliance