Deploying multiple VMs via PowerCLI – Updated v1.2

DeployVMv1.2

I’ve gotten some great feedback from my original PowerShell/PowerCLI script to deploy multiple VMs asynchronously via a CSV file found here.  I decided a minor update was needed to employ these new ideas along with a few I had myself.

One of those ideas was to require the usage of the new PowerCLI 5.5 R2 features which allows the script to run without the need for a 32bit PowerShell console.

Changes include:

  • Cleaned up code / Minor bug fixes
  • Added CSV field descriptions to notes section
  • Removed requirement for 32bit PowerShell
  • Added requirement for PowerCLI 5.5 R2 or later
  • Added Boot parameter to determine whether or not to power on new VMs
  • Added OS Customization Spec to CSV (previously was hard coded in user variables)
  • Fixed logic for vSS vs vDS – Added parameter to CSV
  • Added ability to use DHCP instead of just static IPs
  • Renamed a few CSV fields to better describe parameter
  • Added progress bar to indicate status

I also thought it would be a good idea to describe how to setup and run the script as there are a few components that need to be in place for everything to run smoothly. If you happen to have run v1 of the script, you’ll need to create a new DeployVM.csv as some fields have been added and others changed.

In order to run the script, three components need to be setup prior.

1) OS Customization Spec

I won’t go into great detail about what a OS Customization Spec is but I did want to point out a few helpful items. Essentially, we need to create a Custom Spec that we will then use as a template of sorts. I like to have one set aside specifically for the script to use.

For both Windows and Linux you’ll want to set the Computer Name as shown here:
OSSpec_ComputerNameAlso, set the Network as shown:
OSSpec_NetworkYou can then setup the remaining details as it fits your needs.

A note on Linux – you’ll need to set the DNS servers in the Custom Spec as they are not able to be modified via the Set-OSCustomizationNicMapping cmdlet.

Lastly, ensure that your OS is supported via OS Customization Spec as all are not (even if they are supported as a guest OS in VMware – for example Windows 2000 and CentOS are two examples that are not supported)

2) VM Template

This one is pretty self-explanatory – you’ll need a template to clone for your new VM.

3) DeployVM.csv

This is where the script receives all the information that you provide to build the new VMs. As the field descriptions have been added to the script, I won’t go over all of them here.

It’s worth noting that the script can create a blank CSV for you by issuing the following command:

.\DeployVM.ps1 -createcsv

This will create the DeployVM.csv file in the same directory as the script.

Running the script

Once you have tested the script and have everything in place, it’s easy to reuse over again as you’ll just need to update the DeployVM.csv with a few parameters. For ease of use you can get to a point where a single one-liner will fire off the script like so:

.\DeployVM.ps1 -csvfile E:\DeployVM\DeployVM.csv -vcenter vcname -auto

Logging

The last point to mention is that a directory is created to store a log of the actions as well as a folder to store a copy of the DeployVM.csv so you can keep track of who has done what and when. These folders are created in the same directory in which the script is run.

Enjoy!

 

Advertisements

