Chapter 7
Using Templates and Customization Specifications

In this chapter, you will learn to:

  • Use Customization Specifications
  • Creating Customization Specifications
  • Managing Customization Specifications
  • Using Customization Specifications
  • Use Templates
  • Creating Templates
  • Deploying Guests from Templates
  • Maintaining Templates

Creating new virtual machines (VMs) can be a large part of any virtualization administrator’s job. With the perceived ease of deployment, virtualization administrators are often asked to meet deployment schedules that aren’t possible in the physical world. To meet those demands, they have to use the full toolkit at their disposal. When it comes to deploying virtual machines, the tools provided are templates and customization specifications. Their use is a key part of any administrator’s game. In this chapter, you will learn how to create templates and customization specifications, deploy guests, and maintain templates over the long term.

Use Customization Specifications

A customization specification is a collection of information used to customize a guest operating system. This task can be done in conjunction with a deployment operation or independently on an existing VM as long as the machine in question has the following items installed:

  • VMware Tools
  • 32-bit or 64-bit hardware corresponding to the 32-bit or 64-bit operating system to be installed
  • SCSI disks attached at SCSI node 0:0

Guest customization is accomplished through the use of finalization scripts that are executed through the GuestOperationsManager core API. Although this technique works wonderfully, it does require that the finalization script be written for the guest operating system. As of vSphere 4.1, guest customization is supported on all versions of Windows since Windows 2003, as well as most modern RedHat, Debian, Ubuntu, and SUSE Linux distributions. Most Linux distributions based on an officially supported kernel will usually work as well.

Creating Customization Specifications

To create a new customization specification from scratch in PowerCLI, use the New-OSCustomizationSpec cmdlet. For instance, the code contained in Listing 7-1 creates a new Windows customization specification.

Listing 7-1: Creating a new Windows customization specification

New-OSCustomizationSpec -Name 'Win2012R2' `
    -FullName 'Glenn Sizemore' `
    -OrgName 'Get-Admin' `
    -OSType 'Windows' `
    -ChangeSid `
    -Type 'Persistent' `
    -DnsServer '192.168.2.8', '192.168.2.1' `
    -DnsSuffix 'vSphere.local' `
    -AdminPassword 'VMware1!' `
    -TimeZone 35 `
    -Workgroup 'workgroup' `
    -NamingScheme 'Vm'

Linux customization specifications can also be created using the same cmdlet. Listing 7-2 creates an OS Customization Specification for RHEL5.5.

Listing 7-2: Creating a new Linux customization specification

New-OSCustomizationSpec -Name 'RHEL5.5' `
    -OSType 'Linux' `
    -Domain 'vSphere.local' `
    -Type 'Persistent' `
    -DnsServer '192.168.2.8', '192.168.2.1' `
    -DnsSuffix 'vSphere.local' `
    -NamingScheme 'Vm'

Admittedly, creating new customization specifications from scratch is a rare occurrence and is one of those activities just meant for the GUI. Honestly, it is much easier to create one from scratch from within the vSphere Web Client. However, in certain scenarios it is appropriate to automate.

Managing Customization Specifications

That’s not to say there isn’t a need to automate customization specifications. On the contrary, PowerCLI is recommended for all maintenance tasks. For example, if an organization added a new DNS server, adding that server to the existing specifications involves one line of code in PowerCLI:

Get-OSCustomizationSpec |
    Set-OSCustomizationSpec -DnsServer 192.168.1.2, 192.168.1.6

PowerCLI is adept at credential management as well. Most organizations require all administrative credentials to be updated quarterly at a minimum. All too often, this task is ignored because it is deemed too difficult. Well, in PowerCLI maintaining a password is a snap. Listing 7-3 updates the account used to add machines to the domain. Since there may be other accounts used in other specifications for other delegated domains or organizational units, the script first filters the OS customization specifications to only update the specifications using the specified account.

Listing 7-3: Updating the domain credentials within all existing specifications

$Credentials = Get-Credential [email protected]
Get-OSCustomizationSpec |
    Where {$_.DomainUsername -eq $Credentials.UserName} |
    Set-OSCustomizationSpec -DomainCredentials $Credentials

Maintaining the guest password is a snap too. It is perfectly valid to choose to either omit the guest password completely or generate a random password for each new guest. However, if a common password is used for the local administrator account, that password needs to be updated regularly—another complicated and time-consuming task that is simplified with PowerCLI, as seen in Listing 7-4.

Listing 7-4: Updating the local admin user within all existing specifications

Get-OSCustomizationSpec |
    Where-Object {$_.OSType -eq 'Windows'}|
    Set-OSCustomizationSpec -AdminPassword 'P33k@B00!'

It is also possible to clone an existing customization specification. For example, Listing 7-5 takes an existing specification for a Windows 2012 R2 Server and creates a new spec that can be used to deploy Server 2012 R2 Core with IIS. This is accomplished by adding a RunOnce command to the spec to install IIS.

Listing 7-5: Copy specification to create a custom IIS specification

Get-OSCustomizationSpec -Name 'Win2012R2' |
    New-OSCustomizationSpec -Name 'Win2012R2_IIS' |
    Set-OSCustomizationSpec -AutoLogonCount 1 `
        -GuiRunOnce 'cmd /C PowerShell.exe -Command "& {Add-WindowsFeature `
        Web-Server -IncludeAllSubFeature -IncludeManagementTools -Restart}"'

