Hey folks. I have been using the script below and it works very well when doing 1 VM. When I try and do multiple VM's it does the template copy first for ALL vm's, and ends up doing customization for only the last one in the list. What I need is to know how to tweak this so that the script builds 1 VM at a time including customization and power on, then goes on to #2, 3 etc.
Thanks to Mark and Lucd for the original script
##########################################################
#
# Mark Jones 2/23/2012
# Version 3
#
##########################################################
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
$vcenter = Read-Host "Enter Vcenter Name"
$csvimport = Read-Host "Enter CSV filename (fullname with extension)"
$username = read-host "Enter your domain admin username for customization"
$pass = Read-Host -AsSecureString "Enter your password"
$adminpass = Read-Host -AsSecureString "Enter local admin password"
#convert back to string
$pass = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass)
$pass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($pass)
$adminpass = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($adminpass)
$adminpass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($adminpass)
Connect-VIServer $vcenter
$vmlist = Import-CSV $csvimport
foreach ($item in $vmlist) {
# I like to map out my variables
$basevm = $item.template
$datastore = $item.datastore
$vmhost = $item.vmhost
$custspec = $item.custspec
$vmname = $item.vmname
$ipaddr = $item.ipaddress
$subnet = $item.subnet
$gateway = $item.gateway
$pdns = $item.pdns
$sdns = $item.sdns
$vlan = $item.vlan
$location = $item.location
#Clone the templates
$tasks += (New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
}
Write-Host "Waiting for Copies to Finish"
#Wait for all taksks in tasks list before proceeding
Wait-Task -task $tasks
foreach ($item in $vmlist) {
$datastore = $item.datastore
$custspec = $item.custspec
$ipaddr = $item.ipaddress
$subnet = $item.subnet
$gateway = $item.gateway
$pdns = $item.pdns
$sdns = $item.sdns
# $vlan = $item.vlan
$hd = [int]$item.ddrive * 1024 * 1024
$hd2 = [int]$item.edrive * 1024 * 1024
$hd3 = [int]$item.fdrive * 1024 * 1024
$vmname = $item.vmname
$cpu = $item.cpu
$mem = [int]$item.mem * 1024
#set customization spec
New-OSCustomizationSpec -spec $custspec -Name $vmname -type Persistent
Set-OSCustomizationSpec -spec $vmname -AdminPassword $adminpass -DomainUsername $username -DomainPassword $pass -Confirm:$false
Get-OSCustomizationSpec $vmname | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns
#Set network label
# Get-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $vlan -Confirm:$false | Out-Null
#set vm
Set-VM -VM $vmname -OSCustomizationSpec $vmname -NumCpu $cpu -MemoryMB $mem -Confirm:$false
#Create D drive windows
if ($hd){
New-HardDisk -VM $vmname -CapacityKB $hd -ThinProvisioned:$true -Confirm:$false
}
#Create E drive windows
if ($hd2){
New-HardDisk -VM $vmname -CapacityKB $hd2 -Confirm:$false
}
#Create F drive windows
if ($hd3){
New-HardDisk -VM $vmname -CapacityKB $hd3 -Confirm:$false
}
#Remove Cust Spec
Remove-OSCustomizationSpec -CustomizationSpec $vmname -Confirm:$false
}
foreach ($item in $vmlist){
$vmname = $item.vmname
#Start VM
Start-VM -VM $vmname -Confirm:$false -RunAsync
}
Disconnect-VIServer $vcenter -Confirm:$false
Try replacing this
$tasks += (New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
with
$tasks = @(New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
The error came from the fact that there is now only 1 task generated by the New-VM, and the variable $tasks we not defined as an array in the script.
You can use the addition on an array, but not on a simple variable.
With the @(...) construct, we turn the single object into an array with 1 element.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Change the 2 ForEach loops into 1 ForEach loop.
Remove the indicated lines.
You could also drop a number of the assignments in the beginning of the 2nd loop, since you already have those variables populated at the beginning of the 1st loop
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hey Lucd,
I made those changes and it went through and made all the provisioning for the first VM then spit out this error
Method invocation failed because [VMware.VimAutomation.ViCore.Impl.V1.Task.TaskImpl] doesn't contain a method named 'op_Addition'.
At Q:\Scripts\Build\build2.ps1:42 char:14
+ $tasks += <<<< (New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
After that it did not power on the VM and went to start on VM2.
To add to this, is there a way to move the newly created VM's to a folder?
Try replacing this
$tasks += (New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
with
$tasks = @(New-VM -Name $vmname -template $basevm -Location $location -Datastore $datastore -VMHost $vmhost -RunAsync)
The error came from the fact that there is now only 1 task generated by the New-VM, and the variable $tasks we not defined as an array in the script.
You can use the addition on an array, but not on a simple variable.
With the @(...) construct, we turn the single object into an array with 1 element.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference