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 15+ years experience in IT, primary focus: virtualization and modern worksplace.

More Posts - Website

Follow Me:
TwitterLinkedIn

40 thoughts on “VMware: Deploy multiple VM’s from template with PowerCLI

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

  3. # 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)
    }

  4. 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

  5. Pingback: VMware vCenter使用克隆及模板部署虚拟机 | 存储人生
  6. 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

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

  8. 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)
    ===========

  9. 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
    }

  10. 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.

  11. 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

  12. 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

  13. @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

  14. 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

  15. @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

  16. @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

  17. @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

  18. 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.

  19. #############################################################
    # 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

  20. 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

  21. Hi Everyone,

    Looking for script which can create multiple vms using template and use oscustomization from Vcenter and take IP address and name of the VMS

Leave a Reply

Your email address will not be published. Required fields are marked *