new1234.jpg
Home > VMware > VMware: Deploy multiple VM’s from template with PowerCLI

VMware: Deploy multiple VM’s from template with PowerCLI

Last week I was working on a new project, they asked me to install 5 new fileservers based on Windows 2008R2, I installed a new VM and converted it to a template, next I configured a template in “Customization Specifications Manager” with the following details:

Customization template:

Registration information: name company

Computer name: Use the virtual machine name (important)

Product key: Didn’t need it because I’ve configured KMS

Password: Company default local administrator password, selected: Automatically login as the Administrator: 2

Timezone: GMT+0100 (Amsterdam)

Runonce: none

Network: Typical settings

Workgroup or Domain: selected to auto join the domain with domain administrator credentials + domain name (important)

Operation System Options: Selected: Generate New Security ID (SID)

VM template settings:

Hard disk: 40 GB with only OS configured with company standard policy

VMware tools: Latest, this must be installed for Specification Template and NIC

Network: VMXNET3 (needed VMware Tools for driver)

Script: (saved as: FileserverDeploy.ps1)

-vmhost = Target host;

-Name = Name of new VM;

-Template: From wich template you want to deploy the new VM;

-Datastore: Target datastore to place the new VM;

-OSCustomizationspec = Wich “prep” template you want to deploy the new VM;

New-vm -vmhost esx04.vmpros.local -Name FS-SVR01 -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template
New-vm -vmhost esx04.vmpros.local -Name FS-SVR02 -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template
New-vm -vmhost esx04.vmpros.local -Name FS-SVR03 -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template
New-vm -vmhost esx04.vmpros.local -Name FS-SVR04 -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template
New-vm -vmhost esx04.vmpros.local -Name FS-SVR05 -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template

PowerCLI:

Running the script:

image

image

image

Final result:

image

The 5 fileservers deployed from template and joined the domain.. great!

sanderdaems

Sander Daems is founder and author of this blog and working as a Lead (Sr.) Consultant by UNICA ICT Solutions. Sander has over 15 years experience in IT, primary focus: virtualization and modern worksplace.

More Posts - Website