Using Customization Specifications

There are two ways to use an OS customization specification:

  • Apply it to an existing powered-off VM.
  • Attach it during a template deployment.

For now, let’s stick to using a powered-off machine. Although it’s not well known, it is possible to use the Set-VM cmdlet to apply customization specifications to any guest, as long as that guest meets the minimum requirements described earlier.

The Set-VM cmdlet’s -OSCustomizationSpec parameter was intended to be used to apply a customization specification to a cloned VM. However, there is nothing preventing it from being used on demand. Listing 7-6 uses a customization specification to change both the network adapter settings and the domain membership of an existing VM.

Listing 7-6: Employing customization specifications on demand

# Save the credential object with permission to join the domain.
$DomainCredentials = Get-Credential [email protected]
# Clone the Spec adding the domain information.
$Spec = Get-OSCustomizationSpec 'Win2012R2' |
    New-OSCustomizationSpec -Name 'tmp01' -Type NonPersistent |
    Set-OSCustomizationSpec -Domain vSphere.local `
        -DomainCredentials $DomainCredentials

# Update Spec with the new VLAN's IP information
Get-OSCustomizationNicMapping -Spec $Spec |
    Set-OSCustomizationNicMapping -IPmode UseStaticIP `
        -IpAddress '10.1.5.42' `
        -SubnetMask '255.255.255.0' `
        -DefaultGateway '10.1.5.1' `
        -Dns '192.168.2.8','192.168.2.1'
$Spec = Get-OSCustomizationSpec 'tmp01'
# Get the VM
$VM = Get-VM -Name App04
# Shutdown guest to make change.
Stop-VMGuest -VM $VM -Confirm:$false
# Wait while guest shuts down
While ((Get-VM $VM).PowerState -ne 'poweredOff')
{
    Start-Sleep -Seconds 1
}
# Change network settings
# Requires the VMware.VimAutomation.Vds module be loaded
$vDSPG = (Get-VDPortgroup -Name VLAN100)
$VM |
    Get-NetworkAdapter |
    Set-NetworkAdapter -Portgroup $vDSPG -Confirm:$false |
    Out-Null
# Apply customization Spec to apply new network settings
$VM | Set-VM -OSCustomizationSpec $Spec -Confirm:$false |
    Start-VM

Customization specifications are a tool just like any other component of vSphere. With PowerCLI, you can apply that tool to whatever, wherever, whenever need be!

Use Templates

A template is a VM that has been placed in a protected, read-only state to be used as a master copy for subsequent virtual machine creation and provisioning tasks. Once a VM has been converted into a template, it cannot be modified in any way without first being converted back into a virtual machine. There are many reasons to use templates, but they all boil down to one primary benefit: templates reduce the number of steps and the time needed to deploy a new virtual machine.

Creating Templates

With the fundamentals of templates established, all that’s needed to create a new template is a source VM. The source VM will have to be prepared by installing the desired operating system before conversion. With the source VM prepared, there are two ways to create a template:

  • Convert the VM into a template.
  • Clone the VM to a template.

The decision of which method to use is simple. Is the source VM needed for something else? If the answer is yes, then clone the source VM to a template. If the answer is no, then save time and input/output (I/O) operations by converting the source VM to a template.

For example, a web team just finished loading a brand-new Linux server and wants to use it as the source for an upcoming deployment. If that server is not needed for anything else, simply convert it to a template using the Set-VM cmdlet, as we’ve done in Listing 7-7.

Listing 7-7: Converting a VM to a template

Get-VM WEBXX | Set-VM -ToTemplate

If for any reason the source VM is needed for another task, create a new template by cloning the source to a template, as shown in Listing 7-8.

Listing 7-8: Cloning a VM to a template

$VM = Get-VM WEB02
$Folder = Get-Folder WEB
New-Template -Name 'WEBMaster' -VM $VM -Location $Folder

With the latest release of vSphere came a new construct called a content library. Content libraries provide a centralized store to hold Open Virtualization Format (OVF), template, and International Organization for Standardization (ISO) files. When a template is stored in the content library, the library can handle rudimentary replication between vCenter instances. Unlike traditional templates, a template stored in a content library is stored as an OVF file. This means that it cannot be easily converted back to a VM without being deployed. Although this new capability has massive potential, as of this writing it has not been fully integrated into PowerCLI. The content library itself can be managed, but VM provisioning and such are not enabled in the built-in cmdlets.

That’s all there is to it from a vCenter Server/PowerCLI point of view. The truth about templates is that they are only as good as the source VM—which means all the hard work is done up front in the guest.

Deploying Guests from Templates

With the required templates pre-staged, it’s time to deploy some guests. Deploying from a template is a clone operation and, as explained in Chapter 6, “Creating Virtual Machines,” this is accomplished via the New-VM cmdlet. The short script in Listing 7-9 deploys a web server from the Windows 2012 R2 template created in Listing 7-1.

Listing 7-9: Deploying a guest from a template

$Template = Get-Template -Name 'WS2012R2'
$VMHost = Get-VMHost -Name 'vSphere1'
New-VM -Template $Template -Name 'WEB001' -VMHost $VMHost

A straight deploy operation is a very simple task, but the problem is that everything must be prepared prior to the creation of the template because the resulting VM will be an exact copy of the template. Technically, there is nothing wrong with this approach. Mature Windows/Linux shops that have their own deployment processes nailed down aren’t interested in any assistance from VMware. Individuals fortunate enough to work in such an environment should keep doing what they do. For the rest of us, there are customization specifications.

OS customization specifications are the glue that make templates the powerhouse that they are today. To illustrate, the next section will go through a series of deployments, gradually cranking up the complexity. To begin a standard Windows Server deployment using a static IP address via the customization specification, see Listing 7-10.

Listing 7-10: Assigning a static IP address to a Windows Server using a customization specification

# Update Spec with our desired IP information
Get-OSCustomizationSpec -Name 'Win2012R2' |
    Get-OSCustomizationNicMapping |
    Set-OSCustomizationNicMapping -IPmode UseStaticIP `
        -IpAddress '192.168.2.165' `
        -SubnetMask '255.255.255.0' `
        -DefaultGateway '192.168.2.1' `
        -Dns '192.168.2.8','192.168.2.1'
# Get updated Spec Object
$Spec = Get-OSCustomizationSpec -Name 'Win2012R2'
# Get Template to deploy from
$Template = Get-Template -Name 'WS2012R2'
# Get VMHost to deploy new VM on
$VMHost = Get-VMHost -Name 'vSphere1'
# Deploy VM
New-VM -Name 'WEB001' `
    -VMHost $VMHost `
    -Template $Template `
    -OSCustomizationSpec $Spec |
    Start-VM

