ESXi scripted installation PXE PowerCLI

ESXi scripted unattended installation via PXE for any build/image. PowerCLI generates all relevant files.


As part of the project Get-EsxCli on steroids, I need to install a new ESXi host for each new ESXi build.
So far, 23/04/2015, 51 ESXi build from the version 5.0 to 6.0

At this scale, an interactive installation is not an option.
Unattended installation was necessary.
Scripted installation based on PXE boot has been selected due to its simplicity…
…when combined with PowerCLI.

Home lab overview

ESXi whitebox 64 GB
Workstation with Windows 8.1 with 16GB and PowerCLI “Release 6.0 Release 1”
(All scripts in this post have only been tested with the above configuration)

VMware workstation is installed on the workstation and run the vcenter 6.0 VM.
The ESXi whitebox, host all 51 – so far – nested hypervisors.
This post is focused on the ESXi scripted installation via PXE so the script to create the nested hypervisors will be provided only at the end.

Infrastructure servers PXE/TFTP/FTP/DHCP are provided by the Windows workstation via TFTPD32.
This is working well in a lab, however in a production environment you will probably want to import files generated by PowerCLI in enterprise class infrastructure servers.
All scripts in this post are based on the assumption that the PXE server is not only dedicated for VMware.
All VMware images are stored in a subfolder “vmware”, other subfolders could be created for Linux or Windows for example.

Configuration of infrastructure servers PXE/TFTP/FTP/DHCP

An excellent article on this topic has been written by Ivo Beerens.
Create a VMware ESXi 5 PXE unattended scripted installation using Windows

My home lab is heavily inspired from his post, with some minor differences:
Windows 8.1 (was XP SP2)
TFTPD32 4.5 (was 4.0)
FileZilla server 0.9.49 (was 0.9.39)
Network 10.0.0.0/24 (was 192.168.1.0/24)

…and a major one:
51 ESXi build (was one)

Folder structure in the Windows 8.1 workstation:
C:\VMware\ISO
C:\VMware\Patches
C:\PXEBOOT\VMware (The base directory of the tftp server is still “C:\PXEBOOT” )
C:\PXEBOOT\pxelinux.cfg
C:\FTP\kickstart

Scripted creation of all ISO from VMware patches

Download all patches from VMware to the folder “C:\VMware\Patches”
Run the following script from PowerCLI

Get-ChildItem -path "C:\VMware\Patches" -Recurse -include *.zip | foreach-object{
$ESXSoftwareDepot = Add-EsxSoftwareDepot $_.fullname
get-esxImageProfile | where {$_.Name -notlike "*tools"} |foreach-object{
$IsoFullPath = "C:\VMware\ISO\" + $_.name + ".iso"
Export-esxImageProfile $_.name -ExportToIso -FilePath $IsoFullPath
}
$ESXSoftwareDepot | Remove-EsxSoftwareDepot
}

Output example:
For ESXi550-201502001.zip C:\VMware\ISO\ESXi-5.5.0-20150204001-standard.iso

Note:
The following section in the code is optional, it is used only to save some disk space.
where {$_.Name -notlike "*tools"}
In the example above it will prevent the creation of “ESXi-5.5.0-20150204001-no-tools.iso”
At the end around 80GB are used in my workstation even with the above trick.
It is also possible to add vendor customized ISO in the iso folder like for example from HP.

Scripted population of PXE folder

Eject CD, if any, from the workstation before running this script.

Get-ChildItem -path "C:\VMware\ISO" -Recurse -include *.iso  | foreach-object{
Start-Sleep -s 5
$BaseName = $_.BaseName
Write-Host "Mount Image $BaseName"
Mount-DiskImage $_.fullname
	$CDDriveLetter = "ERROR"
	get-psdrive | where {$_.Description -match "5" -or $_.Description -match "6" }| foreach-object{
	 $CDDriveLetter = $_.root
	}
Write-Host "Drive is $CDDriveLetter"
$SourcePath = $CDDriveLetter + "\*"
$DestinationPath = "C:\PXEBOOT\VMware\" + $BaseName
Write-Host "Will work on $BaseName with  the drive letter $CDDriveLetter"
	new-item $DestinationPath -type directory
	Copy-Item $SourcePath $DestinationPath
Write-Host "Will unmount $_.fullname"
Dismount-DiskImage -ImagePath $_.fullname
Write-Host "$_.fullname unmounted"
} 

