VMware {code} Community
ken_MSP
Contributor
Contributor

Deploy VM using a template and command line - PowerCLI and customizing Network, RAM, CPU and extra drives ?

Is it possible to deploy VMs using a template yet altering the specifications like additional RAM, CPUs and drives all using one command line?

I currently have to build VMs using our template, wait until it finishes building and then customize network settings, select customization specification file, RAM, CPUs and drives before powering it up.

I would love to script our unique custom builds with PowerCLI using one command line.  I guess I want to be able to over-ride some elements of the template while still using the OS.

We're running ESXi 5.0

Thanks in advance. 

4 Replies
MKguy
Virtuoso
Virtuoso

I do that in a custom deployment script too, it's really not difficult.

I would post the whole script if it was a bit less accommodated to our environment and less horribly coded by my hunble self, also there's probably a few better examples out there. But here are a few snippets which you should be able to recycle in your script.

First, I'm setting all the custom VM parameters like how many vCPUs etc, you could also read that from a CSV-file or something:

 $displayname = "My_Test_VM" #vCenter Name
$vcpu = 2 $memMB = 2048
$Disk1GB
= 30
$Disk2GB = 20  # 0 = no 2nd/3rd disk
$Disk3GB
= 0    # 0 = no 2nd/3rd disk $haprio = "ClusterRestartPriority" #ClusterRestartPriority, Disabled, Low, Medium, High
$prodtest
= "PROD" # PROD or TEST

$description
= "testvm scripted"
$sourcetemplate = "W2k8R2-Template" #vCenter name of the template
$responsible
= "Mr. Nameless"
$network
=  "VLAN_311" #Name of the vSSwitch/dvSwitch Portgroup
$NetIP = "10.1.1.72"
$NetMask
= "255.255.255.0"
$NetGW = "10.1.1.1"
$NetDNS
= ("10.10.1.20", "10.10.1.21", "10.10.1.22") $NetWins = "10.10.1.25" $computername = "MyNETBIOSName"
$domainfqdn
= "mydomain.local"
$localadmingroup
= "MyADAdmins"

$RunOnce = (     "net config server /SRVCOMMENT:`"$description`"",     "netsh interface set interface name=`"Local Area Connection`" newname=`"NIC1 - $NetIP`"",     "c:\install\someagent.exe /install"

)

Then I have a couple of functions or code blocks doing the actual work, here are a few (UpdateVMSettings is probably what you want):

if($prodtest -eq "PROD") {
    $cluster = (Get-Cluster ProductiveCluster)
    $datastore = (Get-DatastoreCluster MyDRSCluster)
}
elseif($prodtest -eq "TEST") {
    $cluster = (Get-Cluster TestCluster)
    $datastore = ($cluster | Get-VMHost | Get-Datastore TEST_LUN_* | Sort -Property FreeSpaceMB | Select -last 1)
}

function Get-LocalAdminCreds {
    Write-Host "Enter Password for local admin of the VM:`n"    return (Get-Credential administrator)
}

function CreateTemplateSpec {
    New-OSCustomizationSpec -Type NonPersistent -Name "Tempspec" -OSType Windows -Description "Temp scripted Spec $description" -FullName "My Name" -OrgName "My Company" -NamingScheme Fixed -NamingPrefix $computername -AdminPassword $localadmincreds.GetNetworkCredential().password -TimeZone 110 -ChangeSid -Domain $domainfqdn -DomainCredentials $adcredentials -GuiRunOnce $RunOnce -AutoLogonCount 1    Get-OSCustomizationSpec Tempspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IPAddress $NetIP -SubnetMask $NetMask -DefaultGateway $NetGW -Dns $NetDNS -Wins $NetWins}