The workflow here is somewhat backward, but it makes sense once the underlying mechanism is explained. First, the customization specification was modified to use the desired IP address. Here is where it gets a little crazy: when executed, the update is applied to the actual customization specification—this isn’t an object in memory. Once the now modified customization object is retrieved from vCenter Server along with the template and VMHost object, a simple call of the New-VM cmdlet will deploy the new virtual machine.

Notice in Listing 7-10 that the New-VM object is piped into Start-VM. This is strongly advised because that customization information isn’t in the guest yet—and won’t be until that VM is powered on the first time. Once the new virtual machine is powered on for the first time, vCenter waits for VMware Tools to report in. After the Tools report in for the first time, vCenter Server copies an OS customization script to the guest VM and then calls a series of finalization scripts that perform the guest customization.

Although completely functional, both of the previous examples had one critical flaw: they modified the customization specification stored on vCenter Server. This behavior is especially troublesome as it will permanently modify the source specification. To work around this, use nonpersistent OS customization specifications. The process looks identical to the process in Listing 7-10 with one exception: before making any modifications, the customization specification is cloned to a nonpersistent specification. This step enables the modification of the specification without affecting the copy stored on vCenter Server. The code contained in Listing 7-11 deploys another Windows Server performing the same customization as before but this time leaving the master copy on vCenter Server unaffected.

