Shadministration — Byte-sized adventures in tech

Bootstrapping VM’s Using VMWare PowerCLI

vmware-powercli-bootstrap-script

Lately I’ve been spinning up more Linux VM’s (mostly Debian/Ubuntu) in my VMWare ESXI home lab. While it’s simple enough to launch a new VM, I found it tedious to configure certain settings after launch. Most of these were the same for each VM – update/install packages, configure SSH, create directories, open firewall ports, etc. The obvious answer to this is to write a bash script and be done with it – which I did. But without SSH first being enabled, I wasn’t sure how to get that bash script on the guest OS without manually creating it using the VMWare guest console and typing in the script contents. Enter PowerCLI.

PowerCLI is a PowerShell module for managing VM’s in a VMWare vSphere or ESXI environment. It’s chocked full of commands that will make your life much easier if you are managing more than a handful of VM’s. You can install it by running “Install-Module VMware.PowerCLI” in an administrative PowerShell console. The two commands I used to accomplish my goal here were “Copy-VMGuestFile” and “Invoke-VMScript”. The first one I used to copy my bash script from my local computer (a Windows 10 machine) to the VM guest OS filesystem (Ubuntu Linux). I then used “Invoke-VMScript” to execute that script on the guest OS. Throw this and some supporting variables into a PowerShell script, and you’re a double-click away from performing base-configuration on your new VM. Here’s my PowerShell code on GitHub so you can see exactly what I did.

# PREREQUISITE: Install the VMWare PowerCLI module on your system
$presentDir = Get-Location | Select-Object -ExpandProperty Path
$vmwEnviHostname = "ESXI01"
$vmName = Read-Host "Enter the name of the Virtual Machine to connect to"
$sshKeyPath = Read-Host "Enter path to the private key (including the key file name) to use for ssh connection to this VM"
# Put contents of public ssh key into variable
$sshPubKeyContents = Get-Content "$sshKeyPath.pub"
$vmwCred = Get-Credential -Message "Enter your vSphere or ESXI host credentials"
$guestOSCred = Get-Credential -Message "Enter the username and password of the inital guest OS user"
$guestOSUser = $guestOSCred.Username
# Associated bash script in same directory as this script
$pathToBashSSHInitScript = "$presentDir\Ubuntu-SSH-Init.sh"
# Connect to vSphere/ESXI environment
try {
Connect-VIServer -Server $vmwEnviHostname -User $vmwCred.Username -Password (ConvertFrom-SecureString -SecureString $vmwCred.Password -AsPlainText)
}
catch {
throw $_
Write-Host "Invalid credentials or VMWare host cannot be reached"
break
}
# Copy bash file to VM user directory
try {
Get-Item "$pathToBashSSHInitScript" | Copy-VMGuestFile -Destination "/home/$guestOSUser" -VM $vmName -LocalToGuest -GuestUser $guestOSCred.Username -GuestPassword (ConvertFrom-SecureString -SecureString $guestOSCred.Password -AsPlainText)
}
catch {
throw $_
Write-Host "Unable to copy bash ssh init file to guest"
break
}
# Run SSH-init bash script. Does a package update, installs openssh, opens port 22 in firewall, and creates ssh dir.
try {
Invoke-VMScript -VM $vmName -ScriptText "echo $(ConvertFrom-SecureString -SecureString $guestOSCred.Password -AsPlainText) | sudo -S bash ~/Ubuntu-SSH-Init.sh" -GuestUser $guestOSCred.Username -GuestPassword (ConvertFrom-SecureString -SecureString $guestOSCred.Password -AsPlainText) -ScriptType "Bash"
}
catch {
throw $_
Write-Host "Invalid VM Name or guest OS credentials, or error running ssh-init bash script on guest"
break
}
# Import public ssh key contents on local machine to authorized_keys file on guest. Clear command history as we passed our sudo password in the command.
try {
Invoke-VMScript -VM $vmName -ScriptText "echo $sshPubKeyContents >> ~/.ssh/authorized_keys; history -c" -GuestUser $guestOSCred.Username -GuestPassword $guestOSCred.Password
}
catch {
throw $_
Write-Host "Could not find ssh public key (is it named the same as the associated private key?)"
}
Disconnect-VIServer -Confirm:$false
Read-Host "SSH Configuration for $vmName complete. Press ENTER to exit dialogue..."

Below is the bash script I copied over to the VM. You could put anything you want in here, but just for reference:

#!/usr/bin/env bash
apt-get -y update
apt-get -y install openssh-server
ufw allow 22
mkdir ~/.ssh
touch ~/.ssh/authorized_keys

Now, this is a pretty simple script, and there’s probably a lot more I could and should do to improve error-checking and make this modular for different VM configurations or for running on different guest OS’s. There may be other ways of accomplishing this as well, but hopefully this will give you what you need to tailor this solution to your requirements. Happy scripting!

Leave a Reply

Your email address will not be published. Required fields are marked *