AutoLab automation uncovered, PowerShell

It’s Alastair here with the latest AutoLab automation post, this one is a little about the PowerShell automation that helps bring the pieces together. The first AutoLab automation post is here, the second here and the third here.

One of my favourite automation tools for vSphere is the PowerCLI snapin to Microsoft PowerShell. If you are a Windows guy working in Virtualization then you should get to know PowerCLI.  I consider myself a real beginner with PowerCLI, I use it when I have a task to repeat but it’s not where I work all day.  There are some awesome scripters who are more comfortable on a command prompt than with a GUI, these are the guys whose scripts I have hacked to make my script and you can start by doing the same.  If you are a skilled scripter you may despair at my scripts, feel free to email me to recommend better ways.

The PowerShell scripts in the AutoLab all start in the Automate folder on the build share; from there they are copied to the VM as it’s built. Copying the scripts locally helps avoid PowerShell prompting about running from an untrusted location.

I use a library script to keep a collection of function definitions that I reuse; it’s also a good way to keep your main script clean. Close to the top of most of the AutoLab PowerShell scripts is:

. "C:\PSFunctions.ps1"

A lot of the scripts also need to use the PowerCLI snapin, I choose to explicitly load this in the script as it takes a while and I show messages about the delay before loading

Add-PSSnapin VMware.VimAutomation.Core

The other things is to use a lot of variables rather than typing the same text repeatedly, sometimes even build the variables from other variables in the script

    $VMHost = "host"

    $VMHost += $i

    $VMHost += ".lab.local"


The main script that sets up vCenter is the AddHosts.ps1 script which is run on the vCenter VM.  The script is setup specifically for the AutoLab; it hasn’t been written to be re-usable elsewhere but can be the source of inspiration for your scripts.  There are a few segments that are conditional; some depend on what version of ESX I find others depend on whether datastores and VMs exist.  I’ve left these out of the following sections as they are very AutoLab specific, below are some of the main sections of the AddHosts script

vCenter configuration

Create a Datacenter

New-DataCenter -Location (Get-Folder -NoRecursion) -Name Lab

Create a DRS Cluster inside the Datacenter we just created

New-Cluster Local -DRSEnabled -Location Lab -DRSAutomationLevel PartiallyAutomated

Enable HA, set Admission control and isolation addresses on the cluster

set-cluster -cluster $Cluster -HAEnabled:$True -HAAdmissionControlEnabled:$True -confirm:$False

New-AdvancedSetting -Entity $cluster -Type ClusterHA -Name ‘das.isolationaddress1’ -Value "" -confirm:$False -force

New-AdvancedSetting -Entity $cluster -Type ClusterHA -Name ‘das.usedefaultisolationaddress’ -Value false -confirm:$False -force

$spec = New-Object VMware.Vim.ClusterConfigSpecEx

$spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo

$spec.dasConfig.admissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy

$spec.dasConfig.admissionControlPolicy.cpuFailoverResourcesPercent = 50

$spec.dasConfig.admissionControlPolicy.memoryFailoverResourcesPercent = 50

$Cluster = Get-View $Cluster

$Cluster.ReconfigureComputeResource_Task($spec, $true)

Create a Guest OS Customization configuration that we can use later

New-OsCustomizationSpec -Name Windows -OSType Windows -FullName Lab -OrgName Lab.local -NamingScheme VM -ProductKey $ProdKey -LicenseMode PerSeat -AdminPass VMware1! -Workgroup Workgroup -ChangeSid -AutoLogonCount 999

ESXi server configuration

These steps are repeated for each ESXi server, this is where having systematic naming and IP addressing is great since we can use a formula to calculate names  and IP addresses.

Setup NTP

Add-VmHostNtpServer -NtpServer “” -VMHost $VMhost

$ntp = Get-VMHostService -VMHost $VMhost | Where {$_.Key -eq ‘ntpd’}

Set-VMHostService $ntp -Policy "On"    

Enable local and remote shells

$SSH = Get-VMHostService -VMHost $VMhost | Where {$_.Key -eq ‘TSM-SSH’}

Set-VMHostService $SSH -Policy "On"

$TSM = Get-VMHostService -VMHost $VMhost | Where {$_.Key -eq ‘TSM’}

Set-VMHostService $TSM -Policy "On"

Create a vSwitch and portgroups for VMs

$switch = New-VirtualSwitch -VMhost $vmHost -Nic $pnic.DeviceName -NumPorts 128 -Name vSwitch1

New-VirtualPortGroup -Name Servers -VirtualSwitch $switch

New-VirtualPortGroup -Name Workstations -VirtualSwitch $switch

set-VirtualSwitch $switch -Nic vmnic2,vmnic3 -confirm:$False

Attach NICs to vSwitch0

$switch = Get-VirtualSwitch -vmHost $vmHost

set-VirtualSwitch $switch -Nic vmnic0,vmnic1 -confirm:$False

Create VMkernel ports and set NIC teaming for some of them

