Being a novice at creating powershellCLI scripts from scratch, I have managed to put together a script to automate the creation of virtual machines for my ESXi5.1 training lab. Some of my commands have been adapted from Luc-D's blog. A big thank you for your super blog.
I have a list of VMs which have different OS, Memory, CPU, Disk, NetworkPort, ISOPath, FloppyDrive etc.
Below is the routine i have created from having used the VMware PowerCLI help and reference along with examples from the VMware community. I would like some help with being able to optimize the code to speed up the processing because it does take quite to process, I tried using the | Out-Null but it does not seem to switch off the output. Also wanted to know how to read the parameters from a CSV file, and phase the creation of each VM by powering one after another once it has been fully configured, like remotely checking via VMTools for the existence of a file or setting on a VM before the next VM gets created sequentially - something like a vAPP configuration. I have tried the CSV but only managed to partially make it work my script is included below:
Finally, when it is time to clean up an script to check if VM is powered ON then switch OFF and delete from Inventory and Disk the VM. (I think I could manage the deletion relatively easily). Hope my request is not a big ask.
Thanks in advance.
### Connect to vSphere Host with root
$date= Get-Date
$ESXhost = Read-Host "Enter ESX Host Name or IP"
$username = Read-Host "Username"
$password = Read-Host "Password"
Connect-VIServer -Server $ESXhost -User $username -Password $password
### Create DC
$VMname = "Lab_DC"
New-VM -VMHost $ESXhost -CD -Name $VMname -MemoryMB 512 -NumCPU 1 -Version v9 -GuestId windows7Server64Guest -Floppy -Datastore LUN1 -DiskGB 15 -DiskStorageFormat Thin -Notes "$VMname AutoDeployed on $date"
Get-VM $VMname | Get-CDDrive | Set-CDDrive -ISOPath "[Host3] VMs/Lab_Local\WIN2K8R2SP1_CUST.ISO" -StartConnected $true -Confirm:$false
$DelayValue = "5000"
$vm = Get-VM $VMname | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
$vmConfigSpec.BootOptions.BootDelay = $DelayValue
$vmConfigSpec.flags = New-Object VMware.Vim.VirtualMachineFlagInfo
$vmConfigSpec.flags.enableLogging = $false
$vm.ReconfigVM_Task($vmConfigSpec)
Get-VM $VMname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName "Lab_Local" -Confirm:$False
Get-FloppyDrive -VM $VMname | Set-FloppyDrive -FloppyImagePath "[Build] Automate/BootFloppies/LAB-DC.flp" -StartConnected $true -Confirm:$false
For the most part the above successfully creates the VM but I have about 20 VMs that I need to build/delete and the only way I can do it is by adding individual set of edited commands for each VM - this is not nice to manage, so I tried to add a foreach loop to read the VM Name and Parameters for each VM from a CSV file.
The CSV File is formatted as follows:
VMName,MemoryMB,NumCpu,Version,GuestId,Datastore,DiskGB,ISOPath,NetworkName,FloppyPath
Lab_DC,512,1,v9,windows7Server64Guest,Lun1,15,[Host3] VMs/Lab_Local\WIN2K8R2SP1_CUST.ISO,Lab_Local,[Build] Automate/BootFloppies/LAN-DC.flp
Lab_VC,2048,1,v9,windows7Server64Guest,Lun2,20,[Host3] VMs/Lab_Local\WIN2K8R2SP1_CUST.ISO,Lab_Local,[Build] Automate/BootFloppies/LAN-VC.flp
I tried to add this to "test" as below but it only seems to work partially. It fails to set the ISO path, Floppy Path and Network Port correctly - couldn't figure out how to use the BootOptions correctly so I left this out.
$VMs = Import-CSV b:\automate\servers.csv -UseCulture
New-VM -VMhost Host3 -CD -Name $VM.VMName -MemoryMB $VM.MemoryMB -NumCPU $VM.NumCPU -Version $VM.Version -GuestId $VM.GuestId -Floppy -Datastore $VM.Datastore -DiskGB $VM.DiskGB -DiskStorageFormat "Thin" -Notes "$name Auto Deployed on $date"
Get-VM $VM | Get-CDDrive | Set-CDDrive -ISOPath $VM.ISOPath -StartConnected $true -Confirm:$false
Get-VM $VM | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $VM.NetworkName -Confirm:$False
Get-FloppyDrive -VM | Set-FloppyDrive -FloppyImagePath $VM.FloppyPath -StartConnected $true -Confirm:$false
Below is the output I get from the above routine.
| Name | Port User |
| ---- | ---- ---- |
| Host3 | 443 root |
WARNING: The 'Description' property of VirtualMachine type is deprecated. Use the 'Notes' property instead.
WARNING: The 'HardDisks' property of VirtualMachine type is deprecated. Use 'Get-HardDisk' cmdlet instead.
WARNING: The 'NetworkAdapters' property of VirtualMachine type is deprecated. Use 'Get-NetworkAdapter' cmdlet instead.
WARNING: The 'UsbDevices' property of VritualMachine type is deprecated. Use 'Get-UsbDevice' cmdlet instead.
WARNING: The 'CDDrives' property of VitrualMachine type is deprecated. Use 'Get-CDDrive' cmdlet instead.
WARNING: The 'FloppyDrives' property of VirtualMachine type is deprecated. Use 'Get-FloppyDrive' cmdlet instead.
WARNING: The 'Host' property of VirtualMachine type is deprecated. Use the 'VMHost' property instead.
WARNING: The 'HostId' property of VirtualMachine type is deprecated. Use the 'VMHostId' property instead.
Get-FloppyDrive : Missing an argument for parameter 'VM'. Specify a parameter of type 'VMware.VimAutomation.ViCore.Type
s.V1.Inventory.VirtualMachine[]' and try again.
At b:\Automate\Various Scripts\CreateVM.ps1:48 char:20
+ Get-FloppyDrive -VM <<<< | Set-FloppyDrive -FloppyImagePath $VM.FloppyPath -StartConnected $true -Confirm:$false
| + CategoryInfo | : InvalidArgument: (:) [Get-FloppyDrive], ParameterBindingException | |
| + FullyQualifiedErrorId : MissingArgument,VMware.VimAutomation.ViCore.Cmdlets.Commands.VirtualDevice.GetFloppyDriv |
e
Ah, my mistake, I didn't check your code.
Inside the loop the script should use the $_ variable instead of the $VM variable for the New-VM.
That $_ variable will have the line read from the CSV file.
I updated the code above. Give it another try.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Try like this
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
$vmConfigSpec.BootOptions.BootDelay = $DelayValue
$vmConfigSpec.flags = New-Object VMware.Vim.VirtualMachineFlagInfo
$vmConfigSpec.flags.enableLogging = $false
Import-CSV b:\automate\servers.csv -UseCulture | %{
$vm = New-VM -VMhost Host3 -CD -Name $_.VMName -MemoryMB $_.MemoryMB -NumCPU $_.NumCPU -Version $_.Version `
-GuestId $_.GuestId -Floppy -Datastore $_.Datastore -DiskGB $_.DiskGB -DiskStorageFormat "Thin" `
-Notes "$name Auto Deployed on $date"
Get-CDDrive -VM $vm | Set-CDDrive -ISOPath $VM.ISOPath -StartConnected $true -Confirm:$false
Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $VM.NetworkName -Confirm:$False
Get-FloppyDrive -VM $vm | Set-FloppyDrive -FloppyImagePath $VM.FloppyPath -StartConnected $true -Confirm:$false
$vm.ExtensionData.ReconfigVM_Task($vmConfigSpec)
}
I assumed that the bootoptions would be the same for each VM you are creating.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD, thank you for your super fast response. Yes, the Boot Option parameters are the same for all VMs.
I tried what you suggested, but seem to be getting error with the basic command, I think my CSV script didn't actually work properly, I must have got confused with another script that I tried to put together which worked but it only read the VM Name. I checked again and found the command could not read the VM name from the CSV file. Any ideas where I am going wrong with my command parameters.
$vm = New-VM -VMhost Host3 -CD -Name $VM.VMName -MemoryMB $VM.MemoryMB -NumCPU $VM.NumCPU -Version $VM.Version `
-GuestId $VM.GuestId -Floppy -Datastore $VM.Datastore -DiskGB $VM.DiskGB -DiskStorageFormat "Thin" `
-Notes "$name Auto Deployed on $date"
Get-CDDrive -VM $vm | Set-CDDrive -ISOPath $vm.ISOPath -StartConnected $true -Confirm:$false
Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $vm.NetworkName -Confirm:$False
Get-FloppyDrive -VM $vm | Set-FloppyDrive -FloppyImagePath $vm.FloppyPath -StartConnected $true -Confirm:$false
It seems there is a problem because the -Name value is not being read from the CSV file.
My test CSV file has the below fields:
VMName,MemoryMB,NumCpu,Version,GuestId,Datastore,DiskGB,ISOPath,NetworkName,FloppyPath
Lab_DC,512,1,v9,windows7Server64Guest,Lun1,15,[Host3] VMs/Lab_Local\WIN2K8R2SP1_CUST.ISO,Lab_Local,[Build] Automate/BootFloppies/LAN-DC.flp
Error:
New-VM : Cannot validate argument on parameter 'Name'. The argument is null or empty. Supply an argument that is not nu
ll or empty and then try the command again.
At B:\Automate\NewVMs.ps1:19 char:45
+ $vm = New-VM -VMhost Host3 -CD -Name <<<< $vm.VMName -MemoryMB $vm.MemoryMB -NumCPU $vm.NumCPU -Version $vm.
Version -GuestId $vm.GuestId -Floppy -Datastore $vm.Datastore -DiskGB $vm.DiskGB -DiskStorageFormat "Thin" -Notes "$nam
e Auto Deployed on $date"
+ CategoryInfo : InvalidData: (:) [New-VM], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewVM
Ah, my mistake, I didn't check your code.
Inside the loop the script should use the $_ variable instead of the $VM variable for the New-VM.
That $_ variable will have the line read from the CSV file.
I updated the code above. Give it another try.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
The $_variable did fix the issue and now it works perfectly. It was a nice little exercise for me in PowerCLI and a very big thanks for your assistance. I had been trying to use various different examples from this community and blogs including yours but just couldn't get it right. Just one question how do i turn off the script output because it is slowing down the processing?
My next goal is to adapt this routine with being able to use snapshots of a different VMs and creating either linked clones or full clones (options read from the same CSV file). In its present utilization I build a lab consisting of Domain Controller, vCenter (unattended silent installs) followed by different VMs etc, but what I would like to be able to do is add a POWER ON command for DC (first VM) which is straightforward but add a WAIT state which queries something like the VMTOOLS heartbeat from the DC to indicate that is now fully built before next VM the vCenter server gets created and POWER ON state is applied.
Any code examples would be greatly appreciated.
Message was edited by: Mayur J Patel Updated and corrected grammar mistakes
You can redirect output by a redirect (>) or by piping the output of a cmdlet to null ( ...| Out-Null).
Have a look at Creating a linked clone from a snapshot point in PowerCLI
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
