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
LucD
Leadership
Leadership

No,n0, the parameter CapacityKB wants the size in KB.

So you should do

$size = 40 * (1GB/1KB)

or

$size = 40 * 1MB

To select a specific disk you can use a Where-clause.

For example

$hd = Get-Harddisk | where{$_.Name -eq "Hard disk 2"}

will get you the 2nd harddisk


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

0 Kudos
markdjones82
Expert
Expert

Ok, i'm getting close to getting this thing done.

I do have one more question.  I have noticed if a VM is waiting for customization you can't reapply customization.

In my script I am getting the cust spec and then changing the NIC template and assigning.  If I wanted to change the admin password, domain user etc what is best way to do that?

Can i make a non persistent change to the current cust spec for those pieces and then change the nic part like so?

Set-OsCustomizationSpec $custspec -Type NonPersistent -DomainUser $user -DomainPassword $pass -AdminPassword $adminpass

Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns

Or would it be better to create a temp spec run the NIC mapping on that one then remove?  Thoughts?

Also, I am trying to pass a variable for size called $hd = $item.ddrive, but it just spits out a ton of 3030303030 for specify of 30.  Any ideas why that is happenign?

if ($hd){
    New-HardDisk -VM $vmname -CapacityKB ($hd * 1MB) ThinProvisioned:$true
    }

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

To be honest, I'm not sure that OSCustomizationNicMapping is NonPersistent when the OSCustomization is NonPersistent.

That's why I prefer to clone the OSCustomizationSpec to a temporary one and do all the changes on there.

It looks as if that $hd is a [string]. With the multiplication operator you can specify how many times you want that string to be repeated.

So you are getting 1MB times the string "30".

Make sure $hd is an [int] by doing specific casting.

Like this

$hd = [int]$item.ddrive

I suspect that $item.ddrive comes from the CSV file. All fields coming from a CSV are of type [string].


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

0 Kudos
markdjones82
Expert
Expert

That did the trick Luc!  I think i'm with you, i will create a new temp spec and remove it.  That will be version 2.  Here is V1 of customize static ip, set CPU/mem, and an additional D drive.

##########################################################
#
# Mark Jones 2/20/2012
#
#
##########################################################
Connect-VIServer vcenter

$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

          
    #Clone the BaseVM with the adjusted Customization Specification
    New-VM -Name $vmname -template $basevm -Datastore $datastore -VMHost $vmhost -RunAsync
   
}
while (get-task -status running | Where-Object {$_.name -eq "clonevm_task"})

{
    sleep 20
     }

foreach ($item in $vmlist) {
    $datastore = $item.datastore
    $vmhost = $item.vmhost
    $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 * 1MB
    $vmname = $item.vmname
    $cpu = $item.cpu
    $mem = $item.mem

#set customization spec
    Get-OSCustomizationSpec $custspec | 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 CPU/Mem and customizaton

    Set-VM -VM $vmname -OSCustomizationSpec $custspec -NumCpu $cpu -MemoryMB $mem -Confirm:$false
   
#Create D drive windows
    if ($hd){
    New-HardDisk -VM $vmname -CapacityKB $hd -ThinProvisioned:$true}

}

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

Oh and how are people getting around putting the creds in plain text in a spreadsheet?  I saw a way to ask for creds but i assume that asks for every VM

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

You could consider using the Export- Import-PSCredential functions from Hal.


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

0 Kudos
markdjones82
Expert
Expert

Luc, as far as Hal's encryption, i haven't used another function in my script.  Do i just copy it to directory and then import it into mine to use it?

Here is V2 for anyone that cares.  It uses a csv with these headers:

templatedatastorevmhostcustspecvmnameipaddresssubnetgatewaypdnssdnsvlancpumemddriveadminpassusernamepass

##########################################################
#
# Mark Jones 2/20/2012
# Version 2
#
##########################################################
Connect-VIServer vcenter.com

$vmlist = Import-CSV vms.csv

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
         
    #Clone the templates
    New-VM -Name $vmname -template $basevm -Datastore $datastore -VMHost $vmhost -RunAsync

}

while (get-task -status running | Where-Object {$_.name -eq "clonevm_task"})
{
    sleep 20
}

foreach ($item in $vmlist) {
    $datastore = $item.datastore
    $vmhost = $item.vmhost
    $custspec = $item.custspec
    $ipaddr = $item.ipaddress
    $subnet = $item.subnet
    $gateway = $item.gateway
    $pdns = $item.pdns
    $sdns = $item.sdns
    $vlan = $item.vlan
    $hd = [int]$item.hd * 1MB
    $vmname = $item.vmname
    $cpu = $item.cpu
    $mem = $item.mem
    $username = $item.username
    $pass = $item.pass
    $adminpass = $item.adminpass

   #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
    #Start VM
    Start-VM -VM $vmname -Confirm:$false
}

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

Luc/ALL,

  I got a work around for the admin, domain, and username plain text issue.  I have it prompt one time at the beginning of the script and read that into the variable.  Here is V3

##########################################################
#
# Mark Jones 2/23/2012
# Version 3
#
##########################################################

#Prompt for domain username/password and local admin password

$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.com

$vmlist = Import-CSV vms.csv

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
         
    #Clone the templates
    New-VM -Name $vmname -template $basevm -Datastore $datastore -VMHost $vmhost -RunAsync

}

while (get-task -status running | Where-Object {$_.name -eq "clonevm_task"})
{
    sleep 20

}

