A prevalent task for a VMware admin is to power down VM X and add more CPU or RAM to the VM. Infrastructure as code enthusiasts suggest that any operation performed manually should be automated. Let us look at how we could automate this.
PowerCLI
We want to resize the VM TESTVM from using 24GB to 64GB of RAM. We want the script to turn off the VM, add the RAM, and start it up again.
# Load VMware PowerCLI module
Import-Module VMware.PowerCLI
# Connect to vCenter Server
$vcServer = "your_vcenter_server"
$vcUser = "your_username"
$vcPassword = "your_password"
Connect-VIServer -Server $vcServer -User $vcUser -Password $vcPassword
# Define the VM name and new memory size
$vmName = "TESTVM"
$newMemoryGB = 64
# Get the VM object
$vm = Get-VM -Name $vmName
# Power off the VM
if ($vm.PowerState -eq "PoweredOn") {
Write-Host "Powering off VM: $vmName"
Stop-VM -VM $vm -Confirm:$false
}
# Change the memory size
Write-Host "Changing memory size of VM: $vmName to $newMemoryGB GB"
Set-VM -VM $vm -MemoryGB $newMemoryGB -Confirm:$false
# Power on the VM
Write-Host "Powering on VM: $vmName"
Start-VM -VM $vm -Confirm:$false
# Disconnect from vCenter Server
Disconnect-VIServer -Server $vcServer -Confirm:$false
Write-Host "Operation completed successfully."
Okay, that would work. To enhance the script, we added external credential storage, logging, and verifications. The script will now read credentials from a file, log operations to `/tmp/resize.log`, and verify the VM’s power states.
# Load VMware PowerCLI module
Import-Module VMware.PowerCLI
# Define paths for credentials and log file
$credentialFile = "C:\path\to\credentials.txt"
$logFile = "/tmp/resize.log"
# Function to log messages
function Log-Message {
param (
[string]$message
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $message" | Out-File -FilePath $logFile -Append
}
# Read credentials from external file
$credentials = Import-Clixml -Path $credentialFile
# Connect to vCenter Server
$vcServer = "your_vcenter_server"
Connect-VIServer -Server $vcServer -Credential $credentials
# Define the VM name and new memory size
$vmName = "TESTVM"
$newMemoryGB = 64
# Get the VM object
$vm = Get-VM -Name $vmName
# Power off the VM if it is powered on
if ($vm.PowerState -eq "PoweredOn") {
Log-Message "Powering off VM: $vmName"
Stop-VM -VM $vm -Confirm:$false
# Verify the VM is powered off
$vm | Wait-Tools -TimeoutSeconds 120
$vm = Get-VM -Name $vmName # Refresh the VM object
if ($vm.PowerState -ne "PoweredOff") {
Log-Message "Failed to power off VM: $vmName"
exit 1
}
Log-Message "VM $vmName is powered off successfully"
}
# Change the memory size
Log-Message "Changing memory size of VM: $vmName to $newMemoryGB GB"
Set-VM -VM $vm -MemoryGB $newMemoryGB -Confirm:$false
# Power on the VM
Log-Message "Powering on VM: $vmName"
Start-VM -VM $vm -Confirm:$false
# Verify the VM is powered on
$vm | Wait-Tools -TimeoutSeconds 120
$vm = Get-VM -Name $vmName # Refresh the VM object
if ($vm.PowerState -ne "PoweredOn") {
Log-Message "Failed to power on VM: $vmName"
exit 1
}
Log-Message "VM $vmName is powered on successfully"
# Disconnect from vCenter Server
Disconnect-VIServer -Server $vcServer -Confirm:$false
Log-Message "Operation completed successfully."
Create a file for the credentials.
Get-Credential | Export-Clixml -Path "C:\path\to\credentials.txt"
This will prompt you to enter your vCenter username and password, which will be securely stored in the specified file.
Running the powershell:


In vCenter we see the same happening

Terraform
A lot of companies have standard tooling when it comes to code. Can we do the same with Terraform?
First, ensure the `govc` tool is installed and verify its installation. You can use a shell script to check if `govc` is installed, and if not, install it:
#!/bin/bash
if ! command -v govc &> /dev/null; then
echo "govc not found, installing..."
wget -q https://github.com/vmware/govmomi/releases/download/v0.20.0/govc_linux_amd64.gz
gunzip govc_linux_amd64.gz
mv govc_linux_amd64 govc
sudo mv govc /usr/local/bin/
sudo chmod +x /usr/local/bin/govc
fi
echo "govc is installed."
To securely store vSphere credentials, use Terraform’s `terraform.tfvars` file and environment variables:
Environment Variables: To store sensitive information like passwords in environment variables:
export TF_VAR_vsphere_user="your_username"
export TF_VAR_vsphere_password="your_password"
export TF_VAR_vsphere_server="your_vcenter_server"
Terraform Configuration: Use `variables` in Terraform to reference these environment variables
variable "vsphere_user" {
description = "vSphere username"
type = string
}
variable "vsphere_password" {
description = "vSphere password"
type = string
sensitive = true
}
variable "vsphere_server" {
description = "vSphere server address"
type = string
}
The main terraform module
provider "vsphere" {
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
allow_unverified_ssl = true
}
resource "vsphere_virtual_machine" "testvm" {
name = "TESTVM"
memory = 64
resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
network_interface {
network_id = data.vsphere_network.network.id
}
lifecycle {
ignore_changes = [
memory
]
}
}
resource "null_resource" "power_off_on" {
provisioner "local-exec" {
command = <<EOT
./install_verify_govc.sh
govc vm.power -off=true /${var.vsphere_datacenter}/vm/${var.vsphere_folder}/TESTVM
govc vm.change -vm=TESTVM -m=64
govc vm.power -on=true /${var.vsphere_datacenter}/vm/${var.vsphere_folder}/TESTVM
EOT
environment = {
GOVC_URL = var.vsphere_server
GOVC_USERNAME = var.vsphere_user
GOVC_PASSWORD = var.vsphere_password
GOVC_INSECURE = "true"
}
}
}
data "vsphere_datacenter" "dc" {
name = var.vsphere_datacenter
}
data "vsphere_compute_cluster" "cluster" {
name = var.vsphere_cluster
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_datastore" "datastore" {
name = var.vsphere_datastore
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_network" "network" {
name = var.vsphere_network
datacenter_id = data.vsphere_datacenter.dc.id
}
Running this code will execute the same operation. Resizing the VM from 24GB to 64GB.
Conclusion
PowerCLI is a robust tool designed for VMware operations. Built on PowerShell, it excels at both Day 1 (initial setup) and Day 2 (ongoing management) tasks.
Terraform achieves its full potential when utilized to deploy and manage large-scale Infrastructure as Code (IaC) solutions that oversee various aspects of a VMware and virtual machine environment.
If your emphasis is on detailed scripting and handling ongoing vSphere operations, PowerCLI is an excellent option. Conversely, if you prefer to manage infrastructure as code and require deploying consistent environments, Terraform is a better fit.