Listing 7-11: Cloning a customization specification to a nonpersistent specification

# Clone our Spec
$Spec = Get-OSCustomizationSpec 'Win2012R2' |
    New-OSCustomizationSpec -Name 'tmp01' -Type NonPersistent
# Update Spec with our desired IP information
Get-OSCustomizationNicMapping -Spec $Spec |
    Set-OSCustomizationNicMapping -IPmode UseStaticIP `
        -IpAddress '192.168.2.42' `
        -SubnetMask '255.255.255.0' `
        -DefaultGateway '192.168. 2.1' `
        -Dns '192.168.2.8','192.168.2.1'
# Get updated Spec Object
$Spec = Get-OSCustomizationSpec -Name 'tmp01'
# Get Template to deploy from
$Template = Get-Template -Name 'Win2012R2'
# Get VMHost to deploy new VM on
$VMHost = Get-VMHost -Name 'vSphere1'
# Deploy VM
New-VM -Name 'WEB001' `
    -VMHost $VMHost `
    -Template $Template `
    -OSCustomizationSpec $Spec |
    Start-VM

Thus far, all of our examples have had only a single network adapter. What about a machine with multiple network adapters? Well, as it turns out, the process is almost exactly the same. The only difference is that each adapter must be specifically targeted by position. Therefore, the current Nic position must be known for each Nic. This information can be retrieved by running the Get-OSCustomizationNicMapping cmdlet for the spec being modified:

Get-OSCustomizationSpec -name 'W2K8R2Core_IIS' |
  Get-OSCustomizationNicMapping


SpecId            Position IPMode   IPAddress    DefaultGateway
------            --------------   ---------     --------------
W2K8R2Core_IIS    1 PromptUser     192.168.145.2
W2K8R2Core_IIS    2 UseStaticIP    10.10.10.11

Once position is determined, it is possible to programmatically configure each NIC (Listing 7-12).

Listing 7-12: Using customization specifications with multiple network adapters

# Clone our Spec
$Spec = Get-OSCustomizationSpec 'Win2012R2_IIS' |
    New-OSCustomizationSpec -Name 'tmp_two_nics' `
        -Type NonPersistent