foreach ($item in $vmlist) {
    $datastore = $item.datastore
    $vmhost = $item.vmhost
    $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
    #Start VM
    Start-VM -VM $vmname -Confirm:$false
}

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

Great, thanks for sharing.


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

0 Kudos
markdjones82
Expert
Expert

Ok, so I have an issue with my script no longer working on Vsphere 5.

Everything works other than joining the domain. The script works fine on 4.x  I enter the credentials at the beginning as a string and pass to the customization spec.  Any ideas why my guests won't join domain on 5.x?

I tried doing this:

http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=101231...

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

The user@my.domain.com format should work against W2K8R2and W7.

Can you test by hard-coding the value instead of prompting ?


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

0 Kudos
markdjones82
Expert
Expert

Luc,

  I tried it with this line edited to not use variable with the same result.  It did not join the domain either. Any ideas?

Set-OSCustomizationSpec -spec $vmname -AdminPassword $adminpass -DomainUsername user@domain.com -DomainPassword $pass -Confirm:$false

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

Luc,

   Any other ideas?

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

Browsing the logs for clues I'm afraid.

Have a look at the logs in the following locations on the customised VM.

c:\windows\temp\vmware-imc\*

c:\windows\setup-act.log

c:\windows\setup-err.log

c:\windows\debug\*


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

0 Kudos
markdjones82
Expert
Expert

Cool let me spin up one more and verify i have everything coded correctly.

Is this something we can open a ticket on with vmware?  not sure if powercli has support per say

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

Concerning support, afaik you can open a call for PowerCLI under your normal support contract. Someone please correct me if I'm wrong ?

And there is this when you are using SDK calls.


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

0 Kudos
markdjones82
Expert
Expert

Luc, just now getting back to testing this. I'm reading through guest customization log and nothing stands out

Customization in progress set to 1 at 2012-Aug-08 05:29:33
Rpci: Sending request='deployPkg.update.state 4 0 C:\Windows\TEMP\vmware-imc\guestcust.log'

Rpci: Sent request='deployPkg.update.state 4 0 C:\Windows\TEMP\vmware-imc\guestcust.log', reply='', len=0, status=1

Successfully opened key SYSTEM\CurrentControlSet\Control\Session Manager\
Size of reg_multi_sz 21.
Read multi_sz value from registry autocheck autochk *, size 21.
string value from registry autocheck autochk *.
Returning 1 elements
Got BootExecute from session mgr.
Native App sysprepDecrypter.exe, arguments ''
Copied file sysprepDecrypter.exe to C:\Windows\system32\sysprepDecrypter.exe
Updated boot execute value.
Successfully created/opened key SOFTWARE\VMware, Inc.\Guest Customization\
New boot execute:
autocheck autochk *
sysprepDecrypter.exe
System Drive: C:

Moving directory 'sysprep' to 'C:'

select * from win32_networkadapter where Manufacturer != 'Microsoft' and ServiceName != 'VMnetAdapter' and  manufacturer is not null and MACAddress is not null
Found 0 objects. Pointer 0. return code 1(0x1)
Executing command C:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe /reboot /unattend:C:\sysprep\sysprep.xml

Successfully executed command C:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe /reboot /unattend:C:\sysprep\sysprep.xml

Trying to connect network interfaces, attempt 1
Rpci: Sending request='deployPkg.update.state 4 103 C:\Windows\TEMP\vmware-imc\guestcust.log@4000'

Rpci: Sent request='deployPkg.update.state 4 103 C:\Windows\TEMP\vmware-imc\guestcust.log@4000', reply='queryNicsSupported', len=18, status=1

Got VMX response 'queryNicsSupported'
Rpci: Sending request='deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000'

Rpci: Sent request='deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000', reply='disconnected', len=12, status=1

Got VMX response 'disconnected'
Rpci: Sending request='deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000'

Rpci: Sent request='deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000', reply='connected', len=9, status=1

Got VMX response 'connected'
The network interfaces are connected on 1 second
Successfully opened key SOFTWARE\VMware, Inc.\Guest Customization\
Size of reg_multi_sz 21.
Read multi_sz value from registry autocheck autochk *, size 21.
string value from registry autocheck autochk *.
Returning 1 elements
Successfully opened key SYSTEM\CurrentControlSet\Control\Session Manager\
Size of reg_multi_sz 22.
Read multi_sz value from registry sysprepDecrypter.exe, size 22.
string value from registry sysprepDecrypter.exe.
Returning 1 elements
Going to delete file C:\Windows\system32\sysprepDecrypter.exe
Deleted file C:\Windows\system32\sysprepDecrypter.exe
Customization in progress set to 0 at 2012-Aug-08 05:32:39
Rpci: Sending request='deployPkg.update.state 5 0 C:\Windows\TEMP\vmware-imc\guestcust.log'

Rpci: Sent request='deployPkg.update.state 5 0 C:\Windows\TEMP\vmware-imc\guestcust.log', reply='', len=0, status=1

SysprepDecrypter has unobfuscated the password successfully
Deleting "C:\sysprep" ...

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

Ok we figured it out.  My coworker had noticed that in my CustSpec that I clone from I had the workgroup option checked instead of domain.

So, when passing the credentials I guess it couldn't apply them to anything.  I changed it in my base customization spec and we are in business!

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

PowerCLI – Using PowerShell Jobs is not there anymore. Can someone restore it?

Thanks in advance.

0 Kudos
markdjones82
Expert
Expert

newa, I don't undertand wha you are asking?

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