Scripted fix of all BOOT.cfg

Please check first this excellent post – PXE booting a scripted ESXi 5.x Install – to undersand challenges associated to BOOT.cfg

Get-ChildItem -path "C:\PXEBOOT\VMWARE" -Recurse -include Boot.cfg | foreach-object{
$DirectoryName = $_.DirectoryName
$DirectoryFiltered = 'prefix=' + (($_.DirectoryName -replace [Regex]::Escape("C:\PXEBOOT\"),"") -replace [Regex]::Escape("\"),"/") + "/" + "`n"
$BackupPath = $DirectoryName + "\BOOT.CFG.backup"
	If(Test-Path $BackupPath){
	Write-host "The following backup already exist $BackupPath"
	}
	Else{
	Write-host "No Backup Yet, create one"
	Copy-Item $_.Fullname $BackupPath
	}
$DestinationPath = $DirectoryName + "\BOOT.CFG"	
Remove-item $DestinationPath -Force
$NewFile = [System.IO.File]::ReadAllLines($BackupPath)
$stream1 = [System.IO.StreamWriter] $DestinationPath
$NewFile = $NewFile -replace [Regex]::Escape("/"),""
$MyCounter = 0
	$NewFile | foreach-object{
		If($MyCounter -eq 2){
		$stream1.Write("$DirectoryFiltered")
		}
	$NewOutputWithTab = $_.substring(0) + "`n"
	$stream1.Write("$NewOutputWithTab")
	$MyCounter = $MyCounter + 1
	}

$stream1.Close()
$stream1 = $Null
}

This part was actually the most challenging.

Let’s play a little game.
Could you find the differences between these two pictures?
Picture1
First clue:
With the left BOOT.cfg everything is working fine
With the right BOOT.cfg…errors will be generated while booting with PXE

Second clue:
Notepad++ and “View>Show Symbol>Show All Characters”
Picture2

By default files generated with PowerShell use as carriage return “CRLF”
However the BOOT.cfg file, from the Linux world, must use as carriage return “LF”
I let you guess, how much time i have wasted in troubleshooting settings which at the end were correct from the beginning.

After spotting the issue it was still necessary to create files with “LF” instead of “CRLF”.
It is not that straightforward with PowerShell.

Scripted creation of the default PXE configuration file

All scripts are based on the assumption that a subfolder “vmware” has been created in the PXE servers.
New-ESXi_PXE_defaultconf.ps1

New-ESXi_PXE_defaultconf -DestinationFolder 'C:\PXEBOOT\pxelinux.cfg' -PXE_VMware_Folder 'C:\PXEBOOT\VMWARE'

Now if you pxeboot a server you can choose between all “ESXi image”.
This is a good starting point but we are still far from the unattended installation…

Scripted creation of the customized PXE configuration file for each host

New-ESXi_PXE_conf.ps1
With the function above you will be able to create a customized PXE configuration file which will enable a server with a specific MacAddress to pxeboot from a specific ESXi image.
Please note the kickstart/ftp section line, the relevant files will be created in the next section.
The assumption is that all kickstart files will be stored in a FTP server.

If you collect details from your physical servers you can create a csv file with the following columns.
“MacAddress” “Image” “ManagementIP”
Then it will be easy to import this file and call the function New-ESXi_PXE_defaultconf for each row.
Note: The IP will be used in the next section.

My home lab is based on nested ESXi host with one vmnic each.
I have followed a slightly different approach.

First i am using a reference csv file which looks like this.

VersionNameReleaseDateBuildToAnalysePatchImageNameIPNotes
5.0.0ESXi 5.0 GA24/08/2011469512YESVMware-VMvisor-Installer-5.0.0-469512.x86_64VMware-VMvisor-Installer-5.0.0-469512.x86_6410.0.0.100
5.0.0ESXi 5.0 Patch 113/09/2011474610YESESXi500-201109001ESXi-5.0.0-20110904001-standard10.0.0.101
5.0.0ESXi 5.0 Express Patch 103/11/2011504890YESESXi500-201111001ESXi-5.0.0-20111104001-standard10.0.0.102
5.0.0ESXi 5.0 Patch 215/12/2011515841YESESXi500-201112001ESXi-5.0.0-20111204001-standard10.0.0.103
5.0.0ESXi 5.0 Update 115/03/2012623860YESupdate-from-esxi5.0-5.0_update01ESXi-5.0.0-20120302001-standard10.0.0.104
5.0.0ESXi 5.0 Express Patch 212/04/2012653509NOESXi500-201204001ESXi-5.0.0-20120404001-standard10.0.0.105BUG
5.0.0ESXi 5.0 Express Patch 303/05/2012702118YESESXi500-201205001ESXi-5.0.0-20120504001-standard10.0.0.106
5.0.0ESXi 5.0 Express Patch 414/06/2012721882YESESXi500-201206001ESXi-5.0.0-20120604001-standard10.0.0.107
5.0.0ESXi 5.0 Patch 312/07/2012768111YESESXi500-201207001ESXi-5.0.0-20120704001-standard10.0.0.108
5.0.0ESXi 5.0 Patch 427/09/2012821926YESESXi500-201209001ESXi-5.0.0-20120904001-standard10.0.0.109
5.0.0ESXi 5.0 Update 220/12/2012914586YESupdate-from-esxi5.0-5.0_update02ESXi-5.0.0-20121202001-standard10.0.0.110
5.0.0ESXi 5.0 Patch 528/03/20131024429YESESXi500-201303001ESXi-5.0.0-20130304001-standard10.0.0.111
5.0.0ESXi 5.0 Express Patch 515/05/20131117897YESESXi500-201305001ESXi-5.0.0-20130504001-standard10.0.0.112
5.0.0ESXi 5.0 Patch 629/08/20131254542YESESXi500-201308001ESXi-5.0.0-20130804001-standard10.0.0.113
5.0.0ESXi 5.0 Update 317/10/20131311175YESupdate-from-esxi5.0-5.0_update03ESXi-5.0.0-20131002001-standard10.0.0.114
5.0.0ESXi 5.0 Patch 723/01/20141489271YESESXi500-201401001ESXi-5.0.0-20140104001-standard10.0.0.115
5.0.0ESXi 5.0 Patch 829/05/20141851670YESESXi500-201405001ESXi-5.0.0-20140504001-standard10.0.0.116
5.0.0ESXi 5.0 Express Patch 601/07/20141918656YESESXi500-201407001ESXi-5.0.0-20140704001-standard10.0.0.117
5.0.0ESXi 5.0 Patch 928/08/20142000308YESESXi500-201408001ESXi-5.0.0-20140804001-standard10.0.0.118
5.0.0ESXi 5.0 Patch 1004/12/20142312428YESESXi500-201412001ESXi-5.0.0-20141204001-standard10.0.0.119
5.0.0ESXi 5.0 Patch 1126/02/20152509828YESESXi500-201502001ESXi-5.0.0-20150204001-standard10.0.0.146
5.1.0ESXi 5.1.0 GA10/09/2012799733YESVMware-VMvisor-Installer-5.1.0-799733.x86_64VMware-VMvisor-Installer-5.1.0-799733.x86_6410.0.0.120
5.1.0ESXi 5.1.0a25/10/2012838463YESESXi510-201210001ESXi-5.1.0-20121004001-standard10.0.0.121
5.1.0ESXi 5.1 Patch 120/12/2012914609YESESXi510-201212001ESXi-5.1.0-20121204001-standard10.0.0.122
5.1.0ESXi 5.1 Express Patch 207/03/20131021289YESESXi510-201303001ESXi-5.1.0-20130304001-standard10.0.0.123
5.1.0ESXi 5.1 Update 125/04/20131065491YESupdate-from-esxi5.1-5.1_update01ESXi-5.1.0-20130402001-standard10.0.0.124
5.1.0ESXi 5.1 Express Patch 323/05/20131117900YESESXi510-201305001ESXi-5.1.0-20130504001-standard10.0.0.125
5.1.0ESXi 5.1 Patch 225/07/20131157734YESESXi510-201307001ESXi-5.1.0-20130704001-standard10.0.0.126
5.1.0ESXi 5.1 Patch 317/10/20131312873YESESXi510-201310001ESXi-5.1.0-20131004001-standard10.0.0.127
5.1.0ESXi 5.1 Update 216/01/20141483097YESupdate-from-esxi5.1-5.1_update02ESXi-5.1.0-20140102001-standard10.0.0.128
5.1.0ESXi 5.1 Express Patch 427/02/20141612806YESESXi510-201402001ESXi-5.1.0-20140204001-standard10.0.0.129
5.1.0ESXi 5.1 Patch 429/04/20141743533YESESXi510-201404001ESXi-5.1.0-20140404001-standard10.0.0.130
5.1.0ESXi 5.1 Express Patch 517/06/20141900470YESESXi510-201406001ESXi-5.1.0-20140604001-standard10.0.0.131
5.1.0ESXi 5.1 Patch 531/07/20142000251YESESXi510-201407001ESXi-5.1.0-20140704001-standard10.0.0.132
5.1.0ESXi 5.1 Patch 630/10/20142191751YESESXi510-201410001ESXi-5.1.0-20141004001-standard10.0.0.133
5.1.0ESXi 5.1 Update 304/12/20142323236YESupdate-from-esxi5.1-5.1_update03ESXi-5.1.0-20141202001-standard10.0.0.134
5.5.0ESXi 5.5 GA22/09/20131331820YESVMware-VMvisor-Installer-5.5.0-1331820.x86_64VMware-VMvisor-Installer-5.5.0-1331820.x86_6410.0.0.135
5.5.0ESXi 5.5 Patch 122/12/20131474528YESESXi550-201312001ESXi-5.5.0-20131204001-standard10.0.0.136
5.5.0ESXi 5.5 Update 111/03/20141623387YESupdate-from-esxi5.5-5.5_update01ESXi-5.5.0-20140302001-standard10.0.0.137
5.5.0ESXi 5.5 Update 1a19/04/20141746018YESESXi550-201404001ESXi-5.5.0-20140404001-standard10.0.0.138
5.5.0ESXi 5.5 Express Patch 319/04/20141746974YESESXi550-201404020ESXi-5.5.0-20140401020s-standard10.0.0.139
5.5.0ESXi 5.5 Express Patch 411/06/20141881737YESESXi550-201406001ESXi-5.5.0-20140604001-standard10.0.0.140
5.5.0ESXi 5.5 Patch 201/07/20141892794YESESXi550-201407001ESXi-5.5.0-20140704001-standard10.0.0.141
5.5.0ESXi 5.5 Update 209/09/20142068190YESupdate-from-esxi5.5-5.5_update02ESXi-5.5.0-20140902001-standard10.0.0.142
5.5.0ESXi 5.5 Patch 315/10/20142143827YESESXi550-201410001ESXi-5.5.0-20141004001-standard10.0.0.143
5.5.0ESXi 5.5 Express Patch 502/12/20142302651YESESXi550-201412001ESXi-5.5.0-20141204001-standard10.0.0.144
5.5.0ESXi 5.5 Patch 427/01/20152403361YESESXi550-201501001ESXi-5.5.0-20150104001-standard10.0.0.145
5.5.0ESXi 5.5 Express Patch 605/02/20152456374YESESXi550-201502001ESXi-5.5.0-20150204001-standard10.0.0.147
6.0.0ESXi 6.0 GA12/03/20152494585YESVMware-ESXi-6.0.0-2494585-depotESXi-6.0.0-2494585-standard10.0.0.148New
6.0.0ESXi 6.0 Express Patch 109/04/20152615704YESESXi600-201504001ESXi-6.0.0-20150404001-standard10.0.0.149New
5.5.0ESXi 5.5 Express Patch 707/04/20152638301YESESXi550-201504001ESXi-5.5.0-20150402001-standard10.0.0.150New
5.1.0ESXi 5.1 Patch 726/03/20152583090YESESXi510-201503001ESXi-5.1.0-20150304001-standard10.0.0.151New

This file has been created manually.
All IPs are outside of the DHCP scope to avoid IP conflicts.

At this stage we are only interested by the following columns.
Build
ImageName

Notes:
The ImageName is matching the name in the associated folder in “C:\PXEBOOT\VMWARE”
The naming convention for nested host VMs in this lab is “Build_VM”. For example “2615704_VM”

Connect-VIServer -Server "10.0.0.8" -User "administrator@vsphere.local" -Password "MyL@b0123"
 $ReferencePath = "C:\Temp\Reference.csv"
$ReferenceTable = Import-Csv -path $ReferencePath -useculture
$ReferenceTable | Where {$_.Notes -eq "New"} | foreach-object{
$VMname = $_.Build + "_VM"

		Get-vm -name $VMName | get-networkadapter | where {$_.Name -eq "Network adapter 1"} | foreach-object{
		$MacAddress = $_.MacAddress
		}

New-ESXi_PXE_conf -Host_macaddress $MacAddress -DestinationFolder 'C:\PXEBOOT\pxelinux.cfg' -ImageName $_.ImageName -FTPAddress "10.0.0.5" -FTPUser 'vmware' -FTPPassword 'vmware'
}

DIsconnect-VIServer -Server "10.0.0.8" -confirm:$False 

Scripted creation of the customized kikstart file for each host

Now let’s create the kickstart files mentioned in the previous section for all hosts.
They will be stored in the FTP server.

The function below will generate a kickstart file for each server.
New-ESXi_ks_conf.ps1

Similar to the previous section, you will find below how this function is used in this lab based on nested Hypervisors.
It will be quite easy to adapt the logic to another scenario.

Connect-VIServer -Server "10.0.0.8" -User "administrator@vsphere.local" -Password "MyL@b0123"

 $ReferencePath = "C:\temp\Reference.csv"
$ReferenceTable = Import-Csv -path $ReferencePath -useculture
$ReferenceTable | Where {$_.Notes -eq "New"} | foreach-object{
$VMname = $_.Build + "_VM"

		Get-vm -name $VMName | get-networkadapter | where {$_.Name -eq "Network adapter 1"} | foreach-object{
		$MacAddress = $_.MacAddress
		}
$HostName = $_.Build + "-HOST"
New-ESXi_ks_conf `
-Host_macaddress $MacAddress `
-DestinationFolder 'C:\FTP\kickstart' `
-Miscellaneous_rootpw "MyL@b01" `
-Miscellaneous_keyboard "Norwegian" `
-Miscellaneous_reboot $True `
-installorUpgrade_Mode 'install' `
-Install_diskSelection_Mode 'firstdisk' `
-Install_overwritevmfs $True `
-Network_bootproto "static" `
-Network_device "vmnic0" `
-Network_ip $_.IP `
-Network_netmask "255.255.255.0" `
-Network_gateway "10.0.0.1" `
-Network_nameserver "10.0.0.5" `
-Network_hostname $HostName 

}

DIsconnect-VIServer -Server "10.0.0.8" -confirm:$False 

Result

Start your first server and enjoy the show of a scripted installation unattended via PXE.
At the end you will get a new ESXi host, installed from the right image, with the correct management IP address.

Notes:
In my lab, with 2 or 3 servers started concurrently the installation is working fine for all of them.
Above 3 the stability is lost. The bottleneck has not been identified yet.
If you are planning to import all files generated in enterprise class infrastructure servers, maybe you will not experience this issue.

What to do next?

You already have the IP and the password of a fresh installed ESXi host.
With PowerCLI, the sky’s the limit

Some example below:
Add the new hosts to vCenter
Configure settings like NTP / syslog
Add hosts to distributed vSwitch and create new interface for VMotion
Use Get-EsxCli on steroids to configure storage claim rules, or anything available with esxcli.

Scripted creation of all nested ESXi hosts

There is nothing really new here.
Published just for the sake of completeness.
“Onyx” was used when configuring a new VM via vSphere Client to generate PowerCLI code.
A new VM has been created with vSphere Web Client based on recommendation for nested ESXi hypervisors.
Differences between the two VMs have been identified by extracting all settings via PowerCLI and API
Last step was to modify slightly the script generated with Onyx to take into account the differences.
The VM generated has only one vmnic but it is enough for a home lab.
There are probably better ways to generate VM for nested hypervisors via PowerCLI.

function CreateNestedHypervisorVM{
	param(
	$Build
	)

	process{
	$FullName = $Build + "_VM"
	If(get-vm -name $FullName){
	}
	Else{
	$config = New-Object VMware.Vim.VirtualMachineConfigSpec
	$config.name = $FullName
	$config.version = "vmx-10" ####Customized
	$config.guestId = "vmkernel5Guest" ####Customized
	$config.nestedHVEnabled = $True ####Customized
	$config.files = New-Object VMware.Vim.VirtualMachineFileInfo
	$config.files.vmPathName = "[SSD3]"
	$config.tools = New-Object VMware.Vim.ToolsConfigInfo
	$config.tools.afterPowerOn = $true
	$config.tools.afterResume = $true
	$config.tools.beforeGuestStandby = $true
	$config.tools.beforeGuestShutdown = $true
	$config.tools.beforeGuestReboot = $true
	$config.flags = New-Object VMware.Vim.VirtualMachineFlagInfo
	$config.flags.snapshotPowerOffBehavior = "powerOff"
	$config.powerOpInfo = New-Object VMware.Vim.VirtualMachineDefaultPowerOpInfo
	$config.powerOpInfo.powerOffType = "preset"
	$config.powerOpInfo.suspendType = "preset"
	$config.powerOpInfo.resetType = "preset"
	$config.powerOpInfo.standbyAction = "checkpoint" ###Customized
	$config.numCPUs = 2
	$config.numCoresPerSocket = 1
	$config.memoryMB = 4096
	$config.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (4)
	$config.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
	$config.deviceChange[0].operation = "add"
	$config.deviceChange[0].device = New-Object VMware.Vim.VirtualCdrom
	$config.deviceChange[0].device.key = -44
	$config.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualCdromRemotePassthroughBackingInfo
	$config.deviceChange[0].device.backing.deviceName = ""
	$config.deviceChange[0].device.backing.exclusive = $false
	$config.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
	$config.deviceChange[0].device.connectable.startConnected = $false
	$config.deviceChange[0].device.connectable.allowGuestControl = $true
	$config.deviceChange[0].device.connectable.connected = $false
	$config.deviceChange[0].device.controllerKey = 201
	$config.deviceChange[0].device.unitNumber = 0
	$config.deviceChange[1] = New-Object VMware.Vim.VirtualDeviceConfigSpec
	$config.deviceChange[1].operation = "add"
	$config.deviceChange[1].device = New-Object VMware.Vim.VirtualLsiLogicController
	$config.deviceChange[1].device.key = -46
	$config.deviceChange[1].device.busNumber = 0
	$config.deviceChange[1].device.sharedBus = "noSharing"
	$config.deviceChange[2] = New-Object VMware.Vim.VirtualDeviceConfigSpec
	$config.deviceChange[2].operation = "add"
	$config.deviceChange[2].device = New-Object VMware.Vim.VirtualE1000
	$config.deviceChange[2].device.key = -50
	$config.deviceChange[2].device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
	$config.deviceChange[2].device.backing.deviceName = "Console"
	$config.deviceChange[2].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
	$config.deviceChange[2].device.connectable.startConnected = $true
	$config.deviceChange[2].device.connectable.allowGuestControl = $true
	$config.deviceChange[2].device.connectable.connected = $true
	$config.deviceChange[2].device.addressType = "generated"
	$config.deviceChange[2].device.wakeOnLanEnabled = $true
	$config.deviceChange[3] = New-Object VMware.Vim.VirtualDeviceConfigSpec
	$config.deviceChange[3].operation = "add"
	$config.deviceChange[3].fileOperation = "create"
	$config.deviceChange[3].device = New-Object VMware.Vim.VirtualDisk
	$config.deviceChange[3].device.key = -1000000
	$config.deviceChange[3].device.backing = New-Object VMware.Vim.VirtualDiskFlatVer2BackingInfo
	$config.deviceChange[3].device.backing.fileName = ""
	$config.deviceChange[3].device.backing.diskMode = "persistent"
	$config.deviceChange[3].device.backing.split = $false
	$config.deviceChange[3].device.backing.writeThrough = $false
	$config.deviceChange[3].device.backing.thinProvisioned = $true
	$config.deviceChange[3].device.backing.eagerlyScrub = $false
	$config.deviceChange[3].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
	$config.deviceChange[3].device.connectable.startConnected = $true
	$config.deviceChange[3].device.connectable.allowGuestControl = $false
	$config.deviceChange[3].device.connectable.connected = $true
	$config.deviceChange[3].device.controllerKey = -46
	$config.deviceChange[3].device.unitNumber = 0
	$config.deviceChange[3].device.capacityInKB = 41943040
	$config.cpuAllocation = New-Object VMware.Vim.ResourceAllocationInfo
	$config.cpuAllocation.reservation = 0
	$config.cpuAllocation.limit = -1
	$config.cpuAllocation.shares = New-Object VMware.Vim.SharesInfo
	$config.cpuAllocation.shares.shares = 100
	$config.cpuAllocation.shares.level = "normal"
	$config.memoryAllocation = New-Object VMware.Vim.ResourceAllocationInfo
	$config.memoryAllocation.reservation = 0
	$config.memoryAllocation.limit = -1
	$config.memoryAllocation.shares = New-Object VMware.Vim.SharesInfo
	$config.memoryAllocation.shares.shares = 100
	$config.memoryAllocation.shares.level = "normal"
	$config.firmware = "bios"


	 $pool = (Get-VMHost -name "10.0.0.11" | Get-ResourcePool).ExtensionData.Moref


	 $MyFolder = (get-folder | where {$_.Name -eq "NestedHostVM"}) | get-view
	 
	 $MyFolder.CreateVM_Task($config, $pool, $null)
	 }
	 }
 }
 
 
 
 
Connect-VIServer -Server "10.0.0.8" -User "administrator@vsphere.local" -Password "MyL@b0123" 
 
 $ReferencePath = "C:\temp\Reference.csv"
$ReferenceTable = Import-Csv -path $ReferencePath -useculture
$MySuperTable = $null
$ReferenceTable | Where {$_.Notes -eq "New"} | foreach-object{
CreateNestedHypervisorVM -Build $_.Build
}

 
 DIsconnect-VIServer -Server "10.0.0.8" -confirm:$False 

2 thoughts on “ESXi scripted installation PXE PowerCLI

  1. Adam

    First of all, WOW fantastic job! Really nice scripts and good explanations, thanks.

    I came to the step where “Scripted creation of the default PXE configuration file” should generate the default configuration file in ‘C:\PXEBOOT\pxelinux.cfg’ but nothing happens when I ran your script “New-ESXi_PXE_defaultconf.ps1”, I don’t get any error message either, but no file is created.

    I have all the directories setup according to your instructions.

    C:\VMware\ISO
    C:\VMware\Patches
    C:\PXEBOOT\VMware (The base directory of the tftp server is still “C:\PXEBOOT” )
    C:\PXEBOOT\pxelinux.cfg
    C:\FTP\kickstart

    Would you know what could be wrong?

    Best Regards,

    Adam

    Reply

Leave a Reply

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