79 thoughts on “Deploying multiple VMs via PowerCLI – Updated v1.2

  1. PK Vanity

    I get “Attempted to divide by zero” at line 240 and “Index operation failed; the array index evaluated to null” at line 265. Any ideas?

    Reply
      1. PK Vanity

        Actually I found my issues. For some reason the $newVMs.count was not registering, but by adding @($newVMs).count it picked up the value. Also, for the array index being null…that was my bad. I had the Foreach closing bracket misplaced. Thanks for your quick response and willing to assist. I appreciate that greatly!!

  2. Hash

    Hi, I get he following error:
    Deploying VMs

    Attempted to divide by zero.
    At C:\temp\DeployVM.ps1:217 char:1
    + Write-Progress -Activity “Deploying VMs” -Status $vmStatus -PercentComplete (100 …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

    Deploying win2k8_02

    win2k8_02 failed to deploy!
    Attempted to divide by zero.

    Reply
    1. smasterson Post author

      Hash,
      It seems to not be validating the number of VMs to create properly. Please confirm you are using version 1.2. Can you send me a copy of the log as well as the csv and I’ll take a closer look? smasterson [at] gmail

      –shawn

      Reply
      1. Hash

        Hi Shawn, thank you for your reply.
        Interestingly I have tried with two VM’s in the CSV file and the script works perfectly. I seem to be getting the error if there is only one VM in CSV file which is how I have been testing. As I will be deploying more then one VM I am happy not to chase further but can still send you a copy of the log and CSV if you are interested.

        This script is exactly what I am looking for, but also have a requirement to deploy with two NIC’s with different ip address details on separate VLAN’s. Is it possible to add the capability of multiple NIC’s like you have done with the additional disks for example NIC1 NIC2.

        Thank you again for an outstanding solution.

  3. venkatesh

    Hi,

    i am trying to install vm by using this script. vm is installing and the hardware changes are working perfectly but the ip address which we assign in script is not working .please advice .

    Reply
    1. smasterson Post author

      Hi venkatesh
      There are a couple of possibilities here. If DHCP is set to true in the csv, it will skip the IP assignment. The guest OS must be supported and VMware tools must be installed.
      You could try to deploy manually via the spec and see if any errors are thrown in vCenter.

      Hope this helps

      Reply
      1. venkatesh

        Hi ,

        We set DHCP as false only . i am debugging code by putting out_log option it showing like it taking static ip which i have given in csv file . but when the vm up again it is taking DHCP only it is not taking ip which i have given .and vmware tools are installed .

  4. venkatesh

    Hi When i checked temp logs i found below
    please check

    [2014-10-26T00:22:07 INFO] GuestCustUtil invoked.
    [2014-10-26T00:22:07 INFO] Params: customize -sealparam “/quiet /generalize /oobe /reboot” -nics 4000 -schedulenativeunobfusc
    [2014-10-26T00:22:07 DEBUG] Customization in progress set to 1 at 2014-Oct-26 00:22:07
    [2014-10-26T00:22:07 DEBUG] Rpci: Sending request=’deployPkg.update.state 4 0 C:\Windows\TEMP\vmware-imc\guestcust.log’

    [2014-10-26T00:22:07 DEBUG] Rpci: Sent request=’deployPkg.update.state 4 0 C:\Windows\TEMP\vmware-imc\guestcust.log’, reply=”, len=0, status=1

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

    [2014-10-26T00:22:07 DEBUG] Moving directory ‘sysprep’ to ‘C:’

    [2014-10-26T00:22:07 DEBUG] select * from win32_networkadapter where Manufacturer != ‘Microsoft’ and ServiceName != ‘VMnetAdapter’ and manufacturer is not null and MACAddress is not null
    [2014-10-26T00:22:07 DEBUG] Found 1 objects. Pointer 1696468. return code 0(0x0)
    [2014-10-26T00:22:07 DEBUG] Found 0 objects. Pointer 0. return code 1(0x1)
    [2014-10-26T00:22:07 DEBUG] Returning value 00:50:56:9B:0F:67 for system property
    [2014-10-26T00:22:07 DEBUG] Setting dhcp for nic # 0
    [2014-10-26T00:22:07 DEBUG] Returning value \\TESTPC-PC\ROOT\CIMV2:Win32_NetworkAdapter.DeviceID=”7″ for system property
    [2014-10-26T00:22:07 DEBUG] ASSOCIATORS OF {\\TESTPC-PC\ROOT\CIMV2:Win32_NetworkAdapter.DeviceID=”7″} where ResultClass = Win32_NetworkAdapterConfiguration
    [2014-10-26T00:22:08 DEBUG] Found 1 objects. Pointer 169ae20. return code 0(0x0)
    [2014-10-26T00:22:08 DEBUG] Found 0 objects. Pointer 0. return code 1(0x1)
    [2014-10-26T00:22:08 DEBUG] Clearing gateway ip addresses.
    [2014-10-26T00:22:08 DEBUG] Enabling DHCP on the computer
    [2014-10-26T00:22:08 DEBUG] Returning value \\TESTPC-PC\ROOT\CIMV2:Win32_NetworkAdapterConfiguration.Index=7 for system property
    [2014-10-26T00:22:08 DEBUG] Setting DNS Server to ip
    [2014-10-26T00:22:08 DEBUG] Executing command C:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe /reboot /unattend:C:\sysprep\sysprep.xml

    [2014-10-26T00:22:08 DEBUG] Successfully executed command C:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe /reboot /unattend:C:\sysprep\sysprep.xml

    [2014-10-26T00:22:08 DEBUG] Trying to connect network interfaces, attempt 1
    [2014-10-26T00:22:08 DEBUG] Rpci: Sending request=’deployPkg.update.state 4 103 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′

    [2014-10-26T00:22:08 DEBUG] Rpci: Sent request=’deployPkg.update.state 4 103 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′, reply=’queryNicsSupported’, len=18, status=1

    [2014-10-26T00:22:08 DEBUG] Got VMX response ‘queryNicsSupported’
    [2014-10-26T00:22:08 DEBUG] Rpci: Sending request=’deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′

    [2014-10-26T00:22:08 DEBUG] Rpci: Sent request=’deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′, reply=’disconnected’, len=12, status=1

    [2014-10-26T00:22:08 DEBUG] Got VMX response ‘disconnected’
    [2014-10-26T00:22:09 DEBUG] Rpci: Sending request=’deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′

    [2014-10-26T00:22:09 DEBUG] Rpci: Sent request=’deployPkg.update.state 4 104 C:\Windows\TEMP\vmware-imc\guestcust.log@4000′, reply=’connected’, len=9, status=1

    [2014-10-26T00:22:09 DEBUG] Got VMX response ‘connected’
    [2014-10-26T00:22:09 INFO] The network interfaces are connected on 1 second
    [2014-10-26T00:22:09 INFO] GuestCustUtil exiting.

    Reply
  5. JJVidanez

    Hi,
    I’m getting the following error:

    Required property datastore is missing from data object of type VirtualMachineRelocateSpecDiskLocator

    while parsing serialized DataObject of type vim.vm.RelocateSpec.DiskLocator
    at line 1, column 1068

    while parsing property “disk” of static type ArrayOfVirtualMachineRelocateSpecDiskLocator

    while parsing serialized DataObject of type vim.vm.RelocateSpec
    at line 1, column 1014

    while parsing property “location” of static type VirtualMachineRelocateSpec

    while parsing serialized DataObject of type vim.vm.CloneSpec
    at line 1, column 1003

    while parsing property “cloneSpec” of static type VirtualMachineCloneSpec

    while parsing serialized DataObject of type vim.storageDrs.StoragePlacementSpec
    at line 1, column 324

    while parsing call information for method RecommendDatastores
    at line 1, column 218

    while parsing SOAP body
    at line 1, column 207

    while parsing SOAP envelope
    at line 1, column 38

    while parsing HTTP request for method recommendDatastores
    on object of type vim.StorageResourceManager
    at line 1, column 0

    For every vm,
    my versions are:

    VMware vSphere PowerCLI 5.5 Release 2 Patch 1 build 1931983
    and vcenter 5.5 update 2

    Reply
    1. JJVidanez

      Hi,
      I found the error https://communities.vmware.com/thread/473720
      I’m launching your script against a datastorage cluster (SDRS) and then it doesn’t apply the parameter of DiskStorageFormat. If we use this parameter we can only work against datastorage and not SDRS.
      So only 2 options or decide which datastorage to use estimating the space that would use, or remove the parameter DiskStorageFormat.
      To be honest I don’t like neither of them but doesnt look like any other solution available.

      Reply
      1. smasterson Post author

        Correct, it is a bug in PowerCLI 😦
        For me, I have removed the DiskStorageFormat switch in the New-VM call so I can still use Datastore Clusters. It seems to use thin by default which is what I would want anyhow.
        It was supposedly fixed in PowerCLI 5.8 according to the release notes but I still get the same error.

  6. JJVidanez

    I would like to introduce some changes on your script in order to use New-OSCustomizationSpec per vm and -nonpersistent parameters, and a switch for SDRS or datastore directly. I will upgrade it to version 1.3 and keep your credits if you dont mind.
    I’ll publish it in my blog if you agrees

    Reply
    1. smasterson Post author

      Absolutely, feel free to customize to your own liking!
      Note – you can currently specify a Datastore Cluster or a single Datastore – no changes needed.

      Reply
      1. JJVidanez

        Ok I have your 1.3 script ready, the improves are :
        1. Add creation onthefly for customization Spec for linux systems
        2. Ability to create machines names and guest hostname using different names
        3. Added a value to find out the kind of disk because powercli bug for SDRS reported at https://communities.vmware.com/message/2442684#2442684
        4. Remove the dependency for an already created OScustomization Spec

        For 1.4 I would like to:
        1. The ability to deploy system with more than 1 IP coming from a template with just one network adapter. So you need to create the adapter and populate it.
        2. The ability to deploy VMs in bunches. I mean if a cluster has 4 nodes create maximum of vms at time and wait until they finish.

  7. Pingback: Crear múltiples Linux VMs de un fichero CSV usando PowerCli. Deploying multiple Linux VMs using PowerCli – VIDANEZ SITE

  8. venaktesh

    hi i am getting below exception

    index operation failed :the array index evaluated to null . at c:\deplyvm.ps1:184 char 5

    please advice.

    Reply
  9. Ankur Dahiya

    Hello Shawn,

    Can you help me with the statement in the script to have the VMs created with the gues OS name in the LowerCase & VM Name in vCenter in the UpperCase.

    Regards,
    Ankur Dahiya

    Reply
  10. smasterson Post author

    Hi Ankur
    Unfortunately, the same variable is used for both names (via the OS Customization Spec), so the change will need to occur after VM creation.

    What you could try is this:
    1) Use lowercase name for VM creation (in csv) – this will create a VM with both Guest OS and vSphere name in lowercase.
    2) Apply change to vSphere name after creation (in portion of script that is going to set vCPU/Disk/etc)

    (I haven’t fully tested this, please proceed with caution!)

    Try inserting this command after line 299 (line 299 should read “$VM = Get-VM $vmName”)
    Set-VM -VM $VM -Name ($VM.Name).ToUpper() -Confirm:$false

    That should do the trick.

    –shawn

    Reply
  11. Matthew Dartez

    So I am running into build issues. Here’s my log:

    **************************************************************************************
    DeployVM Ver:1.2 Start Time: 03-18-2015 08:47:14
    **************************************************************************************

    Using .\DeployVM.csv

    New VMs to create: 4

    Connecting to vCenter – crifvc.myappro.com

    Deploying VMs

    Deploying LC-T-APP-WF01

    LC-T-APP-WF01 failed to deploy!
    3/18/2015 8:47:43 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory parameter OSCustomizationSpec
    3/18/2015 8:47:43 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name ‘tempLC-T-APP-WF01’.
    Index operation failed; the array index evaluated to null.
    3/18/2015 8:47:39 AM New-VM OSCustomizationSpec parameter: Could not find any of the objects specified by name.
    3/18/2015 8:47:39 AM New-VM Could not find OSCustomizationSpec with name ‘tempLC-T-APP-WF01’.
    Deploying LC-T-APP-ENCOR1

    LC-T-APP-ENCOR1 failed to deploy!
    3/18/2015 8:47:56 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory parameter OSCustomizationSpec
    3/18/2015 8:47:56 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name ‘tempLC-T-APP-ENCOR1’.
    Index operation failed; the array index evaluated to null.
    3/18/2015 8:47:51 AM New-VM OSCustomizationSpec parameter: Could not find any of the objects specified by name.
    3/18/2015 8:47:51 AM New-VM Could not find OSCustomizationSpec with name ‘tempLC-T-APP-ENCOR1’.
    Deploying LC-T-APP-UBT01

    LC-T-APP-UBT01 failed to deploy!
    3/18/2015 8:48:08 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory parameter OSCustomizationSpec
    3/18/2015 8:48:08 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name ‘tempLC-T-APP-UBT01’.
    Index operation failed; the array index evaluated to null.
    3/18/2015 8:48:04 AM New-VM OSCustomizationSpec parameter: Could not find any of the objects specified by name.
    3/18/2015 8:48:04 AM New-VM Could not find OSCustomizationSpec with name ‘tempLC-T-APP-UBT01’.
    Deploying LC-T-APP-TMK01

    LC-T-APP-TMK01 failed to deploy!
    3/18/2015 8:48:20 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory parameter OSCustomizationSpec
    3/18/2015 8:48:20 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name ‘tempLC-T-APP-TMK01’.
    Index operation failed; the array index evaluated to null.
    3/18/2015 8:48:16 AM New-VM OSCustomizationSpec parameter: Could not find any of the objects specified by name.
    3/18/2015 8:48:16 AM New-VM Could not find OSCustomizationSpec with name ‘tempLC-T-APP-TMK01’.

    All Deployment Tasks Created

    Monitoring Task Processing

    **************************************************************************************
    Processing Complete

    The following VMs failed to deploy:
    LC-T-APP-WF01
    LC-T-APP-ENCOR1
    LC-T-APP-UBT01
    LC-T-APP-TMK01

    **************************************************************************************
    DeployVM Finish Time: 03-18-2015 08:48:21
    **************************************************************************************

    Reply
    1. Matthew Dartez

      Here’s the Output

      Deploying LC-T-APP-WF01
      Index operation failed; the array index evaluated to null.
      At C:\VS_Projects\PowerShell\PowerCLI\vCenter and vSphere\Deploy_Automations\DeploymentScript03\DepScript03_V01.ps1:265 char:5
      + $taskTab[(New-VM -Name $VM.Name -ResourcePool $VM.ResourcePool -Location $VM …
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : InvalidOperation: (:) [], RuntimeException
      + FullyQualifiedErrorId : NullArrayIndex

      Remove-OSCustomizationSpec : 3/18/2015 8:57:18 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name
      ‘tempLC-T-APP-WF01’.
      At C:\VS_Projects\PowerShell\PowerCLI\vCenter and vSphere\Deploy_Automations\DeploymentScript03\DepScript03_V01.ps1:268 char:5
      + Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName -Confirm:$false
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : ObjectNotFound: (tempLC-T-APP-WF01:String) [Remove-OSCustomizationSpec], VimException
      + FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_ObjectNotFound,VMware.VimAutomation.ViCore.Cmdlets.Commands.Rem
      oveOSCustomizationSpec

      Remove-OSCustomizationSpec : 3/18/2015 8:57:18 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory
      parameter OSCustomizationSpec
      At C:\VS_Projects\PowerShell\PowerCLI\vCenter and vSphere\Deploy_Automations\DeploymentScript03\DepScript03_V01.ps1:268 char:5
      + Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName -Confirm:$false
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : NotSpecified: (:) [Remove-OSCustomizationSpec], VimException
      + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.RemoveOSCustomizationSpec

      LC-T-APP-WF01 failed to deploy!
      3/18/2015 8:57:18 AM Remove-OSCustomizationSpec Value cannot be found for the mandatory parameter OSCustomizationSpec
      3/18/2015 8:57:18 AM Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name ‘tempLC-T-APP-WF01’.
      Index operation failed; the array index evaluated to null.
      3/18/2015 8:57:14 AM New-VM OSCustomizationSpec parameter: Could not find any of the objects specified by name.
      3/18/2015 8:57:14 AM New-VM Could not find OSCustomizationSpec with name ‘tempLC-T-APP-WF01’.

      Reply
      1. smasterson Post author

        Hi Matt
        It appears as though the name you are passing for the OS Customization Spec does not exist – can you confirm you have setup one up named ‘tempLC-T-APP-WF01’?

      2. Matthew Dartez

        So, the CSV is setup this way:
        Name Boot OSType Template CustSpec Folder ResourcePool CPU RAM Disk2 Disk3 Disk4 Datastore DiskStorageFormat NetType Network DHCP IPAddress SubnetMask Gateway pDNS sDNS
        LC-T-APP-WF01 LC-T-APP-TMPL LCC_ApproDev_Testing LCC_TEST LCC_APP_TEST VMAX_LCC_TEST_APP01_04DA Thin VLAN627 10.110.47.118 255.255.255.128 10.110.47.1 10.15.1.3 10.15.1.6
        LC-T-APP-ENCOR1 LC-T-APP-TMPL LCC_ApproDev_Testing LCC_TEST LCC_APP_TEST VMAX_LCC_TEST_APP02_04E2 Thin VLAN627 10.110.47.109 255.255.255.128 10.110.47.1 10.15.1.3 10.15.1.6
        LC-T-APP-UBT01 LC-T-APP-TMPL LCC_ApproDev_Testing LCC_TEST LCC_APP_TEST VMAX_LCC_TEST_APP03_04EA Thin VLAN627 10.110.47.113 255.255.255.128 10.110.47.1 10.15.1.3 10.15.1.6
        LC-T-APP-TMK01 LC-T-APP-TMPL LCC_ApproDev_Testing LCC_TEST LCC_APP_TEST VMAX_LCC_TEST_APP04_04F2 Thin VLAN627 10.110.47.111 255.255.255.128 10.110.47.1 10.15.1.3 10.15.1.6

        I do not know why it’s referencing temp but I did notice in your script it has this in it:
        temp$vmName

        at the OSCustSpec area. So I am perplexed.

      3. smasterson Post author

        You are correct – what is happening here is that the code is taking your existing spec (the one you identified in the csv) and creating a new (temp) spec. It then makes changes to this temp spec and applies them to the template when it is rolled out.

        If you look at your specs – do you see any that start with temp? It seems as though it is either not getting created at all or with the wrong name.

      4. Matthew Dartez

        We have no custspecs named Temp.

        My CSV file looks like this:
        Name,Boot,OSType,Template,CustSpec,Folder,ResourcePool,CPU,RAM,Disk2,Disk3,Disk4,Datastore,DiskStorageFormat,NetType,Network,DHCP,IPAddress,SubnetMask,Gateway,pDNS,sDNS,Notes
        LC-T-APP-WF01,,,LC-T-APP-TMPL,TestLCC,LCC_TEST,LCC_APP_TEST,,,,,,VMAX_LCC_TEST_APP01_04DA,Thin,,VLAN627,,10.110.47.118,255.255.255.128,10.110.47.1,10.15.1.3,10.15.1.6,Woodforest LCC Test Server
        LC-T-APP-ENCOR1,,,LC-T-APP-TMPL,TestLCC,LCC_TEST,LCC_APP_TEST,,,,,,VMAX_LCC_TEST_APP02_04E2,Thin,,VLAN627,,10.110.47.109,255.255.255.128,10.110.47.1,10.15.1.3,10.15.1.6,Encore LCC Test Server
        LC-T-APP-UBT01,,,LC-T-APP-TMPL,TestLCC,LCC_TEST,LCC_APP_TEST,,,,,,VMAX_LCC_TEST_APP03_04EA,Thin,,VLAN627,,10.110.47.113,255.255.255.128,10.110.47.1,10.15.1.3,10.15.1.6,UB&T LCC Test Server
        LC-T-APP-TMK01,,,LC-T-APP-TMPL,TestLCC,LCC_TEST,LCC_APP_TEST,,,,,,VMAX_LCC_TEST_APP04_04F2,Thin,,VLAN627,,10.110.47.111,255.255.255.128,10.110.47.1,10.15.1.3,10.15.1.6,TMK LCC Test Server

        I created another customization spec and labeled it “TestLCC” Still didn’t work (Same Errors)

        I guess it’s not creating the temp spec in the script?

      5. smasterson Post author

        Unfortunately, I can’t test at the moment – can you try changing the VM name to something simple like ‘testvm’.
        Just want to make sure it is not the VM name that is throwing it off.

        Another thing to try would be to test the create spec part of the code with something like this:
        $vmName = “testVMname”
        $currentSpec = “Nameofexistingspec”
        $spec = Get-OSCustomizationSpec -Name $currentSpec
        $tempSpec = $spec | New-OSCustomizationSpec -Name temp$vmName

        Running the above – any errors? Is a new spec created?

      6. Matthew Dartez

        The four variables, are you saying to place them at the beginning of the code? Where should they go?

        Still getting that error when I swap names:

        Deploying testvm1
        Index operation failed; the array index evaluated to null.
        At C:\VS_Projects\PowerShell\PowerCLI\vCenter and
        vSphere\Deploy_Automations\DeploymentScript03\DepScript03.ps1:265 char:2
        + $taskTab[(New-VM -Name $VM.Name -ResourcePool $VM.ResourcePool -Location
        $VM.Fo …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ~~~~~~
        + CategoryInfo : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : NullArrayIndex

        Remove-OSCustomizationSpec : 3/18/2015 10:52:15 AM
        Remove-OSCustomizationSpec Could not find OSCustomizationSpec with name
        ‘temptestvm1’.
        At C:\VS_Projects\PowerShell\PowerCLI\vCenter and
        vSphere\Deploy_Automations\DeploymentScript03\DepScript03.ps1:268 char:2
        + Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName
        -Confirm:$false
        +
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : ObjectNotFound: (temptestvm1:String) [Remove-OSC
        ustomizationSpec], VimException
        + FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_ObjectNo
        tFound,VMware.VimAutomation.ViCore.Cmdlets.Commands.RemoveOSCustomizationS
        pec

        Remove-OSCustomizationSpec : 3/18/2015 10:52:15 AM
        Remove-OSCustomizationSpec Value cannot be found for the mandatory
        parameter OSCustomizationSpec
        At C:\VS_Projects\PowerShell\PowerCLI\vCenter and
        vSphere\Deploy_Automations\DeploymentScript03\DepScript03.ps1:268 char:2
        + Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName
        -Confirm:$false
        +
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Remove-OSCustomizationSpec],
        VimException
        + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomatio
        n.ViCore.Cmdlets.Commands.RemoveOSCustomizationSpec

        testvm1 failed to deploy!
        3/18/2015 10:52:15 AM Remove-OSCustomizationSpec Value cannot be found for the
        mandatory parameter OSCustomizationSpec
        3/18/2015 10:52:15 AM Remove-OSCustomizationSpec Could not find OSCustomization
        Spec with name ‘temptestvm1’.
        Index operation failed; the array index evaluated to null.
        3/18/2015 10:52:11 AM New-VM OSCustomizationSpec parameter: Could not find any
        of the objects specified by name.
        3/18/2015 10:52:11 AM New-VM Could not find OSCustomizationSpec with name ‘temp
        testvm1’.

      7. smasterson Post author

        You should be able to just run the four lines of code (with PowerCLI loaded and connected to VI server).
        You can leave the $vmName variable (or change for testing).
        You should just need to change the $currentSpec variable to the spec name you are trying to use.
        Leave the last two lines alone. The third line grabs the existing spec while the fourth line should make a copy of it.

      8. Matthew Dartez

        Ok looks like just running those four lines creates the CustomSpec, so now what lol?

      9. smasterson Post author

        Hmmm Ok
        Did you try using the same spec and VM name that you are using in the csv?
        Odd how it is created here but not via the full script.

      10. Matthew Dartez

        I did and it created it.

        Not sure why it doesn’t want to create it in the script. Let me know if you want to email (m.dartez@criflending.com) so I can throw some screenshots your way.

  12. Rehman

    Hi! I am trying to use your script, and it goes as far as deploying the VM but fails on Customization. The error in Status on my vi-client “Cannot complete customization”. Any pointers or tips? I can use the same customization when deploying VM’s manually and it works fine so the customization looks fine. Am I missing anything? My template has already got networking config in place.
    Thanks in advance and will wait for your reply.

    Reply
  13. Rehman

    Hello,
    Thank you for your response, I am getting the following in the PS console.

    New VMs to create: 1

    Connecting to vCenter – vcenter

    Deploying VMs

    Deploying TESTVM

    All Deployment Tasks Created

    Monitoring Task Processing

    TESTVM failed to deploy!

    **************************************************************************************
    Processing Complete

    The following VMs failed to deploy:
    TESTVM

    **************************************************************************************
    DeployVM Finish Time: 04-17-2015 03:33:48
    **************************************************************************************
    the log files below:
    **************************************************************************************
    DeployVM Ver:1.2.1 Start Time: 04-17-2015 03:30:46
    **************************************************************************************

    Using DeployVM.csv

    New VMs to create: 1

    Connecting to vCenter – vcenter
    Deploying VMs

    Deploying TESTVM

    All Deployment Tasks Created

    Monitoring Task Processing

    TESTVM failed to deploy!

    **************************************************************************************
    Processing Complete

    The following VMs failed to deploy:
    TESTVM

    **************************************************************************************
    DeployVM Finish Time: 04-17-2015 03:33:48
    **************************************************************************************

    Thanks in advance.

    Regards,
    Rehman

    Reply
    1. smasterson Post author

      Hmm..it seems we are still not seeing the actual error.

      Can you please swap out the following code on line 266:
      -EA SilentlyContinue
      change to
      -EA Stop

      Run again and let me know if you see a more detailed error

      Reply
      1. Rehman

        Hi!
        It ran and finished exactly as the previous errors it didn’t stop
        Thank you so much for assisting in this

      2. smasterson Post author

        Not sure what’s going on here…it seems the actual error is being suppressed some how.

        Try adding this line after line 275
        Write-Host $Error

        Are you running the script from console or ISE?
        Odd that we are not seeing the actual PS error here. Without it, it is very difficult to troubleshoot.

  14. Mor

    Hi Shawn,
    First, great script. saved me lots of time develop it myself 🙂
    i have changed few things for my requirements (added dynamic selection for esx host based on free memory, added few other fields and logic’s because i’m working with 2 vc servers).
    now, i have strange problem.
    i deploy 3 machines for debugging purpose . the first should be fine, the seconds should fail on configure and the third fail completely.
    when the script finish i have the following result:
    Processing Complete

    The following VMs were successfully created:
    meme1-vvw

    The following VMs failed to reconfigure properly:
    meme2-vvw

    The following VMs failed to deploy:
    meme3-vvw
    meme1-vvw

    as you can see the first vm (meme1) is successful and failed at the same time. it looks line the line :”if($taskTab.ContainsKey($_.Id) -and $_.State -eq “Success”)” is true and also the line “elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq “Error”)” is true.
    the only thing i changed in the tasktab is the id name. instead of using the vmname i add id_vmname (id is a filed from the csv).

    complete log:
    **************************************************************************************
    DeployVM Ver:1.2 Start Time: 04-19-2015 11:30:15
    **************************************************************************************

    Using D:\Automation\DeployVM\DeployVMs.csv

    Line 210: New VMs to create: 3
    Line 236: Deploying VMs

    Line 266: Connecting xxx…

    Name Port User
    —- —- —-
    vcprod01.pelephone.co.il 443 PELE\VCUser
    Getting host…
    host @{Name=xxx; [math]::round($_.MemoryUsageGB)=102}
    Line 300: Current customization: Name=tempmeme1-vvw

    free : 19.08

    Line 314: Deploying meme1-vvw

    Line 266: Connecting xxx…
    vcprod01.pelephone.co.il 443 PELE\VCUser
    Getting host…
    host @{Name=xxx; [math]::round($_.MemoryUsageGB)=102}
    Line 300: Current customization: Name=tempmeme2-vvw

    free : 19.08

    Line 314: Deploying meme2-vvw

    Line 266: Connecting xxx…
    vcprod01.pelephone.co.il 443 PELE\VCUser
    Getting host…
    host @{Name=xxx; [math]::round($_.MemoryUsageGB)=102}
    Line 300: Current customization: Name=tempmeme3-vvw

    free : 18.99

    Line 314: Deploying meme3-vvw

    Line 325: meme3-vvw failed to deploy!

    Line 326: 4/19/2015 11:30:45 AM New-VM Could not find Folder with name ‘new ser3vers’. .Exception
    Line 328: 4/19/2015 11:30:45 AM New-VM Could not find Folder with name ‘new ser3vers’.

    Line 335: All Deployment Tasks Created

    Line 336: Monitoring Task Processing

    Line 354: Reconfiguring meme1-vvw
    Line 359: Setting vCPU(s) and RAM on meme1-vvw
    Line 370: Setting Port Group on meme1-vvw
    WARNING: PowerCLI scripts should not use the ‘Client’ property. The property will be removed in a future release.

    MacAddress : 00:50:56:83:14:ec
    WakeOnLanEnabled : True
    NetworkName : dvP_10.57.9.0
    Type : Vmxnet3
    ParentId : VirtualMachine-vm-657391
    Parent : meme1-vvw
    Uid : /VIServer=pele\vcuser@vcprod01.pelephone.co.il:443/VirtualMachine=VirtualMachine-vm-657391/NetworkAd
    apter=4000/
    ConnectionState : NotConnected, GuestControl, NoStartConnected
    ExtensionData : VMware.Vim.VirtualVmxnet3
    Id : VirtualMachine-vm-657391/4000
    Name : Network adapter 1
    Client : VMware.VimAutomation.ViCore.Impl.V1.VimClient

    Line 403: Booting meme1-vvw
    Line 417: meme1-vvw is Complete

    Line 425: meme1-vvw failed to deploy!

    Line 354: Reconfiguring meme2-vvw
    Line 359: Setting vCPU(s) and RAM on meme2-vvw
    Line 370: Setting Port Group on meme2-vvw
    Set-NetworkAdapter : Cannot validate argument on parameter ‘Portgroup’. The argument is null. Supply a non-null
    argument and try the command again.
    At D:\Automation\DeployVM\DeployVM.ps1:385 char:61
    + $VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $MyVDPortgroup -Conf …
    + ~~~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Set-NetworkAdapter], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.VirtualDev
    ice.SetNetworkAdapter

    Line 403: Booting meme2-vvw
    Line 409: meme2-vvw completed with errors
    Line 411: Cannot validate argument on parameter ‘Portgroup’. The argument is null. Supply a non-null argument and try th
    e command again.
    2
    1
    1

    **************************************************************************************
    Processing Complete

    The following VMs were successfully created:
    meme1-vvw

    The following VMs failed to reconfigure properly:
    meme2-vvw

    The following VMs failed to deploy:
    meme3-vvw
    meme1-vvw

    **************************************************************************************
    DeployVM Finish Time: 04-19-2015 11:31:36
    **************************************************************************************
    Success:
    meme1-vvw
    @FailConfig:
    meme2-vvw
    @FailDeploy:
    meme3-vvw
    meme1-vvw

    Thanks
    Mor

    Reply
  15. Rehman

    Hi!
    I have added the Write-Host$Error but still no joy. I was running this from PowerGUI on Friday and today have executed this from PowerCli console but the errors are exactly the same as I had posted earlier. Below is the version detail I am running .

    C:\ Get-PSVersion

    Major Minor Build Revision
    —– —– —– ——–
    4 0 -1 -1

    PowerCLI C:\ Get-PowerCLIVersion

    PowerCLI Version
    —————-
    VMware vSphere PowerCLI 6.0 Release 1 build 2548067
    —————
    Component Versions
    —————
    VMWare AutoDeploy PowerCLI Component 6.0 build 2358282
    VMWare ImageBuilder PowerCLI Component 6.0 build 2358282
    VMware License PowerCLI Component 6.0 build 2315846
    VMware vSphere PowerCLI Component 6.0 build 2548068
    VMware Cloud Infrastructure Suite PowerCLI Component 6.0 build 2548068
    VMware VDS PowerCLI Component 6.0 build 2548068
    VMware vCloud Director PowerCLI Component 6.0 build 2512755
    VMware HA PowerCLI Component 6.0 build 2510422
    VMware vCloud Air PowerCLI Component 6.0 build 2512755
    VMware PowerCLI Component for Storage Management 6.0 build 2522368

    Reply
  16. Matthew Lieblong

    Shawn,
    Thank you for sharing this multiple VM deployment tool. It worked perfectly right out of the gate. I have modified it a bit for use with rolling out large numbers of IO Analyzer worker VMs with more granular configurations. On the worker IO Analyzer VMs, VMware recommends placing the primary OS disk on a storage system other than that which you intend to test so as to avoid having untracked OS operations impact a target storage system’s maximum capabilities and skewing the results. As originally written, your DeployVM script placed any of the optional additional disks on the same datastore as the primary/OS. Since you already had the optional disks 2/3/4 coded in the script, I added fields and variables to the csvfile, createcsv, and post-build reconfiguration section of the script respectively, as well as updated the comments at the top. I have tested placing all three additional disks on three unique datastores successfully with various arrangements, skips, etc. CSV file must have DiskStorageFormat value for each additional disk 2/3/4, or will error. A similar vnic mod would likely address the need for additional vnics as one commenter previously requested. Your script was a great help, so in turn I am sharing the modified version (below).
    Thanks again.
    -Matthew Lieblong

    ———-beginning of script—————–

    #requires –Version 3

    #——————————————————————–
    # Parameters
    param (
    [parameter(Mandatory=$false)]
    [string]$csvfile,
    [parameter(Mandatory=$false)]
    [string]$vcenter,
    [parameter(Mandatory=$false)]
    [switch]$auto,
    [parameter(Mandatory=$false)]
    [switch]$createcsv
    )
    #——————————————————————–
    # User Defined Variables
    #——————————————————————–
    # Static Variables
    $scriptName = “DeployVM”
    $scriptVer = “1.2”
    $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
    $starttime = Get-Date -uformat “%m-%d-%Y %I:%M:%S”
    $logDir = $scriptDir + “\Logs\”
    $logfile = $logDir + $scriptName + “_” + (Get-Date -uformat %m-%d-%Y_%I-%M-%S) + “_” + $env:username + “.txt”
    $deployedDir = $scriptDir + “\Deployed\”
    $deployedFile = $deployedDir + “DeployVM_” + (Get-Date -uformat %m-%d-%Y_%I-%M-%S) + “_” + $env:username + “.csv”
    $exportpath = $scriptDir + “\DeployVM.csv”
    $headers = “” | Select-Object Name, Boot, OSType, Template, CustSpec, Folder, ResourcePool, CPU, RAM, Disk2, Disk3, Disk4, Datastore, Datastore2, Datastore3, Datastore4, DiskStorageFormat, DiskStorageFormat2, DiskStorageFormat3, DiskStorageFormat4, NetType, Network, DHCP, IPAddress, SubnetMask, Gateway, pDNS, sDNS, Notes
    $taskTab = @{}
    #——————————————————————–
    # Load Snap-ins
    # Add VMware snap-in if required
    If ((Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null) {add-pssnapin VMware.VimAutomation.Core}
    #——————————————————————–
    # Functions
    Function Out-Log {
    Param(
    [Parameter(Mandatory=$true)][string]$LineValue,
    [Parameter(Mandatory=$false)][string]$fcolor = “White”
    )
    Add-Content -Path $logfile -Value $LineValue
    Write-Host $LineValue -ForegroundColor $fcolor
    }
    Function Read-OpenFileDialog([string]$WindowTitle, [string]$InitialDirectory, [string]$Filter = “All files (*.*)|*.*”, [switch]$AllowMultiSelect)
    {
    Add-Type -AssemblyName System.Windows.Forms
    $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $openFileDialog.Title = $WindowTitle
    if (![string]::IsNullOrWhiteSpace($InitialDirectory)) { $openFileDialog.InitialDirectory = $InitialDirectory }
    $openFileDialog.Filter = $Filter
    if ($AllowMultiSelect) { $openFileDialog.MultiSelect = $true }
    $openFileDialog.ShowHelp = $true # Without this line the ShowDialog() function may hang depending on system configuration and running from console vs. ISE.
    $openFileDialog.ShowDialog() > $null
    if ($AllowMultiSelect) { return $openFileDialog.Filenames } else { return $openFileDialog.Filename }
    }
    #——————————————————————–
    # Main Procedures
    # Start Logging
    Clear-Host
    If (!(Test-Path $logDir)) {New-Item -ItemType directory -Path $logDir | Out-Null}
    Out-Log “**************************************************************************************”
    Out-Log “$scriptName`tVer:$scriptVer`t`t`t`tStart Time:`t$starttime”
    Out-Log “**************************************************************************************`n”
    # If requested, create DeployVM.csv and exit
    If ($createcsv) {
    If (Test-Path $exportpath) {
    Out-Log “`n$exportpath Already Exists!`n” “Red”
    Exit
    } Else {
    Out-Log “`nCreating $exportpath`n” “Yellow”
    $headers | Export-Csv $exportpath -NoTypeInformation
    Out-Log “Done!`n”
    Exit
    }
    }

    # Ensure PowerCLI is at least version 5.5 R2 (Build 1649237)
    If ((Get-PowerCLIVersion).Build -lt 1649237) {
    Out-Log “Error: DeployVM script requires PowerCLI version 5.5 R2 (Build 1649237) or later” “Red”
    Out-Log “PowerCLI Version Detected: $((Get-PowerCLIVersion).UserFriendlyVersion)” “Red”
    Out-Log “Exiting…`n`n” “Red”
    Exit
    }

    # Test to ensure csv file is available
    If ($csvfile -eq “” -or !(Test-Path $csvfile) -or !$csvfile.EndsWith(“DeployVM.csv”)) {
    Out-Log “Path to DeployVM.csv not specified…prompting`n” “Yellow”
    $csvfile = Read-OpenFileDialog “Locate DeployVM.csv” “C:\” “DeployVM.csv|DeployVM.csv”
    }
    If ($csvfile -eq “” -or !(Test-Path $csvfile) -or !$csvfile.EndsWith(“DeployVM.csv”)) {
    Out-Log “`nStill can’t find it…I give up” “Red”
    Out-Log “Exiting…” “Red”
    Exit
    }
    Out-Log “Using $csvfile`n” “Yellow”
    # Make copy of DeployVM.csv
    If (!(Test-Path $deployedDir)) {New-Item -ItemType directory -Path $deployedDir | Out-Null}
    Copy-Item $csvfile -Destination $deployedFile | Out-Null
    # Import VMs from csv
    $newVMs = Import-Csv $csvfile
    $newVMs = $newVMs | Where {$_.Name -ne “”}
    [INT]$totalVMs = @($newVMs).count
    Out-Log “New VMs to create: $totalVMs” “Yellow”
    # Check to ensure csv is populated
    If ($totalVMs -lt 1) {
    Out-Log “`nError: No entries found in DeployVM.csv” “Red”
    Out-Log “Exiting…`n” “Red”
    Exit
    }
    # Show input and ask for confirmation, unless -auto was used
    If (!$auto) {
    $newVMs | Out-GridView -Title “VMs to be Created”
    $continue = Read-Host “`nContinue (y/n)?”
    If ($continue -notmatch “y”) {
    Out-Log “Exiting…” “Red”
    Exit
    }
    }
    # Connect to vCenter server
    If ($vcenter -eq “”) {$vcenter = Read-Host “`nEnter vCenter server FQDN or IP”}
    Try {
    Out-Log “`nConnecting to vCenter – $vcenter`n`n” “Yellow”
    Connect-VIServer $vcenter -EA Stop | Out-Null
    } Catch {
    Out-Log “`r`n`r`nUnable to connect to $vcenter” “Red”
    Out-Log “Exiting…`r`n`r`n” “Red”
    Exit
    }
    # Start provisioning VMs
    $v = 0
    Out-Log “Deploying VMs`n” “Yellow”
    Foreach ($VM in $newVMs) {
    $Error.Clear()
    $vmName = $VM.Name
    $v++
    $vmStatus = “[{0} of {1}] {2}” -f $v, $newVMs.count, $vmName
    Write-Progress -Activity “Deploying VMs” -Status $vmStatus -PercentComplete (100*$v/($newVMs.count))
    # Create custom OS Custumization spec
    If ($vm.DHCP -match “true”) {
    $spec = Get-OSCustomizationSpec -Name $VM.CustSpec
    $tempSpec = $spec | New-OSCustomizationSpec -Name temp$vmName
    $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
    -IpMode UseDhcp | Out-Null
    } Else {
    If ($VM.OSType -eq “Windows”) {
    $spec = Get-OSCustomizationSpec -Name $VM.CustSpec
    $tempSpec = $spec | New-OSCustomizationSpec -Name temp$vmName
    $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
    -IpMode UseStaticIP -IpAddress $VM.IPAddress -SubnetMask $VM.SubnetMask `
    -Dns $VM.pDNS,$VM.sDNS -DefaultGateway $VM.Gateway | Out-Null
    } ElseIF ($VM.OSType -eq “Linux”) {
    $spec = Get-OSCustomizationSpec -Name $VM.CustSpec
    $tempSpec = $spec | New-OSCustomizationSpec -Name temp$vmName
    $tempSpec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
    -IpMode UseStaticIP -IpAddress $VM.IPAddress -SubnetMask $VM.SubnetMask `
    -DefaultGateway $VM.Gateway | Out-Null
    }
    }
    # Create VM
    Out-Log “Deploying $vmName”
    $taskTab[(New-VM -Name $VM.Name -ResourcePool $VM.ResourcePool -Location $VM.Folder -Datastore $VM.Datastore -DiskStorageFormat $VM.DiskStorageFormat`
    -Notes $VM.Notes -Template $VM.Template-OSCustomizationSpec temp$vmName -RunAsync -EA SilentlyContinue).Id] = $VM.Name
    # Remove temp OS Customization spec
    Remove-OSCustomizationSpec -OSCustomizationSpec temp$vmName -Confirm:$false
    # Log errors
    If ($Error.Count -ne 0) {
    If ($Error.Count -eq 1 -and $Error.Exception -match “‘Location’ expects a single value”) {
    $vmLocation = $VM.Folder
    Out-Log “Unable to place $vmName in desired location, multiple $vmLocation folders exist, check root folder” “Red”
    } Else {
    Out-Log “`n$vmName failed to deploy!” “Red”
    Foreach ($err in $Error) {
    Out-Log “$err” “Red”
    }
    $failDeploy += @($vmName)
    }
    }
    }
    Out-Log “`n`nAll Deployment Tasks Created” “Yellow”
    Out-Log “`n`nMonitoring Task Processing” “Yellow”
    # When finsihed deploying, reconfigure new VMs
    $totalTasks = $taskTab.Count
    $runningTasks = $totalTasks
    while($runningTasks -gt 0){
    $vmStatus = “[{0} of {1}] {2}” -f $runningTasks, $totalTasks, “Tasks Remaining”
    Write-Progress -Activity “Monitoring Task Processing” -Status $vmStatus -PercentComplete (100*($totalTasks-$runningTasks)/$totalTasks)
    Get-Task | % {
    if($taskTab.ContainsKey($_.Id) -and $_.State -eq “Success”){
    #Deployment completed
    $Error.Clear()
    $vmName = $taskTab[$_.Id]
    Out-Log “`n`nReconfiguring $vmName” “Yellow”
    $VM = Get-VM $vmName
    $VMconfig = $newVMs | Where {$_.Name -eq $vmName}
    # Set CPU and RAM
    Out-Log “Setting vCPU(s) and RAM on $vmName” “Yellow”
    $VM | Set-VM -NumCpu $VMconfig.CPU -MemoryGB $VMconfig.RAM -Confirm:$false | Out-Null
    # Set port group on virtual adapter
    Out-Log “Setting Port Group on $vmName” “Yellow”
    If ($VMconfig.NetType -match “vSS”) {
    $network = @{
    ‘NetworkName’ = $VMconfig.network
    ‘Confirm’ = $false
    }
    } Else {
    $network = @{
    ‘Portgroup’ = $VMconfig.network
    ‘Confirm’ = $false
    }
    }
    $VM | Get-NetworkAdapter | Set-NetworkAdapter @network | Out-Null
    # Add additional disks if needed
    If ($VMConfig.Disk2 -gt 1) {
    Out-Log “Adding additional disk 2 on $vmName – don’t forget to format within the OS” “Yellow”
    $VM | New-HardDisk -CapacityGB $VMConfig.Disk2 -Datastore $VMconfig.Datastore2 -StorageFormat $VMconfig.DiskStorageFormat2 -Persistence persistent | Out-Null
    }
    If ($VMConfig.Disk3 -gt 1) {
    Out-Log “Adding additional disk 3 on $vmName – don’t forget to format within the OS” “Yellow”
    $VM | New-HardDisk -CapacityGB $VMConfig.Disk3 -Datastore $VMconfig.Datastore3 -StorageFormat $VMConfig.DiskStorageFormat3 -Persistence persistent | Out-Null
    }
    If ($VMConfig.Disk4 -gt 1) {
    Out-Log “Adding additional disk 4 on $vmName – don’t forget to format within the OS” “Yellow”
    $VM | New-HardDisk -CapacityGB $VMConfig.Disk4 -Datastore $VMconfig.Datastore4 -StorageFormat $VMConfig.DiskStorageFormat4 -Persistence persistent | Out-Null
    }
    # Boot VM
    If ($VMconfig.Boot -match “true”) {
    Out-Log “Booting $vmName” “Yellow”
    $VM | Start-VM -EA SilentlyContinue | Out-Null
    }
    $taskTab.Remove($_.Id)
    $runningTasks–
    If ($Error.Count -ne 0) {
    Out-Log “$vmName completed with errors” “Red”
    Foreach ($err in $Error) {
    Out-Log “$Err” “Red”
    }
    $failReconfig += @($vmName)
    } Else {
    Out-Log “$vmName is Complete” “Green”
    $successVMs += @($vmName)
    }
    }
    elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq “Error”){
    # Deployment failed
    $failed = $taskTab[$_.Id]
    Out-Log “`n$failed failed to deploy!`n” “Red”
    $taskTab.Remove($_.Id)
    $runningTasks–
    $failDeploy += @($failed)
    }
    }
    Start-Sleep -Seconds 10
    }
    #——————————————————————–
    # Close Connections
    Disconnect-VIServer -Server $vcenter -Force -Confirm:$false
    #——————————————————————–
    # Outputs
    Out-Log “`n**************************************************************************************”
    Out-Log “Processing Complete” “Yellow”
    If ($successVMs -ne $null) {
    Out-Log “`nThe following VMs were successfully created:” “Yellow”
    Foreach ($success in $successVMs) {Out-Log “$success” “Green”}
    }
    If ($failReconfig -ne $null) {
    Out-Log “`nThe following VMs failed to reconfigure properly:” “Yellow”
    Foreach ($reconfig in $failReconfig) {Out-Log “$reconfig” “Red”}
    }
    If ($failDeploy -ne $null) {
    Out-Log “`nThe following VMs failed to deploy:” “Yellow”
    Foreach ($deploy in $failDeploy) {Out-Log “$deploy” “Red”}
    }
    $finishtime = Get-Date -uformat “%m-%d-%Y %I:%M:%S”
    Out-Log “`n`n”
    Out-Log “**************************************************************************************”
    Out-Log “$scriptName`t`t`t`t`tFinish Time:`t$finishtime”
    Out-Log “**************************************************************************************”

    ———–end of script—————–

    Reply
  17. Adrian Sahota

    Hello, I’ve been using the script for a few weeks now, saved a lot of time and effort on new builds of environments, so firstly thanks!

    When running the script to deploy, say, 20 VM’s, What i see happening is that first 4 or 5 machines are started, then shortly afterwards all other machines are then started for deployment. What rules/process govern the number of machines that are deployed at once? ie, if i want the system to build 5 systems at a time out of a batch?

    Regards
    Adrian

    Reply
    1. smasterson Post author

      Hi There
      Currently there are no throttling rules within the script (though there probably should be).
      You might want to check the vCenter tasks to see if any are queuing

      Reply
  18. Cameron

    Great script, saves me tons of time! Is there a way to select additional datastores for Disk2,Disk3 type deployments.

    Reply
  19. Mike

    Looks like this is a very nice script, however, having issues with it and it fails. Running on vCenter 6 and PowerCLI 6.0 R2 Below is error:

    testvm failed to deploy!
    Index operation failed; the array index evaluated to null.
    4/13/2016 10:41:32 AM New-VM VIContainer parameter: Could not find any of the objects specified by name.

    Any ideas on why? I cant seem to figure it out

    Reply
    1. smasterson Post author

      Hi Mike
      I haven’t had a chance to use on v6 yet – may or may not be the issue here.
      It looks as though it does not like the item specified in the csv under ResourcePool. This should contain the name of a Resource Pool, Host or Cluster.

      Reply
  20. Mor

    Hi,
    i’m facing some problems and i hope you can help.
    i’m using 3 different vcenter servers (selected by params in the csv).
    2 are ok but the third recently failing with vm exist. the thing is that the vm doesn’t exist until the new-vm command, and then in the vc it looks like there are two attempts to clone the vm, 2 seconds apart (the first start the clone and 2 secs later there is a failure that the vm exist).
    i can’t find any thing that will explain this behavior, not in the script and not in the vc logs.
    any thoughts/ideas?

    thanks
    mor

    Reply
  21. sudhakar

    i used this script and its working. But when i mention cluster names for Host and datastore its not wworking. i have to give specific host and lun which is again making issue on resource usages

    Reply
    1. smasterson Post author

      This shouldn’t be an issue as clusters and datastore clusters should both be supported.
      What version of vSphere/PowerCLI/PowerShell are you running?

      Reply
  22. Jawed Abbasi

    Hi I am having issue with this script can someone help please.
    I have ESX clusters CL01 and CL02; both clusters have resource pool called “Infrastructure”.
    In my csv under Folder option I have CL02 and under resourcepool option I have “Infrastructure” but script fails with following errors:

    Deploying vm1-jaw
    Index operation failed; the array index evaluated to null.
    At C:\Users\jabbasi\Documents\DeployVM-ShawnM\DeployVMs.ps1:265 char:5
    + $taskTab[(New-VM -Name $VM.Name -ResourcePool $VM.ResourcePool -Location $VM …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

    vm1-jaw failed to deploy!
    Index operation failed; the array index evaluated to null.
    6/2/2016 9:54:00 AM New-VM VIContainer parameter: Could not find any of the objects specified by name.
    6/2/2016 9:54:00 AM New-VM The specified parameter ‘ResourcePool’ expects a single value, but your name criteria ‘Infrastructure’ corresponds to multiple values.
    Deploying vm2-jaw
    Index operation failed; the array index evaluated to null.
    At C:\Users\jabbasi\Documents\DeployVM-ShawnM\DeployVMs.ps1:265 char:5
    + $taskTab[(New-VM -Name $VM.Name -ResourcePool $VM.ResourcePool -Location $VM …

    Reply
    1. smasterson Post author

      Hello
      It looks like I can see two issues
      1) Do you have a blue folder called CL02? You mention you have a cluster called CL02 – this is not a blue folder
      2) It appears you have multiple resources called Infrastructure – this is going to error as it doesn’t know which Infrastructure to place the VM in

      HTH

      Reply
      1. Jawed Abbasi

        Hi Shawn
        Clusters are not really shown like a folder; hierarchy I have is

        DC (which is building) > CL01 (which is ICON with 3 Computers) > ResourcePool (infrastructure) that is a blue Circle
        DC (which is building) > CL02 (which is ICON with 3 Computers) > > ResourcePool (infrastructure) that is a blue Circle

  23. Jawed Abbasi

    Hi Shawn
    Clusters are not really shown like a folder; hierarchy I have is

    DC (which is building) > CL01 (which is ICON with 3 Computers) > ResourcePool (infrastructure) that is a blue Circle
    DC (which is building) > CL02 (which is ICON with 3 Computers) > > ResourcePool (infrastructure) that is a blue Circle

    Reply
    1. smasterson Post author

      It sounds as though you are looking at the ‘Hosts and Clusters’ view. Using your description I would say CL01 and CL02 are Hosts.

      Try switching to the ‘VMs and Templates’ view – this is where you will find blue folders (if there are any)

      Reply
  24. JuanJose Vidañez García

    Hello Shawn Masterso,
    I have created the version 1.6 of the script and its available at https://github.com/Vidanez/DeployVMs/blob/master/DeployVM.ps1
    NOTES
    Author: Shawn Masterson
    Created: May 2014
    Version: 1.2

    Author: JJ Vidanez
    Created: Nov 2014
    Version: 1.3
    Add creation onthefly for customization Spec for linux systems
    Ability to create machines names and guest hostname using different names
    Added a value to find out the kind of disk because powercli bug for SDRS reported at https://communities.vmware.com/message/2442684#2442684
    Remove the dependency for an already created OScustomization Spec

    Author: JJ Vidanez
    Created: Jul 2015
    Version: 1.4
    Adding domain credential request for Windows systems

    Author : Simon Davies – Everything-Virtual.com
    Created : May 2016
    Version: 1.5
    Adding AD Computer Account Creation in specified OU’s for VM’s at start of deployment – Yes even Linux as that was a requirement
    It’s possible to restrict this to just Windows VM’s by removing the comment at line #261

    Author: JJ Vidanez & Robert Rowan
    Created: Jun 2016
    Version: 1.6
    Fixed issue to deploy just one VM
    Adding banner for each credential to show the domain where credentials are set
    If OU parameter is defined at the OU create the object on AD where the machine is register Linux and Windows

    Reply
  25. Andrew

    Hey Shawn, great script, I owe you a beer! Quick question, do you know of a way to run some Linux commands at VM creation time in a similar fashion to AWS’ user data or a kickstart file’s %post section?

    Reply
  26. Adam Brown

    Newest version 1.6 doesn’t like any vCenter i input “unable to connect to vCenter”. Also our “Administrator” account PW starts with a bang “!” and it seems the script errors out when inputting the exclamation…Still using version 1.4 and it works just fine…

    Reply
    1. smasterson Post author

      Hi Adam

      Might need some clarification here as the script has only v1.0 (original) and v1.2.1 (latest).
      All versions of the script simply connect to a vcenter using the account running the command via this simple line:
      Connect-VIServer $vcenter -EA Stop
      (Where $vcenter is the server name/IP given when prompt)

      Reply
  27. Wayne

    I’m running the script and it is deploying the VMs OK but when it comes to re-configure them it fails saying “Get-VM VM with name’XXXXXXX’ was not found using the specified filter(s).”
    I’m not sure if this is because the name of the VM as seen in vSphere (in the csv file the NameVM field) and the the actual servername (in the csv file the Name field) are different (long story relating to different departments requirements).
    The NameVM field = test01vm
    The Name field = TestWin01VM.

    Output error:

    Reconfiguring TestWin01VM
    Get-VM : 10/13/2016 3:10:34 PM Get-VM VM with name ‘TestWin01VM’ was not found using the
    specified filter(s).
    At C:\vmdeploy\csvdeploy_1_2.ps1:357 char:13
    + $VM = Get-VM $vmName
    + ~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (:) [Get-VM], VimException
    + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Co
    mmands.GetVM

    Setting vCPU(s) and RAM on TestWin01VM
    Setting Port Group on TestWin01VM
    Adding additional disk on TestWin01VM – don’t forget to format within the OS
    Booting TestWin01VM
    TestWin01VM completed with errors
    10/13/2016 3:10:34 PM Get-VM VM with name ‘TestWin01VM’ was not found using the specified filter(s).

    Reply
    1. smasterson Post author

      It appears as though you have customized the script as currently it does not have the ability to account for the VM name being different from the OS name

      Reply
      1. Wayne

        Thanks to spotting the.
        I somehow got a copy that was saying it was version 1.3.
        using 1.2 the above error disappears.Now I have another issue.
        It is unable to set the portgroup.
        I get the following error:

        Set-NetworkAdapter : 10/14/2016 8:40:57 AM Set-NetworkAdapter The specified parameter ‘Portgroup’ expects a
        single value, but your name criteria ‘10.105.19_Corp_Test’ corresponds to multiple values.
        At C:\vmdeploy\csvdeploy.ps1:319 char:31
        + $VM | Get-NetworkAdapter | Set-NetworkAdapter @network | Out-Nu …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidResult: (System.Collecti…dObjectInterop]:List`1) [Set-NetworkAdapter], VimExcep
        tion
        + FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_MoreResultsThanExpected,VMware.VimAutomation.ViC
        ore.Cmdlets.Commands.VirtualDevice.SetNetworkAdapter

        Set-NetworkAdapter : 10/14/2016 8:40:57 AM Set-NetworkAdapter Value cannot be found for the mandatory
        parameter Portgroup
        At C:\vmdeploy\csvdeploy.ps1:319 char:31
        + $VM | Get-NetworkAdapter | Set-NetworkAdapter @network | Out-Nu …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Set-NetworkAdapter], VimException
        + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.VirtualDevice.
        SetNetworkAdapter

        Any suggestions?

      2. smasterson Post author

        This could be a couple of things
        1) Do you have multiple objects by the same name, even different types of objects?(10.105.19_Corp_Test)
        2) Do you have multiple connections open? (Can check with $defaultVIServers)
        3) You could try using Get-VirtualPortGroup (or Get-VDPortGroup if using vDS) to see what is returned for the name (ex: Get-VirtualPortGroup -Name “10.105.19_Corp_Test”)

      3. Wayne

        When I run Get-VirtualPortGroup -Name “10.105.19_Corp_Test” I get the following:

        PowerCLI C:\> Get-virtualPortGroup -Name “10.105.19_Corp_test”

        Name Key VLanId PortBinding NumPorts
        —- — ———- ————— ————–
        10.105.19_Corp_Test key-vim.host.PortGroup-10.1… 19
        10.105.19_Corp_Test key-vim.host.PortGroup-10.1… 19
        10.105.19_Corp_Test key-vim.host.PortGroup-10.1… 19

        The cluster I’m using has 3 hosts and each host has the same PortGroups configured on them.
        This is the standard way our clusteres are configured.
        I need it to be able to build the VM on any of the hosts and use the same PortGroup whichever host it uses.

      4. smasterson Post author

        Not sure what is going on here. I just ran a fresh test and had no issues on vSphere 5.5/PowerCLI 5.5.
        At this point even though the script ended with error, the VM should actually be created, so we can do some tests. Try the following and see what you get:
        $vmName = “NameOfCreatedVM”
        $networkName = “10.105.19_Corp_Test”
        $VM = Get-VM $vmName
        $VM | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $networkName

        That is pretty much the standard was to assign a network name to a VM adapter. Beyond that, I am not sure…maybe try this link for more info:
        https://communities.vmware.com/thread/307621?start=0&tstart=0

  28. djchinzz

    Wonderful Script, i have one question for non applicable fields what i need to mention in csv. for example, we don’t user resource pool,SDRS & other things. Please advise.

    Reply
    1. smasterson Post author

      Optional fields are marked as such in the Notes (optional).
      Without DRS/sDRS you’ll need to specify a particular Host or Datastore for the VM as opposed to a Cluster or Datastore Cluster.

      Reply
  29. Glynn Williams

    I love your script but am having some issues. Well only one issue now, I have worked through the other issues I had. Now it all comes down to the NIC. As soon as I deploy a VM I get a bunch of errors about setting the NIC customization.

    Set-OSCustomizationNicMapping : 4/21/2017 1:37:27 PM Set-OSCustomizationNicMapping
    Required property ip is missing from data object of type CustomizationIPSettings
    while parsing serialized DataObject of type vim.vm.customization.IPSettings
    at line 1, column 2058
    while parsing property “adapter” of static type CustomizationIPSettings
    while parsing serialized DataObject of type vim.vm.customization.AdapterMapping
    at line 1, column 2043
    while parsing property “nicSettingMap” of static type ArrayOfCustomizationAdapterMapping
    while parsing serialized DataObject of type vim.vm.customization.Specification
    at line 1, column 586
    while parsing property “spec” of static type CustomizationSpec
    while parsing serialized DataObject of type vim.CustomizationSpecItem
    at line 1, column 335
    while parsing call information for method OverwriteCustomizationSpec
    at line 1, column 218
    while parsing SOAP body
    at line 1, column 207
    while parsing SOAP envelope
    at line 1, column 38
    while parsing HTTP request for method overwrite
    on object of type vim.CustomizationSpecManager
    at line 1, column 0
    At C:\Users\99gwilliams\Desktop\EBI VM Deploy\DeployVM.ps1:244 char:53
    + … pec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping `
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Set-OSCustomizationNicMapping], InvalidRequest
    + FullyQualifiedErrorId : Client20_VMGuestServiceImpl_ModifyServersideSpec_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.SetOSCustomizationNicMapping

    I have DHCP set to true in the CSV, I have also tried setting it to true but still putting IP information in. I need it to set the DNS, but use DHCP for everything else. In my Customization I previously had it set up to use DHCP but set DNS, per your recommendation at the top I told it to use typical settings instead.

    The VM continues to deploy but once completed the NIC is not set to CONNECTED or CONNECT AT POWER ON. I need the NIC connected in order to finish out the customization that joins it to the domain.

    Any help would be greatly appreciated.

    Here is the CSV file.

    Name,Boot,OSType,Template,CustSpec,Folder,ResourcePool,CPU,RAM,Disk2,Disk3,Disk4,Datastore,DiskStorageFormat,NetType,Network,DHCP,IPAddress,SubnetMask,Gateway,pDNS,sDNS,Notes
    IND01-GlynnTest,FALSE,Windows,EBI-Template-DomainJoin,EBI-Virtual-Desktops,EBI Remote Desktops,NYC_Nehelem,2,6,,,,vnx_cluster,thin,vDS,VLAN62,TRUE,,,,8.8.8.8,4.4.4.4,

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s