function UpdateVMSettings {
    Write-Host "Changing Portgroup and virtual Hardware..."
    $PortGroup = ($vm | Get-VMHost | Get-VirtualPortGroup -Name $network)     Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -NetworkName $PortGroup -StartConnected $true -Confirm:$false
   
Set-VM $vm -MemoryMB $memMB -NumCpu $vcpu -Confirm:$false

   
Get-HardDisk -VM $vm | Set-HardDisk -CapacityKB ($Disk1GB * 1MB) -Confirm:$false   
    if
($Disk2GB -gt 0) { New-HardDisk -VM $vm -CapacityKB ($Disk2GB * 1MB) -Storageformat Thin -Confirm:$false }     if($Disk3GB -gt 0) { New-HardDisk -VM $vm -CapacityKB ($Disk3GB * 1MB) -Storageformat Thin -Confirm:$false }     Set-Annotation $vm -CustomAttribute "Created on" -Value (Get-Date -uformat %d.%m.%Y) -Confirm:$false
   
Set-Annotation $vm -CustomAttribute "Created by" -Value $env:username -Confirm:$false
    Set-Annotation $vm -CustomAttribute "System owner" -Value $responsible -Confirm:$false
}
New-VM -Name $displayname -Location $vclocation -ResourcePool $cluster -Datastore $datastore -Description $description -Template $sourcetemplate -OSCustomizationspec Tempspec -HARestartPriority $haprio -DiskStorageFormat Thin

The script is also taking care checking for existing AD computers, used IPs or vCenter names, updates the AD computeraccount description afterwards and adds DRS VM group membership, stuff which I've not included here for reasons mentioned above.

Here's also snippet that will run scripts inside the guest via Invoke-VMScript to add a local admins, extend C:\ and partition other disks:

function GuestScript {
    param(
        [string]$admingroup, 
        [string]$domain,
        [bool]$extend,
        [bool]$format    )

    if(($admingroup -ne "") -and ($domain -ne "")) {
        Write-Host "Adding $admingroup to local admin group..." 
        Invoke-VMScript -ScriptText "([adsi]`"WinNT://./Administrators,group`").Add(`"WinNT://$domain/$admingroup,group`")" -VM $vm -GuestCredential $localadmincreds    }

    if($extend -eq 1) {
        Write-Host "Extending partition C:\"        Invoke-VMScript -ScriptText 'out-file c:\install\diskpartscript.txt -Encoding ASCII -InputObject "select volume 2`r`n extend`r`n"' -VM $vm -GuestCredential $localadmincreds        Invoke-VMScript -ScriptText "diskpart /s c:\install\diskpartscript.txt" -ScriptType bat -VM $vm -GuestCredential $localadmincreds    }

    if($format -eq 1) {
        Write-Host "Partitioning other disks..."
       
$script = '        $NumDisks = (Get-Wmiobject -class "Win32_DiskDrive").count         for($CurrentDisk = 1; $NumDisks -gt $CurrentDisk; $CurrentDisk++) {             for($j=67; gdr($NextFreeLetter = [char]++$j) 2>$null) {}             out-file c:\install\diskpartscript.txt -Encoding ASCII -InputObject "select disk $CurrentDisk`r`n online disk noerr`r`n attributes disk clear readonly`r`n clean`r`n create partition primary`r`n format fs=ntfs quick`r`n assign letter=$NextFreeLetter"             diskpart /s c:\install\diskpartscript.txt         } '   
    
Invoke-VMScript -ScriptText $script -VM $vm -GuestCredential $localadmincreds     } }
-- http://alpacapowered.wordpress.com
Bala18
Contributor
Contributor

Massive work, MKGuy!!!

I was looking for this snippet for more than a month and finally a good day today!!! Thanks much!!!

I have a question with  Set-VM $vm -MemoryMB $memMB -NumCpu $vcpu -Confirm:$false

(in VSphere 5.1) Do we have a command to set number of cores per socket and number of Virtual sockets?

For instance, if i need 4vCPUs then I should be able to set 2 cores per socket and 2 virtual sockets.

Thanks in advance.

0 Kudos
MKguy
Virtuoso
Virtuoso

You can modify the number of cores per socket like this:

$spec = New-Object -Type VMware.Vim.VirtualMachineConfigSpec -Property @{"NumCoresPerSocket" = 2;"numCPUs" = 4};

$vm.ExtensionData.ReconfigVM_Task($spec);

With this the VM will be configured with a total 4 vCPUs, spread across 2 sockets with 2 cores each.

Also see:

http://communities.vmware.com/message/1891250#1891250

-- http://alpacapowered.wordpress.com
Bala18
Contributor
Contributor

Does New-OSCustomizationSpec resets the password for the account which is mentioned in -FullName switch?

Because, after the sysprep I am unable to login to the server using the credential what I mention in -AdminPassword swtich. Can you help me understand what would be the password set for Administrator account after the sysprep and how to avoid sysprep from changing the administrator password?

Thanks for any help.

0 Kudos