Interactive Script for Creating VM’s using PowerCLI

Applies to VMware, PowerCLI, Virtual Machines
Modules needed: vmware.powercli

As someone who works in a VMware environment, and likes the command line, PowerCLI is a lifesaver. Are you mad about the phasing-out of vSphere, forcing everyone to use the web-based vCenter manager? PowerCLI is the best way to get around it. I’ve been doing my research making sure I can do everything in PowerShell that I can in vSphere/vCenter. One of the most common tasks being creating virtual machines.

Before we get started, there are a few things you are going to need. First of all, you need a vCenter host. Got it? Great. Next, you need the module PowerCLI. This can be easily installed by typing install-module vmware.powercli.

In my current environment, we are utilizing Templates, Customization Specifications, and Tags.

  • Templates are pretty simple to make, since you can just convert a running VM to one. This is a good place to start.
  • In a future post, I’ll explain how to create Customization Specs using PowerCLI as well. Currently, I’m using OS Customization specs to set the network adapters, and join the machine to the domain.
  • Lastly, we use Tags to set when the VM will be backed up using Veeam.

Since there’s a good amount of code going into this, I’ve commented through the script to show you what’s happening. It goes like this:

# Static settings, based on your environment.

$server = # The name of the vCenter Server you are connected to.
$KnownGoodSpec = # This variable asks for an OS Customization, created in vCenter. Use get-oscustomizationspec to see what you have available.
$SubnetMask = # Subnet, DNS, and Gateway are assumed to be static, if you are using this script on the same network every time.
$dnsServers =
$DefaultGateway =
$Template = # This variable asks for a template, created in vCenter. Use get-template to see what you have available.

# Begin
Write-Host "Create a VM" -ForegroundColor Yellow

# Gets the new VM name. In my OSCustomization, this also gets set to the hostname of the machine.
$vmname = Read-Host "VM Name"

# Displays available Hosts, in order of least utilized to most.
$gvmh = Get-VMHost | Sort-Object -Property CpuUsageMhz | Format-Table -AutoSize | Out-String
Write-Host $gvmh
$vmhost = Read-Host "Host"

# Displays available Datastores, in order of most free space to least.
$lds = Get-Datastore | Sort-Object -Property FreeSpaceGB -Descending | Out-String
Write-Host $lds
$datastore = Read-Host "Datastore"

# The "Backup Scheme" section is based on VM Tags, which correlate to Backup Schedules in Veeam
# If you don't utilize this in your environment, you may want to remove the next block of code, and the "Get-VM -Name $vmname | New-TagAssignment -Tag $tag" at the end of the script.
$gtag = Get-Tag | Where-Object -Property Category -Like "Backup Scheme" | Format-Table -AutoSize | Out-String
Write-Host $gtag
$backupTag = Read-Host "Tag Name"
$backupCat = Read-Host "Tag Category"
$tag = Get-Tag -Name $backupTag -Category $backupCat

# Displays all Folders.
$gf = Get-Folder | Format-Table -Property Id,Name,parent -AutoSize | Out-String
Write-Host $gf
$folderID = Read-Host "Folder Id"
$folder = Get-Folder -Id $FolderID


# Collects VM Specs.
$spec1 = Write-Host "VM Specs:" -ForegroundColor Yellow
$spec2 = Write-Host "---------------"
$cpu = Read-Host "Number of CPUs"
$core = Read-Host "Cores per CPU"
$ram = Read-Host "Memory (GB)"

# The IP address is added to the OSCustomizationspec, using the OSCusomtizationNicMapping cmdlet.
$ip = Read-Host "IP Address"

