VMware Cloud Community
markdjones82
Expert
Expert

VM Deployment with customization, parallel

All,

  I am using a modified script I found on Jase's blog, (Thanks!) and it appears to be working great, but my big problem is it does one at a time.  I would like them to go in parallel. Is there anyway to do this?  I have tried to add the -RunAsync option on my new-vm command, but then I get errors. Without the runasync command it works group see errors below the script.

##########################################################
# cloneandsetip.ps1

##########################################################
Connect-VIServer vcentername.name.com

$vmlist = Import-CSV vms.csv

foreach ($item in $vmlist) {

    # I like to map out my variables
    $basevm = $item.basevm
    $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

    #Get the Specification and set the Nic Mapping
    Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns
   
    #Clone the BaseVM with the adjusted Customization Specification
   New-VM -Name $vmname -template $basevm -Datastore $datastore -VMHost $vmhost -RunAsync | Set-VM -OSCustomizationSpec $custspec -Confirm:$false

    #Set the Network Name (I often match PortGroup names with the VLAN name)
    Get-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $vlan -Confirm:$false

    #Remove the NicMapping (Don't like to leave things unkept)
    Remove-OSCustomizationNicMapping -OSCustomizationNicMapping (Get-OSCustomizationSpec Test | Get-OSCustomizationNicMapping) -Confirm:$false

Errors that occur:

Set-VM : The input object cannot be bound to any parameters for the command eit
her because the command does not take pipeline input or the input and its prope
rties do not match any of the parameters that take pipeline input.
At U:\powercli\deployvm.ps1:30 char:100
+     New-VM -Name $vmname -template $basevm -Datastore $datastore -VMHost $vmh
ost -RunAsync | Set-VM <<<<  -OSCustomizationSpec $custspec -Confirm:$false
    + CategoryInfo          : InvalidArgument: (CloneVM_Task:PSObject) [Set-VM
   ], ParameterBindingException
    + FullyQualifiedErrorId : InputObjectNotBound,VMware.VimAutomation.ViCore.
   Cmdlets.Commands.SetVM

Get-OSCustomizationSpec : 2/17/2012 12:59:16 PM    Get-OSCustomizationSpec
   Could not find Customization Specification with name 'Test'.
At U:\powercli\deployvm.ps1:36 char:89
+     Remove-OSCustomizationNicMapping -OSCustomizationNicMapping (Get-OSCustom
izationSpec <<<<  Test | Get-OSCustomizationNicMapping) -Confirm:$false
    + CategoryInfo          : ObjectNotFound: (Test:String) [Get-OSCustomizati
   onSpec], VimException
    + FullyQualifiedErrorId : Common_CommonUtil_FilterCollection_ObjectNotFoun
   d,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetOSCustomizationSpec

Remove-OSCustomizationNicMapping : Cannot bind argument to parameter 'OSCustomi
zationNicMapping' because it is null.
At U:\powercli\deployvm.ps1:36 char:64
+     Remove-OSCustomizationNicMapping -OSCustomizationNicMapping <<<<  (Get-OS
CustomizationSpec Test | Get-OSCustomizationNicMapping) -Confirm:$false
    + CategoryInfo          : InvalidData: (:) [Remove-OSCustomizationNicMappi
   ng], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,V

http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
72 Replies
BrianLBLESD
Contributor
Contributor

I finally got a machine to auto-join, with a custspec, where I used lowercase domain.windows.local instead of DOMAIN.WINDOWS.LOCAL

0 Kudos
LucD
Leadership
Leadership

Strange, domain names are not case sensitive afaik.

But great that you got it working :smileycool:


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
BrianLBLESD
Contributor
Contributor

The script in this thread doesn't work for me with this AD domain, I don't know why. 

0 Kudos
markdjones82
Expert
Expert

Here is one of my updated scripts, it changes the method a little and also doesn't create persistent customization specs.  I also have different versions for deploying to a DRS cluster and also to a Storage DRS cluster if interested.  Just hit me up on PM

##########################################################
#
#
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
   
$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
    }
   
#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
http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
BrianLBLESD
Contributor
Contributor

Mark,

I've tried this in 2 different AD domains, I am using just a username, not a username@windows.domain or WINDOWS\username in the custspec, or in the script input.

I have tried upper and lower case FQDN windows domains in the custspec.