Follow Me:
TwitterLinkedIn

  1. January 17th, 2011  (Quote) at 15:44  (Quote) | #1

    You might also consider using some of the great features of PowerShell to make this even nicer:

    1..5 | Foreach {
    New-vm -vmhost esx04.vmpros.local -Name FS-SVR$_ -Template WIN2008R2_Template -Datastore datastore2 -OSCustomizationspec WIN2008R2_Template
    }

  2. January 17th, 2011  (Quote) at 15:51  (Quote) | #2

    @Alan Renouf

    Cool, thanks Alan! Much easier!

  3. Peter Riters
    February 6th, 2011  (Quote) at 13:17  (Quote) | #3

    Great this helped me alot

  4. katehudsob
    February 8th, 2011  (Quote) at 07:39  (Quote) | #4

    i like it VMware: Deploy multiple VM’s from template with PowerCLI | VMpros now im your rss reader

  5. vinod
    February 12th, 2011  (Quote) at 00:42  (Quote) | #5

    I have a task to deploy multiple VMs with sequential naming convention, in multiple ESX servers which will use same template but different datastore. can you help with powercli script for same? Thanks! Vinod@Alan Renouf

  6. Drew
    March 9th, 2011  (Quote) at 17:45  (Quote) | #6

    Anyway to deploy with static IPs? IE add the IP address to the .ps1 file?

  7. Brent
    April 20th, 2011  (Quote) at 19:33  (Quote) | #7

    Thanks for the tips here. Anybody know how to automatically set the datastore to the one with the most free space?

  8. Tim
    May 10th, 2011  (Quote) at 16:34  (Quote) | #8

    # Notes: deploy.txt format is as follows,
    # serverA
    # serverB
    # serverC
    # serverETC
    #
    ##################################################################################################################################################
    #
    # Define Variables
    $strNewVMName = Get-content “c:\ps\deploy.txt”
    $strTemplate = “TEMPLATE NAME”
    $strDestinationHost = “HOST NAME”
    $strCustomSpec = “CUSTOMIZATION SPEC MANAGER ANSWER FILE”
    $strDatastore = “Datastore Name”
    #
    #For each loop will increment for every string contained with in deploy.txt
    Foreach ($strServer in $strServers)
    #
    # The command below will create the new VM using the name from deploy.txt using the template defined in $strTemplate
    # to the host defined in $strDestinationHost using the thin storage format and the customization template defined in $strCustomSpec.
    {
    New-VM -Name $strNewVMName -Template $(get-template $strTemplate) -VMHost $(Get-VMHost $strDestinationHost) -Datastore $(Get-Datastore $strDatastore) -DiskStorageFormat Thin -OSCustomizationSpec $(Get-OSCustomizationSpec $strCustomSpec)
    }

  9. silvan
    June 9th, 2011  (Quote) at 08:32  (Quote) | #9

    Thanks for this help

    one more questions – is there a possibility to change the virtual hardware during the deployment from the template.

    there is the option in the GUI -> Edit virtual hardwarae (Experimental)

    Does anyone know this?

    Thanks a lot

  10. jonathan
    June 20th, 2011  (Quote) at 05:33  (Quote) | #10

    Many thanks. I was using Google to seach how to deploy multiple VM’s, then I am here. Really useful.

  11. Tom Casull
    July 21st, 2011  (Quote) at 23:50  (Quote) | #11

    Thank you all for the post. This is very handy for creating several VMs.
    I have a question, I would like to have 100+ servers created using the same vm template, yet I would like it to assign the server and IP from a csv file. Is the possible?
    something like Server-xyz, IP 192.168.1.xxx….. Server-abc, IP 10.123.5.xxx
    Thank you for any ideas.
    Tom

  12. Gurjit Dhillon
    October 27th, 2011  (Quote) at 22:45  (Quote) | #12

    Hi,

    First of all thanks for the script, your script works like a charm. one question, if I configure script to create 10 vpc , script starts to deploy 10 vpc together, is it possible to create 3 vPC at a time and other will be in queue, once first 3 is done, new 3 vPC will start for deployment, like wise it will go.
    May be we can start with 1 vpc at a time.

    I believe some body must have already done this.

    Regards
    Gurjit Dhillon

  13. swapnil
    November 2nd, 2011  (Quote) at 11:32  (Quote) | #13

    I am getting following error while executing the above script.
    =========
    New-VM : Cannot convert ‘System.Object[]’ to the type ‘System.String’ required
    by parameter ‘Name’. Specified method is not supported.
    At C:\Users\Administrator\Desktop\scripts\deploy.ps1:8 char:13
    + New-VM -Name <<<< $strNewVMName -Template $(get-template $strTemplate) -VMHo
    st $(Get-VMHost $strDestinationHost) -Datastore $(Get-Datastore $strDatastore)
    -DiskStorageFormat Thin -OSCustomizationSpec $(Get-OSCustomizationSpec $strCust
    omSpec)
    ===========

  14. Gurjit Dhillon
    November 2nd, 2011  (Quote) at 23:10  (Quote) | #14

    Hi Swapnil,

    try below script.

    # Define Variables

    $NameVM =”vmtest00″
    $strTemplate = “vPC template Win7 BNL 3.0.b5”
    $strDestinationHost = “vmnlutr01-host02.capgemini.nl”
    $strCustomSpec = “vPC Vista-Win7 customization”
    $strDatastore = “UTR-VPC-pool09”
    $strLocation = “vPCs BPO”
    $strPool = “vPCs UTR”

    # Mention number of VM to create
    $HOW_MANY_TO_CREATE=2

    $Date=get-date -uformat “%Y%m%d”
    $NumArray = (1..$HOW_MANY_TO_CREATE)
    #$NumArray = $HOW_MANY_TO_CREATE

    for ([int]$seq=1;$seq -le $HOW_MANY_TO_CREATE;$seq++)
    {$string = $NameVM + ($seq.tostring(“0##”)) #orginale
    “Creating $string”
    New-VM -Name $string -Template $(get-template $strTemplate) -location (get-folder $strLocation) -pool (get-resourcepool $strPool) -VMHost $(Get-VMHost $strDestinationHost) -Datastore $(Get-Datastore $strDatastore) -OSCustomizationSpec $(Get-OSCustomizationSpec $strCustomSpec) | Start-VM -RunAsync
    }

  15. swapnil
    November 16th, 2011  (Quote) at 12:07  (Quote) | #15

    Hi,

    But I want to keep server list file separately and just put server names over there instead of in the script…Please assist.

  16. santhosh pani
    November 17th, 2011  (Quote) at 10:17  (Quote) | #16

    hi, superb man

    we have same kind of work in our organization to deploy multiple vms from Template. from one temp to 24 vms, which kind of precautions we have to take.

    the thing is i have bit knowledge on powercli and i dont which tool to develop scripts of powercli.

  17. santhosh pani
    November 17th, 2011  (Quote) at 10:18  (Quote) | #17

    what is this and how to use this ”-OSCustomizationspec WIN2008R2_Template”

  18. mihir
    March 7th, 2012  (Quote) at 06:21  (Quote) | #18

    does this script automatically install the OSs on the VMs? where there’s no need to manually go install the os on each VM??
    coz now i have a script which can automatically create ‘n’ VMs and link the iso image to them all….but i have to go and install the OS on each:(
    plzz help with a script to execute the above query!thanks

  19. bgonzales
    April 6th, 2012  (Quote) at 18:16  (Quote) | #19

    Did you ever get the script to accomplish deployemnt to the datastore with the most available space? I have the same type of requirement in my environment. Thanks for your help!

    BrentG

    @Brent

  20. bvi1998
    August 2nd, 2012  (Quote) at 17:44  (Quote) | #20

    @bgonzales

    Here is how I get a datastore with enough space. I probably can’t help debug this if you run in to errors but thought I’d share:

    # Create new properties for Datastore calculations
    New-VIProperty -Name UsedGB -ObjectType Datastore `
    -Value {
    param($ds)

    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace)/1GB,1)
    } `
    -BasedONextensionProperty ‘Summary’ `
    -Force

    New-VIProperty -Name ProvisionedGB -ObjectType Datastore `
    -Value {
    param($ds)

    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace + $ds.ExtensionData.Summary.Uncommitted)/1GB,1)
    } `
    -BasedONextensionProperty ‘Summary’ `
    -Force

    # Get datastore like a particular name (win*)and where used and provisioned are within our acceptable range
    # Selects the first one it finds
    $Datastore = Get-Datastore -VMHost $VMHost | where {$_.Name -like “*win*”} |
    where-object {($_.UsedGB) -le 710 -and $_.ProvisionedGB -le 1360}|
    Select-Object -first 1

  21. bvi1998
    August 2nd, 2012  (Quote) at 18:04  (Quote) | #21

    bvi1998 :
    @bgonzales
    Here is how I get a datastore with enough space. I probably can’t help debug this if you run in to errors but thought I’d share:

    (edited the post to add where I the vmhost)
    #Get an ESX host at random to find datastores
    $VMHost = Get-Cluster $ClusterName |Get-VMHost | Get-Random

    # Create new properties for Datastore calculationsNew-VIProperty -Name UsedGB -ObjectType Datastore `-Value {param($ds)
    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace)/1GB,1)} `-BasedONextensionProperty ‘Summary’ `-Force
    New-VIProperty -Name ProvisionedGB -ObjectType Datastore `-Value {param($ds)
    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace + $ds.ExtensionData.Summary.Uncommitted)/1GB,1)} `-BasedONextensionProperty ‘Summary’ `-Force
    # Get datastore like a particular name (win*)and where used and provisioned are within our acceptable range# Selects the first one it finds$Datastore = Get-Datastore -VMHost $VMHost | where {$_.Name -like “*win*”} |where-object {($_.UsedGB) -le 710 -and $_.ProvisionedGB -le 1360}|Select-Object -first 1

  22. bvi1998
    August 2nd, 2012  (Quote) at 18:08  (Quote) | #22

    @bvi1998
    bvi1998 :
    @bgonzales
    Here is how I get a datastore with enough space. I probably can’t help debug this if you run in to errors but thought I’d share:

    (edited the post to add where I the vmhost)
    #Get an ESX host at random to find datastores
    $VMHost = Get-Cluster $ClusterName |Get-VMHost | Get-Random

    # Create new properties for Datastore calculations
    New-VIProperty -Name UsedGB -ObjectType Datastore `-Value {param($ds)
    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace)/1GB,1)} `-BasedONextensionProperty ‘Summary’ `-Force

    New-VIProperty -Name ProvisionedGB -ObjectType Datastore `-Value {param($ds)
    [Math]::Round(($ds.ExtensionData.Summary.Capacity – $ds.ExtensionData.Summary.FreeSpace + $ds.ExtensionData.Summary.Uncommitted)/1GB,1)} `-BasedONextensionProperty ‘Summary’ `-Force

    # Get datastore like a particular name (win*)and where used and provisioned are within our acceptable range
    # Selects the first one it finds

    $Datastore = Get-Datastore -VMHost $VMHost | where {$_.Name -like “*win*”} |where-object {($_.UsedGB) -le 710 -and $_.ProvisionedGB -le 1360}|Select-Object -first 1

  23. auqf
    August 26th, 2012  (Quote) at 09:11  (Quote) | #23

    @Tom Casull
    Get-OSCustomizationSpec Spec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress 10.10.0.1 -SubnetMask 255.255.255.0 -DefaultGateway 10.10.0.1 -AlternateGateway 10.10.0.1 -Dns 10.10.150.1 -PrimaryWins 10.10.150.2

  24. auqf
    August 26th, 2012  (Quote) at 09:35  (Quote) | #24

    @santhosh pani
    Current “** Create Win XP **”;

    $freespaceCalc = @{ Name = “FreespaceGB”; Expression = { Re: PowerCLI script to deploy vm’s from a template::Round($_.FreeSpaceMB * 1MB / 1GB ) } }

    $capacityCalc = @{ Name = “CapacityGB”; Expression = { Re: PowerCLI script to deploy vm’s from a template::Round($_.CapacityMB * 1MB / 1GB) } }

    User enters how manny agents are requred

    $agentTotal = Re: PowerCLI script to deploy vm’s from a template(Read-Host “Enter how many WinXp Agents you need.”)

    $totalXPCount = (Get-VM -Name WinXP-* | Measure-Object).Count

    if($totalXPCount -lt $agentTotal){

    Add missing XP guests

    for($adt = $totalXPCount + 1; $adt -le $agentTotal; $adt++){

    Execute the New-Vm part

    }

    }

    Get-Datastore | Select Name, $freespaceCalc, $capacityCalc |Sort-Object Name | ft -Force -AutoSize| Out-Default

    $datastore = Read-Host “What DataStore do you want to use?”

    $hostList = Get-VmHost | select Name | Sort-Object

    $i = 1

    $hostList | %{Write-Host $i “:” $_.Name; $i++}

    $hostIndex = Read-Host “Enter a number (1 -” $hostList.Count “)”

    Write-Host “You selected host” $hostIndex “with hostname” $hostList[$hostIndex – 1].Name

    $XP = Get-VM -Name WinXP-*

    $totalXPCount = @($XP).Length

    $totalXP = ($totalXPCount + 1)

    for($adt = ($totalXP + $agentTotal);$totalXP -lt $adt; $totalXP++){

    if($totalXPCount -eq $adt)

    {

    break

    }

    $machineName = “WinXP-$totalXPCount”

    $template = “XP-32 Template”

    $osspec = Get-OSCustomizationSpec $XP

    foreach ($vm in $machineName)

    {$vm = New-VM -Name $machineName -Template $template -Host $hostIndex -Datastore $datastore -OSCustomizationSpec $osspec |start-vm }

    }

    Disconnect-VIServer -Server $DefaultVIServer -Confirm:$false

  25. Sitara
    January 25th, 2014  (Quote) at 16:49  (Quote) | #25

    Hi,

    I need to deploy 150 VMs from a template. We use Spreadsheet to pass the inputs for deploying VMs.
    It would be huge input the 150 rows of data into the spreadsheet and looks messy.
    Kindly help in optimizing the same. Let me know if there is an easy way to input the details to the script?.

    Thanks in advance.

  26. Mike
    June 3rd, 2014  (Quote) at 14:11  (Quote) | #26

    @Tom Casull
    Hello Tom, have you found a solution? I am also facing the same problem…please let me know if it’s possible. Thank you!

  27. David Mitchell
    June 4th, 2014  (Quote) at 15:40  (Quote) | #27

    #############################################################
    # David Mitchell 2014/06/04
    # Script to deploy VM(s) from Template(s) and set appropriate
    # IP config for Windows VMs. Also sets # of CPUs, MemoryMB,
    # port group.
    # Moves deployed VM to specific VMs/Template blue folder.
    # Assumptions:
    # connected to viserver before running
    # Customization spec and templates in place and tested
    #############################################################

    # Syntax and sample for CSV File:
    # template,datastore,diskformat,vmhost,custspec,vmname,ipaddress,subnet,gateway,pdns,sdns,pwins,swins,datacenter,folder,stdpg,memsize,cpucount
    # template.2008ent64R2sp1,DS1,thick,host1.domain.com,2008r2CustSpec,Guest1,10.50.35.10,255.255.255.0,10.50.35.1,10.10.0.50,10.10.0.51,10.10.0.50,10.10.0.51,DCName,FldrNm,stdpg.10.APP1,2048,1

    #
    $vmlist = Import-CSV “E:\DeployVMServers.csv”

    # Load PowerCLI
    $psSnapInName = “VMware.VimAutomation.Core”
    if (-not (Get-PSSnapin -Name $psSnapInName -ErrorAction SilentlyContinue))
    {
    # Exit if the PowerCLI snapin can’t be loaded
    Add-PSSnapin -Name $psSnapInName -ErrorAction Stop
    }

    connect-viserver ESX.yourdomain.local

    foreach ($item in $vmlist) {

    # Map variables
    $template = $item.template
    $datastore = $item.datastore
    $diskformat = $item.diskformat
    $vmhost = $item.vmhost
    $custspec = $item.custspec
    $vmname = $item.vmname
    $ipaddr = $item.ipaddress
    $subnet = $item.subnet
    $gateway = $item.gateway
    $pdns = $item.pdns
    $sdns = $item.sdns
    $datacenter = $item.datacenter
    $destfolder = $item.folder
    $stdpg = $item.stdpg
    $memsize = $item.memsize
    $cpucount = $item.cpucount

    #Configure the Customization Spec info
    Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns

    #Deploy the VM based on the template with the adjusted Customization Specification
    New-VM -Name $vmname -Template $template -Datastore $datastore -DiskStorageFormat $diskformat -VMHost $vmhost | Set-VM -OSCustomizationSpec $custspec -Confirm:$false

    #Move VM to Application Group’s folder
    Get-vm -Name $vmname | move-vm -Destination $(Get-Folder -Name $DestFolder -Location $(Get-Datacenter $Datacenter))

    #Set the Port Group Network Name (Match PortGroup names with the VLAN name)
    Get-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $stdpg -Confirm:$false

    #Set the number of CPUs and MB of RAM
    Get-VM -Name $vmname | Set-VM -MemoryMB $memsize -NumCpu $cpucount -Confirm:$false

    }

    Disconnect-VIServer ESX.yourdomain.local

  28. Vettriselvan
    March 7th, 2016  (Quote) at 14:18  (Quote) | #28

    Hi,

    Thanks for the details. I have a scenario to load more than 500 VM. So i have cloned a real VM and formed a template and used it to multiply via the above script. But the VM which i cloned consumes 5 GB. DO we have any template which will have less than 2 GB. I also need OS to be installed in the VM’s. Just what to check if there are any OS which i can use which consumes less disk space.

    Thanks
    Vettri

  29. May 5th, 2016  (Quote) at 09:56  (Quote) | #29

    @Vettriselvan you should probably look at something like DSL (Damn Small Linux – http://www.damnsmalllinux.org/) as the OS of choice here.

    I am assuming that you’re just testing mass deployments?

  30. ESX
    September 13th, 2016  (Quote) at 18:31  (Quote) | #30

    @David Mitchell
    How do you run that E:\DeployVMServers.csv, and is the script PS1 format?

  1. at | #1
  2. at | #2
  3. at | #3
  4. at | #4
  5. at | #5
  6. at | #6
  7. at | #7
  8. at | #8
  9. at | #9