# Get every Nic in our spec
Foreach ($NIC in (Get-OSCustomizationNicMapping -Spec $Spec))
{
    # Set the appropriate NIC settings
    Switch ($NIC.Position)
    {
      1 {
          Set-OSCustomizationNicMapping -IPmode UseStaticIP `
              -OSCustomizationNicMapping $NIC `
              -IpAddress '192.168.2.42' `
              -SubnetMask '255.255.255.0' `
              -DefaultGateway '192.168.2.1' `
              -Dns '192.168.2.8','192.168.2.1'
      }
      2 {
          Set-OSCustomizationNicMapping -IpAddress 10.10.10.42 `
              -IPmode UseStaticIP `
              -SubnetMask '255.255.255.0' `
              -DefaultGateway '10.10.10.2' `
              -Dns '192.168.2.8,'192.168.2.1' `
              -OSCustomizationNicMapping $NIC
      }
    }
}
# Get the updated Spec Object
$Spec = Get-OSCustomizationSpec -Name 'tmp_two_nics'
# Get Template to deploy from
$Template = Get-Template -Name 'Win2012R2'
# Get VMHost to deploy new VM on
$VMHost = Get-VMHost -Name 'vSphere1'
# Deploy VM
New-VM -Name 'WEB001' `
    -VMHost $VMHost `
    -Template $Template `
    -OSCustomizationSpec $Spec |
    Start-VM

Notice how only the customization NIC mapping changed. One of the truly powerful features of PowerCLI is that it doesn’t require a new technique; instead, it builds upon existing knowledge.

Up until now, the examples have only deployed Windows guests. Let’s shift gears and deploy a CentOS 5.x server from a template, as shown in Listing 7-13.

Listing 7-13: Deploying a Linux guest from a template

$Template = Get-Template -Name 'Ubuntu14'
$VMHost = Get-VMHost -Name 'vSphere1'
New-VM -Template $Template -Name 'WEB001' -VMHost $VMHost

Wait! That looks very similar to the Windows guest deployed in Listing 7-9. The only difference is the VM name and the template. So now let’s add a customization spec and configure the guest postdeployment (see Listing 7-14).

Listing 7-14: Using a customization spec to configure a Linux guest postdeployment

# Clone our Spec
$Spec = Get-OSCustomizationSpec Ubuntu14 |
    New-OSCustomizationSpec -Name 'tmp01' -Type NonPersistent
# Update Spec with our desired IP information
Get-OSCustomizationNicMapping -Spec $Spec |
    Set-OSCustomizationNicMapping -IPmode UseStaticIP `
        -IpAddress '192.168.2.145' `
        -SubnetMask '255.255.255.0' `
        -DefaultGateway '192.168.2.1'