The script will execute without error, it just doesn't set the IPs, or do anything else, it will create the custspec per VM and I am not removing them, and am able to execute a new-vm call using that custspec and sometimes it works, sometimes it doesn't.

Thanks for your help.  I would have probably been done with it if I wasn't trying to automate it.

0 Kudos
markdjones82
Expert
Expert

Can you create a new customization spec and make sure that domain join is selected and try from a fresh customization spec?  I am pretty stumped at this point.

Untitled.jpg

http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
0 Kudos
Techonium
Contributor
Contributor

Mark,

You mention a version of this script that handles StorageDRS. I'd appreciate a copy of that one. Don't have enough points to PM you.

Thanks

Shane

0 Kudos
markdjones82
Expert
Expert

This one works with standard switch and i will post the one that works with VDS next. I also attached a screen of the  headers for csv

screen.png

##########################################################
#
# Mark Jones 3/25/2013
# Version 4
#
##########################################################
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
$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

#Define Tasks Array
$tasks = @()

foreach ($item in $vmlist) {

   
   
$basevm = $item.template
   
$datastore = $item.datastore
   
$cluster = $item.cluster
   
$custspec = $item.custspec
   
$vmname = $item.vmname
   
$ipaddr = $item.ipaddress
   
$subnet = $item.subnet
   
$gateway = $item.gateway
   
$pdns = $item.pdns
   
$sdns = $item.sdns
   
$vlan = $item.vlan
   
$hd = [int]$item.ddrive * 1024 * 1024
   
$vmname = $item.vmname
   
$cpu = $item.cpu
   
$mem = [int]$item.mem * 1024
   
$vds= $item.vsm

 
#set customization spec
  New-OSCustomizationSpec -OSCustomizationSpec $custspec -Name $vmname -type NonPersistent | Out-Null
 
Set-OSCustomizationSpec -OSCustomizationSpec $vmname -AdminPassword $adminpass -DomainUsername $username -DomainPassword $pass -Confirm:$false | Out-Null
 
Get-OSCustomizationSpec $vmname | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns | Out-Null
 
$OsCustomization = Get-OSCustomizationSpec $vmname
     
 
#Clone the templates and add to tasks list.  It will spin all up at the same time
  $tasks += (New-VM -Name $vmname -OSCustomizationSpec $OScustomization -template $basevm -Datastore $datastore -ResourcePool $cluster -RunAsync)

}

Write-Host "Waiting for Copies to Finish"

#Wait for all taksks in tasks list before proceeding
Wait-Task -task $tasks

#Set network Label and add harddrives by looping through list and doing one at a time
foreach ($item in $vmlist) {
   
$vmname = $item.vmname
   
$vlan = $item.vlan
   
$hd = [int]$item.ddrive * 1024 * 1024
   
$cpu = $item.cpu
   
$mem = [int]$item.mem * 1024
   
$vlan= $item.vlan

       
   
#Set network label
    Get-VM -Name $vmname | Get-NetworkAdapter -Name "Network adapter 1" | Set-NetworkAdapter -NetworkName $vlan -Confirm:$false
   
   
#set vm
    Set-VM -VM $vmname -NumCpu $cpu -MemoryMB $mem -Confirm:$false
   
   
#Create D drive windows
    if ($hd){
   
New-HardDisk -VM $vmname -CapacityKB $hd -StorageFormat Thin -Confirm:$false
    }
       
}

#Loop through list and power all VM's on simultaneously
foreach ($item in $vmlist){
$vmname = $item.vmname
#Start VM
    Start-VM -VM $vmname -Confirm:$false -RunAsync
}

Disconnect-VIServer $vcenter -confirm:$false
http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
markdjones82
Expert
Expert

Here is the VDS one. These also use thin disks if you don't want to use those you may need to modify

screen.png

##########################################################
#
# Mark Jones 3/25/2013
# Version 4
#
##########################################################
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false |Out-Null
$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

#Define Tasks Array
$tasks = @()

