One of my roles is to stand up environments for development or testing projects. I receive requests on a weekly basis for anywhere from 1-10 virtual machine environments. If I were to use the typical method of vSphere to clone a set of 10 it may take 4-5 hours. The thing about this script is in order to clone multiple VM’s the specs need to be the same, meaning vCPU, RAM and hard drives. You also need to determine the names you want to use for the virtual machines and then write them down in a text file called servers.txt. I’ll break down the code to show you exactly what it’s doing.
$VM_Location = "Example"
$servers = (Get-Content servers.txt)
Line 1. Change this variable to suite your environment. This is the inventory location. Where your virtual machine will be stored in the inventory list.
Line 2. Read in the server names from the servers.txt file – Store in the same location as this script.
function clone_vms {
$template_name = (Read-Host "Enter the template name").Trim()
$ESX_host = (Read-Host "Enter the ESX host").Trim()
$datastore = (Read-Host "Enter the datastore location for the c:\ drive")
foreach($server in $servers)
{
New-VM -Location $VM_Location -VMHost $ESX_host -Name $server -Template $template_name -Datastore $datastore
}
}
Line 1. Simply creating a function to clone the virtual machines. Makes the code a bit more organized and cleaner.
Line 2. Prompting the user for the name of the template. This needs to be exact.
Line 3. Prompting the user for the name of the esx host to place these virtual machines on.
Line 4. Prompting the user for the name of the datastore for the c:\ drive.
Line 5. Simple foreach statement which says for each server in the servers.txt file do the following block of code {xxxxx}
Line 7. New-VM is the cmdlet used to create a new virtual machine. Here we define the inventory location with the $VM_Location variable. We also define the ESX Host where we want to place this vm, the name of the VM, the template to use and the datastore location. Just a tip, if you want to run multiple clones at the same time use the -RunAsync at the end of line 6, inside the two }}. Be warned though if you run more than 4-5 at a time this will severely impact the performance of vCenter. Right now once one vm clone is finished it automatically starts the next one.
function change_vcpu{
$vCPU = Read-Host "Enter the number of vCPU's"
foreach($server in $servers)
{
Set-VM $server -NumCpu $vCPU -Confirm:$false -RunAsync
}
}
Line 4. Set-VM cmdlet is used to change things like vCPU. We define the $server we want to change the vCPU on based on the foreach loop. We also need to let the cmdlet know how many vCPU we are changing to. The -Confirm:$false switch is telling the cmdlet to not prompt me for permission to change this. The -RunAsync switch says change all servers at the same time.
function add_harddrive {
$size = (Read-Host "Enter size in KB").Trim()
$datastore = (Read-Host "Enter DataStore Location").Trim()
foreach($server in $servers)
{
New-HardDisk -VM $server -CapacityKB $size -ThinProvisioned -DataStore $datastore
}
}
Line 6. The New-HardDisk cmdlet gives us the ability to add hard drives to a VM. The -VM switch lets the cmdlet know which VM we are adding a hard disk to. The -CapacityKB switch tells the cmdlet how large of a hard drive we are creating. I’ll talk more about the -ThinProvisioned switch in another blog.
function change_ram_amount {
$ram = Read-Host "Enter amount of RAM in MB"
foreach($server in $servers)
{
Set-VM $server -MemoryMB $ram -Confirm:$false -RunAsync
}
}
function power_on_vms {
foreach ($server in $servers)
{
Start-VM $server -RunAsync
}
Write-Host "$server has been powered on"
}
clone_vms
$change_vcpu = (Read-Host "Do you want to change the vCPU count [y] or [n]").Trim()
if($change_vcpu -eq "y") {change_vcpu}
$add_harddrive = (Read-Host "Do you want to add a harddrive [y] or [n]")
if($add_Harddrive -eq "y") {add_harddrive}
$change_ram = (Read-Host "Do you want to change the amount of RAM [y] or [n]")
if($change_ram -eq "y") {change_ram_amount}
power_on_vms
I’ve pretty much gone through all of the cmdlets used, all of the switches used, etc. The last section is changing the RAM amount with the Set-VM cmdlet and then defining the function power_on_vms which does exactly what it says. The next chunk is what actually makes the script run.
Lets take line 18-19 as an example. Line 18 is asking the user whether or not they want to change the RAM amount on the virtual machines and storing the response in a variable called $change_vcpu. Line 19 is a conditional statement saying if $change_vcpu is equal to “y” then call the change_vcpu function. If the user types anything other than “y” the conditional statement is not equal and moves on to the next one which is prompting to add a hard drive. The same procedure is followed through the rest.
What I do is run a set of 10 virtual machines, specify what I need to and move on to something else. Once I see in vCenter that the virtual machines are all done being created, I check my console again to modify the vCPU, RAM and hard drive specs.