# Get updated Spec Object
$Spec = Get-OSCustomizationSpec -Name 'tmp01'
# Get Template to deploy from
$Template = Get-Template -Name Ubuntu14
# Get VMHost to deploy new VM on
$VMHost = Get-VMHost -Name 'vSphere1'
# Deploy VM
New-VM -Name 'WEB001' `
    -VMHost $VMHost `
    -Template $Template `
    -OSCustomizationSpec $Spec |
    Start-VM

Again, this code looks almost identical to the code from Listing 7-11. That’s one of PowerCLI’s greatest strengths: behind the scenes, VMware has built an amazing abstraction layer in guest customizations. PowerCLI then takes that abstraction layer and abstracts it again. This means that it is either incredibly easy or incredibly difficult to perform guest customization. Either the guest is supported and it’s a snap, or it’s not and guest customization requires custom scripting. Fear not! With Invoke-VMScript, any custom work can be integrated in any PowerCLI script.

Maintaining Templates

Templates are an incredibly powerful tool—one critical to the VM life cycle. It is, however, important to keep templates up to date. It’s a level-of-effort deal; it’s easier to maintain one template than it is to patch or update a number of VMs postdeployment. Some companies choose to update their templates only quarterly and rely on their management tools to fill that gap. We feel this is foolish: regardless of how good an enterprise toolkit is, why waste cycles on a fresh guest deployment when it is easier to just maintain the source template? Whatever the decisions, just remember: PowerCLI is here to assist. With that in mind, there are a few common issues, but one universal pain point with templates.

No matter what you’re doing, the first step is always to convert your template into a VM and the last step is to convert back to a template. You might or might not need to power on the VM in the middle of the process. You will find that you constantly have to account for the power state of the VM during any update. To assist in this trivial task, you can use Wait-VMGuest function (see Listing 7-15).

Listing 7-15: The Wait-VMGuest function

function Wait-VMGuest {

    [CmdletBinding(DefaultParameterSetName='VM')]
    Param(
        [parameter(Position=0
       ,    ParameterSetName='VM'
        )]
        [parameter(Position=0
       ,    ParameterSetName='Guest'
        )]
        [ValidateSet("Startup","Shutdown")]
        [string]
        $Operation
   ,
        [parameter(Mandatory=$True
       ,    ValueFromPipeline=$True
       ,    ParameterSetName='VM'
        )]
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]
        $VM
   ,
        [parameter(Mandatory=$True
       ,    ValueFromPipeline=$True
       ,    ParameterSetName='Guest'
        )]
        [VMware.VimAutomation.ViCore.Impl.V1.VM.Guest.VMGuestImpl]
        $VMGuest

    )
    Process {
        if ($PSCmdlet.ParameterSetName -eq 'Guest') {
            $VM = $VMGuest.VM
        }
        Switch ($Operation)
        {
            "Startup"
            {
                while ($vm.ExtensionData.Guest.ToolsRunningStatus `
                  -eq "guestToolsNotRunning")
                {
                    Start-Sleep -Seconds 1
                    Write-Verbose `
                        "Waiting on VMware tools start for $($vm.Name)"
                    $vm.ExtensionData.UpdateViewData("Guest")
                }
                # return a fresh VMObject
                Write-Output (Get-VM $VM)
                break;
            }
            "Shutdown"
            {
                # wait for the VM to be shut down
                while ($VM.ExtensionData.Runtime.PowerState `
                  -ne "poweredOff")
                {
                    Start-Sleep -Seconds 1
                    Write-Verbose "Waiting for $($vm.Name) to power off"
                    $vm.ExtensionData.UpdateViewData( `
                        "Runtime.PowerState")
                }
                # return a fresh VMObject
                Write-Output (Get-VM $VM)
                break;
            }
        }
    }
}

Wait-VMGuest simplifies the code required to update a template by pausing the pipeline while the target VM either shuts down or starts up. Take note of the way it streamlines the code. Imagine having to put the pipeline into a loop every time a VM is power-cycled. Doing so would break the streaming nature of PowerShell. The Wait-VMGuest function enables the pipeline to stream while still waiting where needed.

Upgrading Hardware

Although this doesn’t come up very often, if a heavy investment was made previously and an organization has amassed a vast collection of templates in a previous version of vSphere, they might want to upgrade all those templates to the latest hardware version to take advantage of the new capabilities. Fortunately, this is one of those tasks that lends itself to automation. In Listing 7-16 we’ll update the WS2K8R2 template to hardware version 11.

Listing 7-16: Update VM hardware version

$VM = Get-Template 'W2K8R2' | Set-Template -ToVM
$VM.ExtensionData.UpgradeVM("vmx-11")
Set-VM -VM $VM -ToTemplate

As tasks go, this one is easy. Get the template object and convert it into a VM. Then, call the UpgradeVM method on the virtual machine object to perform the upgrade. Finally, convert the object back into a template. There is one problem, though: VMware requires that a current version of the VMware Tools be installed prior to upgrading a VM’s hardware version—which means either forcing the upgrade (which is dangerous) or handling the tools upgrade as well (which is complicated). The script in Listing 7-17 forces the Tools upgrade and upgrades the hardware version in one action.

Listing 7-17: Forcing a VM hardware upgrade

$VM = Get-Template 'vm01' | Set-Template -ToVM
$taskMoRef = $vm.ExtensionData.UpgradeVM_Task("vmx-11")
$task = Get-View $taskMoRef
while ($task.Info.State -eq 'running')
{
    $task.UpdateViewData("Info.State")
    $Question = Get-VMQuestion -VM $VM
    if ($Question)
    {
        Answer-VMQuestion -VMQuestion $Question `
            -DefaultOption `
            -Confirm:$false
    }
}
Set-VM -VM $VM -ToTemplate -Confirm:$false

There are scenarios where it makes sense to force an upgrade. For example, if the template didn’t have an operating system or the VMware Tools weren’t installed in the template, there is no choice but to force the upgrade. This situation would be an edge case. Best practice is to always have VMware Tools installed, and a template will almost always have an operating system.

How does one safely automate an upgrade when the operating system or VMware Tools are missing? Before we get into the actual code, let’s talk about what a safe virtual hardware upgrade entails. First, the template must be converted back into a VM to make it writable. Then, VMware Tools need to be upgraded. Once upgraded, the VM needs to be powered off. Then, the hardware version can be upgraded. For good measure, the template should be powered back on to see how it all went.

Listing 7-18 breaks that process down into code.

Listing 7-18: Safely upgrading the VM hardware

# get our template, convert it to a VM, and power said VM on.
$VM = Get-Template 'vm01' |
    Set-Template -ToVM |
    Start-VM |
    Wait-VMGuest Startup
# kick off a tools update and wait for it to finish.
Update-Tools -VM $VM
#Shut down our VM
Stop-VMGuest -VM $VM -Confirm:$false |
    Wait-VMGuest Shutdown | Out-Null
# Perform the hardware upgrade
$vm.ExtensionData.UpgradeVM("vmx-11")
# Power on our VM
Start-VM -VM $VM
# Log in and make sure the upgrade went okay.
# Power our VM back down
$VM = Stop-VMGuest -VM $VM -Confirm:$false |
    Wait-VMGuest Shutdown
# Convert back to template
Set-VM -VM $VM -ToTemplate -Confirm:$false

Very straightforward! Given enough templates to justify the investment, it is possible to fully automate the complete upgrade life cycle. The Update-TemplateHardware function in Listing 7-19 does just that. This script handles the complete upgrade life cycle and performs checks before making any modification to ensure it’s only affecting templates that require an update.

Listing 7-19: Update-TemplateHardware

function Update-TemplateHardware {

    [CmdletBinding()]
    param(
        [parameter(Mandatory=$True
       ,    ValueFromPipeline=$True
       ,    HelpMessage='Template object to upgrade'
        )]
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.TemplateImpl]
        $Template
   ,
        [parameter()]
        [ValidatePattern("vmx-dd")]
        [string]
        $Version="vmx-11"
    )
    Process
    {
        # Convert our template back to a VM, and PowerOn.
        $VM = Set-Template -Template $Template -ToVM

         #check VM Hardware version
        if ($VM.ExtensionData.Config.Version -ne $Version)
        {
            Write-Host "VM Hardware version out of date!" `
                -ForegroundColor 'RED'
            $VM = Start-VM -VM $VM | Wait-VMGuest Startup

            # Check VMware tools version if tools are out of
            # date upgrade them.
            if ($VM.ExtensionData.Guest.ToolsStatus -ne "ToolsOk")
            {
                Write-Host 'VMware tools are out of date!' `
                        -ForegroundColor 'RED'
                #Kick off a tools update
                Try
                {
                    Update-Tools -VM $VM
                }
                Catch
                {
                    Write-Warning $_.Exception.Message
                    break;
                }
                Write-Host "Updating Tools..." -NoNewline
                #Wait for the update to finish
                while ($VM.ExtensionData.Guest.ToolsStatus `
                 -ne "ToolsOk")
                {
                    Start-Sleep -Seconds 1
                    Write-Host "." -NoNewline
                    $VM.ExtensionData.UpdateViewData("Guest")
                }
                Write-Host "DONE" -ForegroundColor 'Green'
                Write-Host "Tools upgrade complete"
                Write-Host "Starting hardware Upgrade"
            }
            else
            {
                Write-Host "ToolsOK Starting hardware Upgrade" `
                    -ForegroundColor 'Green'
            }

            # Shut the VM back down
            Write-Host "Shut down guest"
            $VM = Stop-VMGuest -VM $VM -Confirm:$false |
                Wait-VMGuest Shutdown
            $VM.ExtensionData.UpgradeVM($Version)
            Write-Host "VM Hardware updated..."
            Write-Host "Starting VM please log in and verify"
            $VM = Start-VM -VM $VM
        }
        else
        {
            Write-Host "VM Hardware is up to date." `
                -ForegroundColor 'Green'
            $VM = Set-VM -VM $VM -ToTemplate -Confirm:$false
        }
    }
}

Patching

Once a well-established template is developed, there is no reason to make many modifications. It is necessary, however, to keep the template up to date. Several techniques are available for this purpose.

For example, a Windows shop might leverage Windows Server Update Services (WSUS) or System Center Configuration Manager (SCCM) to patch their Windows VMs. A RedHat shop might use Puppet in conjunction with a Satellite server. Smaller organizations might even use a unified patch platform like Shavlik.

Whatever the chosen process, PowerCLI is here to help. By integrating the existing patch management infrastructure with the virtual infrastructure, it is possible to maintain the best of both worlds. For instance, if an organization manually updates all servers, then more than likely it will manually update its templates as well. PowerCLI can still automate the conversions and power operations, but someone will have to log in and manually install any pending patches (see Listing 7-20).

Listing 7-20: Automating the template patch life cycle

Get-Template 'w2k8R2' |
    Set-Template -ToVM |
    Start-VM |
    Wait-VMGuest Startup |
    # here you would log in and patch the guest
    Wait-VMGuest Shutdown |
    Set-VM -ToTemplate -Confirm:$false

The preceding script used PowerCLI to convert the template into a VM, start the VM, and wait while the guest was updated. PowerCLI then detected the power-off, used that as a cue that the update was finished, and converted the VM back into a template. This approach has the benefit of organizing the patch process, making it repeatable across any number of VMs, while not requiring a completely automated solution.

