📋 Overview
Manually resizing VMs in VMware vSphere is a common but time-consuming operational task — especially when it involves coordinating across multiple datacentres, shutting down VMs safely, verifying changes, and notifying teams. One mistake can mean downtime or an incorrectly sized machine nobody notices for weeks.
This guide walks through a production-ready PowerShell + PowerCLI solution integrated with Jenkins Parameterised Build, giving your infrastructure team a simple, auditable, self-service interface to resize VMs in both the PROD and DR vCenter environments — with zero need to touch a script or a vCenter console directly.
🚀 Why Jenkins Parameterised Build?
Jenkins Parameterised Builds turn any script into a governed, self-service interface. Engineers fill in a simple form and Jenkins handles the rest — no SSH sessions, no shared credentials in chat, no ad-hoc PowerShell runs.
✅ Prerequisites
-
Jenkins Server (LTS recommended)
Windows-based Jenkins agent recommended so PowerShell runs natively. Jenkins 2.346+ supports modern pipeline syntax.
-
VMware PowerCLI installed on Jenkins Agent
Run:
Install-Module VMware.PowerCLI -Scope AllUsers -Forceon the agent node. Disable CEIP:Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP $false -Confirm:$false -
Jenkins Plugins Required
Install: PowerShell Plugin, Credentials Binding Plugin, Email Extension Plugin. Go to Manage Jenkins → Plugin Manager to install.
-
vCenter Service Account
Create a dedicated read/write service account in vCenter with VM modify permissions. Store credentials in Jenkins → Credentials → Global Credentials.
-
SMTP Relay Configured
Ensure the Jenkins agent can reach the SMTP relay (172.0.2.35 in this setup) for email alerting.
-
Log Directory Created on Agent
Create the path
C:\_vSphere_Patching\CPU_Memory_PS_Logs\on the agent before first run. The script auto-creates log files on each execution.
⚙️ Jenkins Job Setup — Step by Step
1. Create a New Freestyle Job
Go to Jenkins Dashboard → New Item. Name it VMware-CPU-Memory-Resize, select Freestyle Project, then click OK.
2. Enable "This project is parameterised"
Tick This project is parameterised under the General section. Add the following parameters:
| Parameter Name | Type | Description | Required |
|---|---|---|---|
PROD_Vcenter_Name |
String | PROD vCenter FQDN (e.g. prod-vcenter...) | Required |
DR_Vcenter_Name |
String | DR vCenter FQDN (e.g. dr-vcenter...) | Required |
Username |
Credentials | vCenter service account (via Jenkins Credentials) | Required |
Password |
Password | vCenter service account password (masked) | Required |
VM_Name |
String | Exact VM name to resize | Required |
CPU |
Choice | Set to yes to resize CPU, no to skip |
Boolean |
Memory |
Choice | Set to yes to resize Memory, no to skip |
Boolean |
CPU_Increase |
String | Number of vCPUs to set (e.g. 4) |
Conditional |
Memory_Increase |
String | Memory in GB to set (e.g. 16) |
Conditional |
no and yes (in that order so no is the safe default). This prevents engineers from accidentally triggering both when only one was intended.
3. Bind Credentials as Environment Variables
Under Build Environment, tick Use secret text(s) or file(s). Add bindings for your vCenter credentials stored in Jenkins Credentials store. Map them to environment variables Username and Password so the script picks them up via $Env:Username and $Env:Password.
4. Add Build Step — Execute PowerShell
Add a Build Step → Execute Windows PowerShell step. In the script field enter:
& "C:\Scripts\VMware-CPU-Memory-Resize.ps1"
The script file should be placed on the Jenkins agent at the above path, or pulled from Git SCM (see optional step below).
5. (Optional) Source from Git Repository
Under Source Code Management, select Git and point to:
https://github.com/automatewithravi/VMware.git
Set the script path to the file in the repo. This ensures every build pulls the latest approved version of the script.
6. Configure Post-Build Email Notifications
Under Post-build Actions → Editable Email Notification, configure recipients and triggers. The script already handles failure emails inline, but Jenkins-level notifications provide an additional safety net for pipeline failures.
7. Save and Test
Click Save. Then click Build with Parameters and test with a non-critical VM first. Review the Console Output in Jenkins and the transcript log file generated on the agent.
🔀 Script Logic Flow
The script follows a deterministic flow on every run — connect, validate, shutdown, modify, verify, start, alert.
| ▶ Jenkins Parameterised Build Triggered |
| ↓ |
| Validate & Connect to PROD / DR vCenter |
| ↓ on failure → Email alert → Exit |
| Check VM Power State |
| ↓ if PoweredOn → Graceful Guest Shutdown (180s) → Force Stop if needed |
| Apply Changes: Set-VMCPU and/or Set-VMMemory |
| ↓ |
| Verify: Confirm actual CPU/Memory matches requested values |
| ↓ on verified → Power On VM |
| ✅ Complete — Transcript logged |
📄 The PowerShell Script
The script is structured into clean reusable functions — Connect-VCenter, Stop-VMSafely, Set-VMCPU, Set-VMMemory, Confirm-CPUChange, and Send-AlertEmail — while preserving the original logic exactly. No logic modification has been made.
# ── HELPER FUNCTIONS ─────────────────────────────────────────── function Send-AlertEmail { param ([string]$Subject, [string]$Body) Send-MailMessage -SmtpServer $SMTP_Server ` -From $Mail_From -To $Mail_To ` -Subject ($Subject + " - " + (Get-Date -Format "dd-MM-yyyy")) ` -Body $Body } function Connect-VCenter { param ([string]$VCenterName, [string]$Label) $Connection = Connect-VIServer -Server $VCenterName -User $Username -Password $Password if ($Connection.IsConnected -ne $true) { Write-Host " Unable to connect to $Label"; Exit 1 } Write-Host " $Label vCenter connected." -ForegroundColor Green } function Stop-VMSafely { param ([string]$VMName, [int]$GraceSeconds = 180) Get-VM | Where-Object { $_.Name -like $VMName } | Stop-VMGuest -Confirm:$false Start-Sleep -Seconds $GraceSeconds Get-VM | Where-Object { $_.Name -like $VMName -and $_.PowerState -like "*On" } | Stop-VM -Confirm:$false } function Set-VMCPU { param ([string]$VMName, [int]$NumCPU) Get-VM -Name $VMName | Set-VM -NumCpu $NumCPU -Confirm:$false } function Set-VMMemory { param ([string]$VMName, [int]$MemoryGB) Get-VM -Name $VMName | Set-VM -MemoryGB $MemoryGB -Confirm:$false } function Confirm-CPUChange { param ([string]$VMName, [int]$Expected) $Actual = (Get-VM -Name $VMName).NumCpu return $Actual -eq $Expected } function Confirm-MemoryChange { param ([string]$VMName, [int]$Expected) $Actual = (Get-VM -Name $VMName).MemoryGB return $Actual -eq $Expected } # ── EXECUTION FLOW ───────────────────────────────────────────── $VM_PowerStatus = (Get-VM -Name $VMName).PowerState if ($CPU -eq "yes" -and $Memory -ne "yes") { if ($VM_PowerStatus -eq "PoweredOn") { Stop-VMSafely -VMName $VMName } Set-VMCPU -VMName $VMName -NumCPU $NumberofCPU_required if (Confirm-CPUChange -VMName $VMName -Expected $NumberofCPU_required) { Start-VMAndVerify -VMName $VMName } } elseif ($Memory -eq "yes" -and $CPU -ne "yes") { if ($VM_PowerStatus -eq "PoweredOn") { Stop-VMSafely -VMName $VMName } Set-VMMemory -VMName $VMName -MemoryGB $Memory_Size_required if (Confirm-MemoryChange -VMName $VMName -Expected $Memory_Size_required) { Start-VMAndVerify -VMName $VMName } } elseif ($CPU -eq "yes" -and $Memory -eq "yes") { if ($VM_PowerStatus -eq "PoweredOn") { Stop-VMSafely -VMName $VMName } Set-VMMemory -VMName $VMName -MemoryGB $Memory_Size_required Set-VMCPU -VMName $VMName -NumCPU $NumberofCPU_required $MemOK = Confirm-MemoryChange -VMName $VMName -Expected $Memory_Size_required $CPUOK = Confirm-CPUChange -VMName $VMName -Expected $NumberofCPU_required if ($MemOK -and $CPUOK) { Start-VMAndVerify -VMName $VMName } }
🛠️ Common Issues & Troubleshooting
| Issue | Likely Cause | Fix |
|---|---|---|
| Cannot connect to vCenter | Wrong FQDN or credentials | Verify FQDN resolves from Jenkins agent; test credentials manually via PowerCLI |
| VM still powered on after 180s | Guest tools not installed / hung OS | Force Stop-VM fallback handles this automatically; check VM console |
| CPU/Memory mismatch after Set-VM | Hot-add not enabled or resource limits | Verify VM hardware settings; check VM version supports hot-add |
| Email not sent | SMTP unreachable from agent | Test Test-NetConnection 172.0.2.35 -Port 25 from the agent |
| PowerCLI not found | Not installed on agent scope | Re-run install with -Scope AllUsers as Administrator |