# Gets additional Disks, and stores them in an array, such that the size and format correlate when being added to the VM.
$disk = @()
do {
	[int]$count = 0
	while ($count -lt 1) {
		Write-Host "Would you like to attach additional disks?"
		Write-Host "1) Yes"
		Write-Host "2) No"
		$selection = Read-Host "Select"
		$hdisks = New-Object system.object
		switch ($selection) {
			'1' {
				$hdsize = Read-Host "Hard disk size (GB)"
				$hdisks | Add-Member -Type NoteProperty -Name Size -Value $hdsize
				$disk += $hdisks
				Write-Host "Storage Format"
				Write-Host "1) Thin Provisioned"
				Write-Host "2) Thick Provisioned"
				$hdprovswitch = Read-Host "Select"
				switch ($hdprovswitch) {
					'1' { $hdprov = "Thin"
						$hdisks | Add-Member -Type NoteProperty -Name Provision -Value $hdprov }
					'2' { $hdprov = "Thick"
						$hdisks | Add-Member -Type NoteProperty -Name Provision -Value $hdprov }
				Write-Host "Disk added." -ForegroundColor Green
			'2' { $count = 1 }
} until ($count -gt 0)


# Displays Confirmation Sheet.
$conf0 = Write-Host "----------------------------------------"
$conf1 = Write-Host "Confirmation:" -ForegroundColor Yellow
$conf2 = Write-Host "----------------------------------------
VM Name: $vmname
Host: $vmhost
Datastore: $datastore
Backup Scheme: $backup
Location: $Folder

Number of CPUs: $cpu
Cores per CPU: $core
Memory (GB): $ram

IP Address: $ip


# If you did not add additional disks, "None" is shown.
if ($disk.count -eq 0) { Write-Host "Additional Disks: None" }

# Otherwise, it will list the disks added, their size, and Storage Format.
else { Write-Host "Additional Disks:" }
$n = 1
foreach ($d in $disk) { Write-Host
	Write-Host "Disk $n"
	Write-Host "---------"
	Write-Host "Size:" $d.Size "GB"
	Write-Host $d.Provision "Provisioned"
	$n = $n + 1 }
Write-Host "----------------------------------------

# Script pauses before executing anything for the VM. This is where you would Cancel if changes need to be made.
Write-Host "Creating VM..." -ForegroundColor green

# Script grabs the OSCustomizationSpec defined at the beginning of the script, and makes a temporary copy of it with the VM in the name.
$oscust = New-OSCustomizationSpec -OSCustomizationSpec $KnownGoodSpec -Name "Temp-$vmname"

# Script then gets the Nic settings of the copy, and replaces them with the info you supplied at the beginning of the script.
Get-OSCustomizationSpec $oscust | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $ip -SubnetMask $SubnetMask -Dns $dnsServers -DefaultGateway $DefaultGateway -Position 1

# Saves all changes to the variable that gets used.
$useCust = Get-OSCustomizationSpec -Name "Temp-$vmname"

# Creates the VM, Sets the specifications entered, starts the VM, and opens a remote console Window.
New-VM -Template $Template -Name $vmname -Server $server -VmHost $vmhost -Datastore $datastore -Location $folder -OSCustomizationSpec $useCust | Set-VM -NumCpu $cpu -CoresPerSocket $core -MemoryGB $ram -Confirm:$false | Start-VM | Open-VMConsoleWindow

# Adds the additional disks.
foreach ($d in $disk) { New-HardDisk -VM $vmname -CapacityGB $d.Size -StorageFormat $d.Provision }

# Sets the tag assignment for Backup Scheduling. Remove the following line if you are not utilizing tags for Backup Scheduling.
Get-VM -Name $vmname | New-TagAssignment -Tag $tag

# Removes the temporary OSCustomizationspec created earlier.
Remove-OSCustomizationSpec -OSCustomizationSpec "Temp-$vmname" -Confirm:$false -ErrorAction Ignore

There you have it. When all the information is entered, you should get a confirmation sheet that looks like this:

Of course, creating VM’s in vSphere doesn’t take all that much time. But when you start adding the Customization Specs, Additional Disks, Tags- there’s a good chunk of your life spent clicking.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s