Of course it is possible to take this process a step further and automate the whole patch life cycle. The script in Listing 7-21 does just that. This time the code takes a snapshot beforehand, and pre-stages any required updates by triggering update detection within the guest. Finally, the VM is cloned back into a new template, thereby fulfilling any failback requirements from the change management processes.

Listing 7-21: Automating the template patch life cycle

$HostCredential = Get-Credential
$GuestCredential = Get-Credential
$DTG = Get-Date -Format s
#Convert template back into VM
$VM = Get-Template 'w2012r2' |
    Set-Template -ToVM
#Take a snapshot before we alter our template
$Snapshot = New-Snapshot -VM $VM `
    -Name Updates_$DTG `
    -Description "scheduled updates $DTG"
#Power on the VM, and wait for tools to report in
$VM = Start-VM -VM $VM | Wait-VMGuest 'Startup'
#kick off the Windows Update detection agent within the guest
Invoke-VMScript -VM $VM `
    -GuestCredential $GuestCredential `
    -HostCredential $HostCredential `
    -ScriptType 'bat' `
   -ScriptText '%windir%system32wuauclt.exe /reportnow /detectnow'
#wait for the VM to be powered off
$VM = Wait-VMGuest -VM $VM -Operation 'Shutdown'
# Create a new template for testing
$Template = New-Template -VM $VM -Name ("{0}_{1}" -f $VM.Name, $DTG)

The next logical step would be to fully automate the installation of patches. Using a combination of Invoke-VMScript and some guest scripting, it is possible to build a hands-free update process. The decision of whether or not that is necessary depends on the organization.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset