🚀 Overview
Manually provisioning a new virtual machine in VMware vSphere means navigating multiple UI wizards, typing network details, resizing disks by hand, then RDP-ing into the guest OS to rename the machine and extend partitions. On a good day that is 30–45 minutes per VM. On a bad day it is an incident waiting to happen.
This post walks through a fully function-based PowerShell / PowerCLI script that handles the entire lifecycle — connecting to a Production or DR vCenter, cloning from a template, resizing CPU and RAM, attaching up to five additional disks, configuring a static IP and DNS inside the guest OS via VMware Tools, renaming the hostname, extending the C: partition, and emailing the team a formatted HTML provisioning report — all driven by a Jenkins Parameterised Build with zero engineer scripting required.
🏗️ Architecture & Flow
The diagram below shows the full lifecycle from Jenkins trigger through to confirmation email.
✅ Prerequisites
Jenkins LTS with a Windows Build Agent
The script requires a Windows node running PowerShell 5.1+. Register a Windows agent in
Jenkins → Manage Nodes, label it windows-powercli, and configure
it to run as a Windows service so it starts automatically after reboots.
VMware PowerCLI Module
On the Windows agent node run:
Install-Module VMware.PowerCLI -Scope AllUsers -Force
then disable the CEIP prompt:
Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP $false
vSphere Template
A Windows Server 2019/2022 VM template with VMware Tools pre-installed. A 40 GB base C: drive is sufficient — the script resizes it at deployment time based on the Jenkins parameter.
Jenkins Plugins
Install from Manage Jenkins → Plugins:
Credentials Binding (secrets injection).
Log Directory on the Agent
Create C:\vSphere_Automation\Logs\NewVM_Provisioning\ on the Windows agent and
grant the Jenkins service account write permissions. Timestamped transcript files land here
for every build run.
📜 Script Walkthrough — Functions
The script is refactored into eight purpose-built PowerShell functions, each owning
a single phase of the provisioning lifecycle. Every function has a .SYNOPSIS comment
block, is independently testable, and can be extended without touching unrelated code.
Connect-ToVCenter
Connects and validates the vCenter session. Exits code 1 on failure so Jenkins marks the build FAILED immediately.
New-VMFromTemplate
Calls New-VM with all deployment parameters. ESXi host auto-selected by environment flag.
Set-VMResources
Null-guarded adjustment of memory, vCPU count, and primary disk size. Blank = template default preserved.
Add-AdditionalDisks
Loops a single array to attach up to 5 persistent disks (E: through I:) — replacing 5 separate if/else blocks.
Wait-ForVMwareTools
Polls toolsStatus every 5 seconds until toolsOK — called twice: after power-on and after hostname restart.
Set-VMGuestNetwork
Runs netsh commands via VMware Tools to configure static IP, subnet, gateway, and DNS — no RDP needed.
Set-VMGuestHostname
Renames the Windows computer name and triggers an async restart via Invoke-VMScript.
Get-VMProvisioningReport
Collects final VM state into a hashtable: hostname, power state, CPU, RAM, disks, timestamps — drives the HTML email.
🔐 Credential Security
$Env:GuestPassword using the Jenkins
Credentials Binding plugin. It is stored as an encrypted Secret Text credential
in Jenkins and never appears in build logs, script files, or notification emails.
Do not pass it as a plain-text String Parameter.
📧 Email Addresses
All notification emails are sent from vmware-automation@automatewithravi.com to it-alerts@automatewithravi.com via the internal SMTP relay.
🔧 Jenkins Setup — Parameterised Build (CI)
This gives engineers a self-service form in Jenkins to provision a VM on demand — no PowerShell knowledge required. All inputs are captured at runtime; the script itself is never modified between deployments.
Create a New Freestyle Job
Go to Jenkins → New Item → Freestyle Project. Name it vSphere-New-VM-Provisioning. Tick "This project is parameterised" at the top of the General section.
Add Choice Parameters for Target Environment
Click Add Parameter → Choice Parameter. Name: Production,
choices: no then yes (no as default is safer).
Repeat for a second parameter named DR. Engineers choose which vCenter to target
before every build run.
Add String Parameters for VM Details
Add String Parameter entries for: VMName, VMGuestname,
VMTemplate, VMDatastoreName, VMFolder,
VM_Networkname, IPAddress, SubnetMask,
GatewayIP, DNSServerIP, VM_Memory, VM_CPU,
VM_Cdrive. See the full reference table in Section 7.
Store Credentials in Jenkins
Go to Manage Jenkins → Credentials → Global → Add Credentials.
Add two Secret Text entries with IDs vcenter-password and
guest-admin-password. These values are encrypted at rest and masked in all build logs.
Bind Credentials in Build Environment
Under Build Environment, tick "Use secret text(s) or file(s)".
Map vcenter-password → variable name Password and
guest-admin-password → variable name GuestPassword.
Jenkins injects these as environment variables before the build step runs.
Add a Windows PowerShell Build Step
Under Build → Add Build Step → Windows PowerShell, enter the two lines below.
Jenkins automatically injects all parameters and bound secrets as $Env: variables.
Set-ExecutionPolicy Bypass -Scope Process -Force & "C:\vSphere_Automation\Scripts\New_VM_Creation_Cluster.ps1"
Restrict to the Windows PowerCLI Agent
Under General → Restrict where this project can be run, enter
windows-powercli. This prevents the job from running on a Linux agent where
PowerCLI is unavailable, which would fail silently.
Archive Transcript Logs as Build Artefacts
Under Post-build Actions → Archive the artefacts, enter
C:/vSphere_Automation/Logs/NewVM_Provisioning/*.txt.
Every build retains a full timestamped audit transcript downloadable from the Jenkins UI.
📋 Build Parameters Reference
Every parameter below appears in the Jenkins Build with Parameters form. Optional fields are null-checked by the script — leave blank and the template default is preserved.
| Parameter Name | Type | Description | Required? |
|---|---|---|---|
Production | Choice | Deploy to Production vCenter? (no / yes) | REQUIRED |
DR | Choice | Deploy to DR vCenter? (no / yes) | REQUIRED |
Username | String | vCenter service account — e.g. svc-vsphere@automatewithravi.com | REQUIRED |
Password | Secret | vCenter password injected via credentials binding | REQUIRED |
VMName | String | vSphere display name for the new VM | REQUIRED |
VMGuestname | String | Windows computer name (hostname) inside the guest OS | REQUIRED |
VMTemplate | String | Exact name of the vSphere template to clone from | REQUIRED |
VMDatastoreName | String | Target datastore for VM files | REQUIRED |
VMFolder | String | vCenter inventory folder path for the new VM | REQUIRED |
VM_Networkname | String | vSphere port group or distributed switch name | REQUIRED |
IPAddress | String | Static IPv4 address for the guest NIC | Optional |
SubnetMask | String | Subnet mask — e.g. 255.255.255.0 | Optional |
GatewayIP | String | Default gateway IP address | Optional |
DNSServerIP | String | Primary DNS server IP address | Optional |
VM_Memory | String | RAM in GB (e.g. 8). Blank = template default | Optional |
VM_CPU | String | Number of vCPUs. Blank = template default | Optional |
VM_Cdrive | String | C: drive size in GB. Blank = template default | Optional |
VM_HDD1 | Choice | Add extra disk 1 as E: drive? (no / yes) | Optional |
VM_HDD1_Size | String | Size in GB for extra disk 1 (E:) | Optional |
VM_HDD2 … VM_HDD5 | Choice | Same pattern for disks 2–5 (F: through I:) | Optional |
GuestPassword | Secret | Guest OS administrator password via credentials binding | REQUIRED |
🌟 Benefits
Speed
Full VM provisioning — disks, network, OS config — in under 10 minutes vs 30–45 minutes manually.
No Credential Exposure
vCenter and guest passwords are encrypted in Jenkins Credentials. They never appear in logs, scripts, or emails.
Self-Service for Engineers
Any authorised engineer provisions a VM from the Jenkins form. Zero PowerShell or vSphere UI knowledge required.
Consistent Every Time
Every VM is built from the same template with the same script version. No drift between Production and DR builds.
Full Audit Trail
Jenkins records who triggered the build, when, and with which parameters. Transcript logs are archived per build.
Automatic Reporting
HTML summary email on success, alert on failure — from vmware-automation@automatewithravi.com.
💡 Pro Tips & Best Practices
🔑 Use a Dedicated Service Account
Create a dedicated AD account (e.g. svc-vsphere@automatewithravi.com) with the
minimum vCenter roles required: Virtual Machine → Provisioning and
Resource → Assign VM to Resource Pool. Never use a personal or domain admin account
for automated workflows.
📦 Keep the Template Thin
The template should contain only the base OS, VMware Tools, and your corporate hardening baseline. Deliver all application software post-provisioning via a downstream Jenkins job (Chocolatey, Ansible, or DSC) so the template stays small and clone times stay fast.
⏱️ Add a VMware Tools Timeout Guard
The do … until toolsOK polling loop spins indefinitely if VMware Tools fails to
start. Add a loop counter (e.g. 60 iterations × 5 seconds = 5-minute ceiling) and throw a
terminating error on timeout so Jenkins marks the build FAILED cleanly rather than
hanging the agent.
🛡️ Prevent Dual-Environment Deployments
Add a validation check in your PowerShell script that errors if both
Production = yes and DR = yes are selected simultaneously.
Alternatively use an Active Choices parameter so selecting one automatically
disables the other in the Jenkins UI.
C:\vSphere_Automation\Logs\NewVM_Provisioning\
with a timestamp filename per run. Archive them in Jenkins under Post-build Actions
to retain a permanent, downloadable record for every deployment — invaluable during
incident investigations.
📦 GitHub Repository
The complete refactored script — New VM creation in cluster.ps1 — is published in the VMware automation repository. Clone it, update the vCenter hostnames and ESXi host names to match your environment, store your credentials in Jenkins, and you are ready to run your first parameterised build.
Star the repository to be notified when new VMware automation scripts are added — covering snapshot management, datastore reporting, host patching, and more.