$pg = New-VirtualPortGroup -Name vMotion -VirtualSwitch $switch -VLanId 16

New-VMHostNetworkAdapter -VMHost $vmhost -Portgroup $pg -VirtualSwitch $switch -IP $VMotionIP -SubnetMask "" -vMotionEnabled:$true -managementTrafficEnabled:$True

$pg = New-VirtualPortGroup -Name FT -VirtualSwitch $switch -VLanId 16

New-VMHostNetworkAdapter -VMHost $vmhost -Portgroup $pg -VirtualSwitch $switch -IP $FTIP -SubnetMask "" -FaultToleranceLoggingEnabled:$true

$pg = New-VirtualPortGroup -Name IPStore1 -VirtualSwitch $switch -VLanId 17

New-VMHostNetworkAdapter -VMHost $vmhost -Portgroup $pg -VirtualSwitch $switch -IP $IPStoreIP1 -SubnetMask ""

$pg = New-VirtualPortGroup -Name IPStore2 -VirtualSwitch $switch -VLanId 17

New-VMHostNetworkAdapter -VMHost $vmhost -Portgroup $pg -VirtualSwitch $switch -IP $IPStoreIP2 -SubnetMask ""

Get-VMHostStorage $VMHost | Set-VMHostStorage -SoftwareIScsiEnabled $true

get-virtualportgroup -name vMotion | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive vmnic1

get-virtualportgroup -name vMotion | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicStandby vmnic0

Rename the local Datastore, Get-ShareableDatastore is declared in the psfunctions library

$DSName = $VMHost.split(‘.’)[0]

$DSName += "_Local"

$sharableIds = Get-ShareableDatastore | Foreach { $_.ID }

Get-Datastore -vmhost $vmhost | Where { $sharableIds -notcontains $_.ID } | Set-DataStore -Name $DSName

Create NFS datastore

New-Datastore -nfs -VMhost $vmhost -Name Build -NFSHost "" -Path "/mnt/LABVOL/Build" -readonly

Setup software ISCSI

$MyIQN = "" + $VMHost.split(‘.’)[0]

Get-VMHostHba -VMhost $vmhost -Type iScsi | Set-VMHostHBA -IScsiName $MyIQN

Get-VMHostHba -VMhost $vmhost -Type iScsi | New-IScsiHbaTarget -Address -Type Send

Get-VMHostStorage $VMHost -RescanAllHba

Shared configuration

Create iSCSI datastores

$iSCSILUNs = get-scsilun -vmhost $VMHost -CanonicalName "t10.*"

New-Datastore -VMHost $VMHost -Name iSCSI1 -Path $iSCSILUNs[2].CanonicalName -Vmfs -FileSystemVersion 5

New-Datastore -VMHost $VMHost -Name iSCSI2 -Path $iSCSILUNs[1].CanonicalName -Vmfs -FileSystemVersion 3

New-Datastore -VMHost $VMHost -Name iSCSI3 -Path $iSCSILUNs[0].CanonicalName -Vmfs -FileSystemVersion 3

Create the unattended configuration floppy with a customised winnt.sif containing your windows product key

(Get-Content b:\Automate\VC\Floppy\winnt.sif) | Foreach-Object {$_ -replace "xxxxx-xxxxx-xxxxx-xxxxx-xxxxx", $ProdKey} | Set-Content b:\Automate\VC\Floppy\winnt.sif

b:\automate\vc\bfi.exe -f=b:\WinInstall.flp b:\automate\vc\floppy\ -t=6

Create a new VM and set it up to automaticlly install Windows from the Build share


$Datastore = Get-Datastore -VMhost $vmHost -name "iSCSI1"

$MyVM = New-VM -Name $VMName -VMhost $vmHost -datastore $Datastore -NumCPU 1 -MemoryMB 384 -DiskMB 3072 -DiskStorageFormat Thin -GuestID winNetEnterpriseGuest

New-CDDrive -VM $MyVM -ISOPath [Build]WinInstall.iso -StartConnected

New-FloppyDrive -VM $MyVM -FloppyImagePath [Build]WinInstall.flp -StartConnected

$intHDiskDeviceKey = ($MyVM.ExtensionData.Config.Hardware.Device | ?{$_.DeviceInfo.Label -eq "Hard disk 1"}).Key

$oBootableHDisk = New-Object -TypeName VMware.Vim.VirtualMachineBootOptionsBootableDiskDevice -Property @{"DeviceKey" = $intHDiskDeviceKey}

$oBootableCDRom = New-Object -Type VMware.Vim.VirtualMachineBootOptionsBootableCdromDevice

$spec = New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{"BootOptions" = New-Object VMware.Vim.VirtualMachineBootOptions -Property @{BootOrder = $oBootableCDRom, $oBootableHDisk}}


Start-VM $MyVM


Don’t be afraid of PowerShell, it’s easy to get started with and there are a heap of sample scripts that you can bend to your will. 


1 thought on “AutoLab automation uncovered, PowerShell

Comments are closed.