foreach ($item in $vmlist) {

   
   
$basevm = $item.template
   
$datastore = $item.datastore
   
$cluster = $item.cluster
   
$custspec = $item.custspec
   
$vmname = $item.vmname
   
$ipaddr = $item.ipaddress
   
$subnet = $item.subnet
   
$gateway = $item.gateway
   
$pdns = $item.pdns
   
$sdns = $item.sdns
   
$vlan = $item.vlan
   
$hd = [int]$item.ddrive * 1024 * 1024
   
$vmname = $item.vmname
   
$cpu = $item.cpu
   
$mem = [int]$item.mem * 1024
   
$vds= $item.vds

  
#set customization spec
   New-OSCustomizationSpec -Name $vmname -FullName BHCS -OSType Windows -OrgName BHCS -NamingScheme Vm -ChangeSid -AdminPassword $adminpass -DomainUsername $username -DomainPassword $pass -Domain bhcs.pvt -TimeZone 020 -type NonPersistent | Out-Null
  
Get-OSCustomizationSpec $vmname | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns | Out-Null
  
$OsCustomization = Get-OSCustomizationSpec $vmname
      
  
#Clone the templates and add to tasks list.  It will spin all up at the same time
   $tasks += (New-VM -Name $vmname -OSCustomizationSpec $OScustomization -template $basevm -Datastore $datastore -ResourcePool $cluster -RunAsync)

}

Write-Host "Waiting for Copies to Finish"

#Wait for all taksks in tasks list before proceeding
Wait-Task -task $tasks

#Set network Label and add harddrives by looping through list and doing one at a time
foreach ($item in $vmlist) {
   
$vmname = $item.vmname
   
$vlan = $item.vlan
   
$hd = [int]$item.ddrive * 1024 * 1024
   
$cpu = $item.cpu
   
$mem = [int]$item.mem * 1024
   
$vds= $item.vds

        
   
#Set network label
    $vdportgroup = Get-VDPortgroup -Name $vlan -VDSwitch $vds
   
Get-VM -Name $vmname | Get-NetworkAdapter -Name "Network adapter 1" | Set-NetworkAdapter -Portgroup $vdportgroup -Confirm:$false
   
   
#set vm
    Set-VM -VM $vmname -NumCpu $cpu -MemoryMB $mem -Confirm:$false
   
   
#Create D drive windows
    if ($hd){
   
New-HardDisk -VM $vmname -CapacityKB $hd -StorageFormat Thin -Confirm:$false
    }
       
}

#Loop through list and power all VM's on simultaneously
foreach ($item in $vmlist){
$vmname = $item.vmname
#Start VM
    Start-VM -VM $vmname -Confirm:$false -RunAsync
}

Disconnect-VIServer $vcenter -confirm:$false
http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
scottvmwarejim
Contributor
Contributor

Mark and Lucd


Thanks for the great write ups, I got my script to work after hours in vsphere 5.1. I tried the same script in vsphere 5.5 and it failed while trying to copy the customization script. I Really like the code you guys have as it lets the build multithread and build a bunch of vms at the same time. Also waits for them to complete. Is there some code that can replace the code below to work with 5.5? I think I read somewhere that 5.1 stores the customization spec in a file and 5.5 saves it in a database.

The error I get is no customization file found.


#set customization spec
  New-OSCustomizationSpec -OSCustomizationSpec $custspec -Name $vmname -type NonPersistent | Out-Null


the above line works fine in vsphere 5.5 in 5.1 I get

Could not fine oscustomizationspec with name 'the actual existing os name'


 
Set-OSCustomizationSpec -OSCustomizationSpec $vmname -AdminPassword $adminpass -DomainUsername $username -DomainPassword $pass -Confirm:$false | Out-Null
 
Get-OSCustomizationSpec $vmname | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns | Out-Null
 
$OsCustomization = Get-OSCustomizationSpec $vmname
     
 
#Clone the templates and add to tasks list.  It will spin all up at the same time
  $tasks += (New-VM -Name $vmname -OSCustomizationSpec $OScustomization -template $basevm -Datastore $datastore -ResourcePool $cluster -RunAsync)



0 Kudos
scottvmwarejim
Contributor
Contributor

Did some more googling, does vsphere 5.5. Require that you have the osc spec file stored locally as a xml file! form

it to be read, unlike vsphere 5.1 ?

I Have the osc sec in vcenter only right now.

0 Kudos
LucD
Leadership
Leadership

No, that is not a requirement in vSphere 5.5


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
markdjones82
Expert
Expert

I have not tested the script with 5.5 yet.  I'll try to test it today if I get a minute if not it may have to be tomorrow due to my workload, but it should work just the same between the 2 I would think.

http://www.twitter.com/markdjones82 | http://nutzandbolts.wordpress.com
0 Kudos