The below works when I have a single line in the CSV and successfully deploys the VM with the variables.
$BuildVar = Import-csv "D:\2019DatacenterTest.csv" -ErrorAction Stop
$BuildVar | Foreach-Object {
$IPadd = $_.IPadd
$Mask = $_.Mask
$Gateway = $_.Gateway
$DNS1 = $_.DNS1
$DNS2 = $_.DNS2
$Vlan = $_.Vlan
$Tplate = $_.Tplate
$CustOS = $_.CustOS
$Cluster = $_.Cluster
$VMserver = $_.VMserver
$OU = $_.OU
$Disk1 = $_.Disk1
$Disk2 = $_.Disk2
$WO = $_.WO
$Notes = $_.Notes
$Cores = $_.Cores
$Memory = $_.Memory
$vCenter = $_.vCenter
}
##########################################################################################################################################################
# Connect to vCenter #
##########################################################################################################################################################
#add-pssnapin vmware.vimautomation.core
Connect-VIServer $vcenter
##########################################################################################################################################################
# Configuring Customization & Deploy VM #
##########################################################################################################################################################
$datastore = Get-Cluster -Name $Cluster | Get-Datastore | Sort-Object -Property FreeSpaceGB -Descending:$true | Select-Object -First 1
$vHost = Get-Cluster $Cluster | Get-VMHost | Sort-Object -Property MemoryUsageGB -Descending:$false | Select-Object -First 1
$OSSpecs = Get-OSCustomizationSpec -Name $CustOS
$NicMapping = Get-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name
Remove-OSCustomizationNicMapping –OSCustomizationNicMapping $NicMapping -Confirm:$false
$NicMapping = Get-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name
New-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $IPadd -SubnetMask $Mask -DefaultGateway $Gateway -Dns $DNS1, $DNS2
New-VM -Name $VMserver -Template $Tplate -OSCustomizationSpec $OSSpecs -VMHost $vhost -Datastore $datastore -ErrorAction Stop
$Nic = Get-NetworkAdapter -VM $VMserver
Set-NetworkAdapter -NetworkAdapter $Nic -NetworkName $Vlan -Confirm:$false
Start-VM $VMserver
When i try to nest it with a foreach () it never creates the second or third VM's in the CSV and the frustrating part is that there are no errors.
foreach ($line in $BuildVar) {
$datastore = Get-Cluster -Name $Cluster | Get-Datastore | Sort-Object -Property FreeSpaceGB -Descending:$true | Select-Object -First 1
$vHost = Get-Cluster $Cluster | Get-VMHost | Sort-Object -Property MemoryUsageGB -Descending:$false | Select-Object -First 1
$OSSpecs = Get-OSCustomizationSpec -Name $CustOS
$NicMapping = Get-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name
Start-Sleep -Seconds 1
Remove-OSCustomizationNicMapping –OSCustomizationNicMapping $NicMapping -Confirm:$false
Start-Sleep -Seconds 1
$NicMapping = Get-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name
New-OSCustomizationNicMapping -OSCustomizationSpec $OSSpecs.Name | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $IPadd -SubnetMask $Mask -DefaultGateway $Gateway -Dns $DNS1, $DNS2
New-VM -Name $VMserver -Template $Tplate -OSCustomizationSpec $OSSpecs -VMHost $vhost -Datastore $datastore -ErrorAction Stop
$Nic = Get-NetworkAdapter -VM $VMserver
Set-NetworkAdapter -NetworkAdapter $Nic -NetworkName $Vlan -Confirm:$false
Start-VM $VMserver
}
The basic problem in your code is that you populate variables from the Import-Csv.
But since you have nothing else in that loop, you will have the values of the last row of your CSV in your variables.
That's why it works with only 1 line in the CSV, but not with multiple lines.
The layout of your code should be, in skeleton format
# Preparation
Connect-VIServer ...
# Loop through CSV
Import-CSV ... |
Foreach-Object -Process {
# Use the properties in $_ to do the cmdlets
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I would strongly advise on always taking LucD's suggestions over mine! ;-). He is a rock star!
I was attempting to deploy these in parallel with -async but i think i need to figure this out first
Part of the issue is that in your foreach($line in $BuildVar) the property values will need to be specified as $line.IPadd, $line.Mask, $line.Gateway, etc.
So your first line to get your datastore would be:
$datastore = Get-Cluster -Name $line.Cluster | Get-Datastore | Sort-Object -Property FreeSpaceGB -Descending:$true | Select-Object -First 1
In your example, you are using just the stand alone variable ($IPadd, $Mask, $Gateway, etc), so you are calling the same variables for every new line of the foreach, so only the first one is being created. The fact that one VM is created is most likely because you have already specified those variables in your session, otherwise they would be null.
You should be able to create the VMs asynchronously still, but if you want some success or failure/error notice, you will have to create tasks for each VM creation and monitor it for completion. Not terribly complex to do, but you would definitely need to expand the script a bit!
The basic problem in your code is that you populate variables from the Import-Csv.
But since you have nothing else in that loop, you will have the values of the last row of your CSV in your variables.
That's why it works with only 1 line in the CSV, but not with multiple lines.
The layout of your code should be, in skeleton format
# Preparation
Connect-VIServer ...
# Loop through CSV
Import-CSV ... |
Foreach-Object -Process {
# Use the properties in $_ to do the cmdlets
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Import-csv "D:\DatacenterTest.csv" -ErrorAction Stop |
ForEach-Object -process {
$datastore = Get-Cluster -Name $_.Cluster | Get-Datastore | Sort-Object -Property FreeSpaceGB -Descending:$true | Select-Object -First 1
$vHost = Get-Cluster $_.Cluster | Get-VMHost | Sort-Object -Property MemoryUsageGB -Descending:$false | Select-Object -First 1
$_.Disk1
$_.Vlan
$vHost.Name
$datastore.Name
}
This worked perfectly
Thank you mmcgill1, this worked as well but i'm assuming its best practice to use LucD's method.
I would strongly advise on always taking LucD's suggestions over mine! ;-). He is a rock star!
@LucD @mmcgill1 - thanks again for the help with this item. Should i create a separate post to modify the behavior of this script to be able to deploy multiple vm's concurrently?
Right now, it is working as should, but it would be much more efficient if it would be able to deploy multiple VMs at the same time.
Many thanks in advance!
Is it as simple as adding "-RunAsync" to the end of each loop?
Import-CSV ... |
Foreach-Object -Process { doing stuff } -RunAsync
Yes and no.
With RunAsync you can indeed launch multiple tasks that will run in the background.
The issue might be that you could overload your system.
That's why most of the time a max counter is defined, to specify how many of such background tasks can run in parallel.
Another issue is how to check the outcome of such background tasks.
You do want to know if they were completed successfully or not.
You will have to retrieve, when you are sure a Task is finished, the Task object and check the result.
There are many sample scripts that do just that available in this community
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference