Using Advanced vSphere Features

In this chapter, you will learn to:

  • Configure EVC
  • vFlash Read Cache
  • Manage DRS Groups
  • Use Fault Tolerance
  • Use Distributed Power Management
  • Configure Host Profiles
  • Configure Active Directory Integration

At this point, we have shown that vSphere is the virtualization platform of choice for a myriad of reasons. This chapter focuses on automating some of the most advanced features vSphere offers. Be aware that many of these features require the Enterprise Plus licensing to be used.

Configure EVC

Have you ever tried to use older hardware in the same cluster as newly purchased servers? Did you encounter a condition where virtual machines would not vMotion between the hardware generations? This is because CPU features between the newer and older generations are incompatible. VMware uses Enhanced vMotion Compatibility (EVC) to mask the features of newer-generation CPUs so that they appear to have the same capabilities as the older generation. This facilitates vMotion across CPUs of the same manufacturer, even when they are vastly different in capability. One thing to note, though, is that EVC doesn’t allow you to vMotion VMs from AMD to Intel, or vice versa.

In recent versions of PowerCLI, VMware has added the ability to configure EVC for a cluster using the standard Set-Cluster cmdlet, as shown in Listing 5-1.

Listing 5-1: Setting the EVC mode using PowerCLI

Get-Cluster $clustername | Set-Cluster -EVCMode intel-nehalem

That code snippet sets the EVC mode intel-nehalem; it masks CPU features for all Intel processors so that they are at the feature level of the Nehalem platform. For ESXi 5.5 the supported EVC modes are as follows:

  • intel-merom
  • intel-penryn
  • intel-nehalem
  • intel-westmere
  • intel-sandybridge
  • intel-ivybridge
  • amd-rev-e
  • amd-rev-f
  • amd-greyhound-no3dnow
  • amd-greyhound
  • amd-bulldozer
  • amd-piledriver

ESXi 6 adds support for these CPU architectures as well:

  • intel-haswell
  • amd-steamroller

For each of the manufacturers, the list builds on the feature set of the less capable architecture. For example, intel-westmere has all of the features of intel-nehalem, plus the features specific to Westmere. This means that your cluster can only support the EVC mode of the least capable CPU architecture. Unfortunately, there is no quick way to determine what that mode should be. You have to make do with trial and error using the GUI. Fortunately, PowerCLI has access to all of this information, so you can create a simple function to determine the maximum EVC setting for any cluster. Take a look at Listing 5-2.

Listing 5-2: The Get-MaxEvcMode functionfunction Get-MaxEvcMode {

    <#  .SYNOPSIS
        Get the highest EVC level for a cluster
        
        .DESCRIPTION
        Function to get the highest EVC level supported by all of 
        the VMHosts in an cluster. Useful to easily/quickly 
        determine the highest EVC level that one might set for 
        the cluster based on the VMHosts that are a part of the
        cluster and their hardware 
        types.
        
        .EXAMPLE
        Get-MaxEvcMode -Cluster (Get-Cluster clusterName)
        Get the EVC mode info for cluster "clusterName"
        .EXAMPLE
        Use the pipeline to get the EVC mode info for the given clusters.
        Get-Cluster someCluster,someOtherCluster | Get-MaxEvcMode
        
        .PARAMETER Cluster
        The cluster whose maximum EVC mode to determine.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        
        .OUTPUTS
        PSCustomObject
    #>
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipeline=$true
        )]
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        $Cluster
    )
    process {
        $hosts = $Cluster | Get-VMHost

        # get the max supported for each host
        $nodeMaxEvcMode = @{}

        $hosts | Foreach-Object {
            $nodeMaxEvcMode.Add(
                $_.Name,
                $_.ExtensionData.Summary.MaxEVCModeKey
            )
        }

        # check to see if there are different CPU manufacturers
        $lastManufacturer = ""
        $incompatible = $false

        $nodeMaxEvcMode.GetEnumerator() | Foreach-Object {
            $currentManufacturer = ($_.Value -split "-")[0]
            if ($lastManufacturer -eq "") {
                $lastManufacturer = $currentManufacturer
            }

            if ($lastManufacturer -ne $currentManufacturer) {
                Write-Warning "Hosts have Intel and AMD CPUs"
                $incompatible = $true
            }
        }

        # check to see if they are all the same
        [Array]$evcGroups = $nodeMaxEvcMode.GetEnumerator() |
            Group-Object -Property Value

        if ($evcGroups.Count -eq 1) {
            # they're the same, print out the first one
            $obj = "" | Select-Object MaxEvcMode
            $obj.MaxEvcMode = $evcGroups[0].Name
            $obj

        } elseif ($incompatible -eq $false) {
            # they're not the same, let's figure out the least
            # common denominator

            # collect all available EVC modes
            $evcModes = @{
                'intel' = @();
                'amd' = @();
            }

            $serviceInstance = Get-View ServiceInstance

            $serviceInstance.Capability.SupportedEVCMode | Foreach-Object {
                $procManufacturer = ($_.key -split "-")[0]
                $procArchiteture = $_.key
                $evcModes.$procManufacturer += $procArchiteture
            }

            # Will map to the array index with the maximum supported
            # value.  The initial value is set high enough that it will
            # be overwritten by the actual host values during the check
            $maxSupported = `
$serviceInstance.Capability.SupportedEVCMode.length

            # check to see what is the lowest supported value
            $nodeMaxEvcMode.GetEnumerator() | Foreach-Object {
                $cpuManufacturer = ($_.Value -split "-")[0]

                # get the index value of this element
                $nodeEvcIndex = [Array]::IndexOf(
                        $evcModes.$cpuManufacturer,
                        $_.Value
                    )

                # check to see if this EVC value is less than
                # the currently reported minimum
                if ($nodeEvcIndex -lt $maxSupported) {
                    $maxSupported = $nodeEvcIndex
                }
            }

            # return the value as an anon object
            $obj = "" | Select-Object MaxEvcMode
            $obj.MaxEvcMode = `
                $evcModes.$cpuManufacturer[$maxSupported]
            $obj

        }
    }
}

You can use the function created in Listing 5-2 in conjunction with the standard Set-Cluster cmdlet to quickly and easily set the EVC mode for any set of servers. Listing 5-3 shows how that’s done.

Listing 5-3: Setting the EVC mode for a cluster

Get-Cluster $clustername | Set-Cluster `
  -EVCMode (Get-Cluster $clustername | `
  Get-MaxEvcMode).MaxEvcMode

Likewise, you can disable EVC for a cluster by setting the EVC mode to $null, as we have done in Listing 5-4.

Listing 5-4: Disabling EVC for a cluster

Get-Cluster $clustername | Set-Cluster -EVCMode $null

EVC is a handy feature to enable vMotion within a cluster of multigenerational servers, but it does have some nuances. For example, you can increase the level of EVC without powering off all VMs in the cluster, but you cannot decrease the level without powering down the VMs first. Similarly, if you vMotion from a cluster with a higher EVC setting to a lower setting, you will need to power down the VM first.

With this workflow in mind, you can seamlessly replace an entire cluster’s worth of servers without having to vMotion across clusters:

  1. Ensure that EVC is enabled for the old servers’ CPU level.
  2. Add the new servers; EVC will mask the new CPU features automatically.
  3. Remove the old servers.
  4. Increase the EVC mode to the maximum available for the new servers.
  5. Reboot the VMs at your convenience; they will automatically begin using the new CPU features.

vFlash Read Cache

vSphere Flash Read Cache (vFRC) is a feature that was introduced by VMware with vSphere 5.5. This feature uses SSDs local to the physical host to provide an accelerated read-only cache for individual VMDKs of virtual machines hosted by that server. This has a tremendously positive effect on the read performance of the virtual machine by using local, low-latency, high-performance drives that don’t have to traverse the storage network. It also works with VMFS, NFS, and even raw device mapping (RDM) disk devices, providing up to 200 GB (by default, but this can be expanded to 400 GB) of cache per VMDK.

If you are familiar with the feature introduced in vSphere 5.1 that enables the host to swap to SSD, this is a replacement for and an extension of that feature. Both the ESXi host and the VMs can be configured to swap to the SSD instead of to a datastore. vFRC is different than this swap-to-SSD functionality in that it acts as a read cache specifically for the VMDKs that have been assigned. Be aware that when vMotioning a VM with vFRC enabled, you will need to specify what action to take with the cache: copy it to the new host or discard the cache.

Administering vFRC is relatively easy; however, it requires the web client and must be done on a per-VMDK basis. Doing so is quite tedious when you have a large number of hosts to enable and VMDKs to assign capacity for. To expedite the configuration of vFRC on the host, we have created a simple PowerShell function (Listing 5-5) that uses all of the available SSDs to create a single VFFS filesystem on the host.

Listing 5-5: The Enable-VMHostVFRC function

function Enable-VMHostVFRC {
    <#  .SYNOPSIS
        Enable vFlash Read Cache for a host.
        
        .DESCRIPTION
        Function to enable vFRC on a host leveraging the available
        SSDs to create the VFFS file system.  Will use all
        available SSDs as determined by the system.
        
        .EXAMPLE
        Enable vFRC for a particular host
        Enable-VMHostVFRC -Host (Get-VM someVM)
        
        .EXAMPLE
        Use the pipeline to enable vFRC for a cluster
        Get-Cluster | Get-VMHost | Enable-VMHostVFRC
        
        .PARAMETER VMHost
        The host to enable vFRC on.
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
        
        .OUTPUTS
        PSCustomObject
    #>
    [CmdletBinding()]
    param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]

        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
        $VMHost
    )
    process {
        # get views for the objects we will interact with
        $hostView = $VMHost | Get-View -Property `
          ConfigManager.StorageSystem, ConfigManager.VFlashManager
        $hostStorage = Get-View -Property SystemFile `
            $hostView.ConfigManager.StorageSystem
        $hostVflash = Get-View `
            $hostView.ConfigManager.VFlashManager

        # get the device path for each of the available SSDs
        $availSsds = $hostStorage.QueryAvailableSsds(
            [NullString]::Value
        ) | Foreach-Object {
            $_.devicePath
        }

        # report if no SSDs were found
        if ($availSsds -eq $null) {
            Write-Verbose "No available SSDs on host $($VMHost).name"
        }

        try {
            # reconfigure to create the vFRC VFFS
            $task = $hostVflash.ConfigureVFlashResourceEx(
                $availSsds

            )

            # update the view to check the status
            $hostVflash.UpdateViewData(
               "VFlashConfigInfo.VFlashResourceConfigInfo"
            )

            # report the status
            $hostVflash.VFlashConfigInfo.VFlashResourceConfigInfo.Vffs
        }
        catch {
            Write-Error `
                "Unable to assign available SSDs to new VFFS"

        }
    }
}

Once the vFRC VFFS filesystem has been configured, you can begin assigning VMDKs to use it. This can be done through the web client, but life is so much easier when you use PowerShell!

First, let’s determine the current settings for a VMDK. To do this, we have created a simple function (Listing 5-6). This can be used to quickly determine which VMDKs are using vFRC, what their allocation is, and what the cache settings are.

Listing 5-6: The Get-HarddiskVFRC function

function Get-HarddiskVFRC {
    <#  .SYNOPSIS
        Get the status of vFRC for a virutal machine hard disk.
        
        .DESCRIPTION
        Determines if vFRC is enabled for a VM hard disk. If
        enabled, will determine the settings and return them.
        
        .EXAMPLE
        Get the vFRC status for a hard disk
        Get-HarddiskVFRC -Disk (Get-VM someVM | Get-VMHarddisk)
        
        .EXAMPLE
        Use the pipeline to get the vFRC status for all hard disks
        in a vApp
        Get-vApp "My Application" | Get-VM | Get-VMHarddisk | 
          Get-HarddiskVFRC
        
        .PARAMETER Disk
        The disk to check vFRC status on.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.VirtualDevice.HardDisk]
        
        .OUTPUTS
        PSCustomObject
    #>
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipeline=$true
        )]

        [VMware.VimAutomation.VICore.Types.V1.VirtualDevice.HardDisk]
        $Disk
    )
    process {
        # get the owning VM based on the disk's parent id
        $parentVm = Get-VM -Id $disk.Parentid

        # create an anon object to store vFRC relevant data
        $info = "" | Select-Object VM,DiskName,ReservationMB,CacheType,`
            CacheMode,BlockSizeKB,VFlashModule
        $info.VM = $parentVm.Name
        $info.DiskName = $Disk.Name

        # read the disk object's info and put it into our custom object
        if ($disk.ExtensionData.VFlashCacheConfigInfo `
            -ne $null) {
            $info.ReservationMB = `
              $disk.ExtensionData.VflashCacheConfigInfo.ReservationInMB
            $info.CacheType = `
         $disk.ExtensionData.VFlashCacheConfigInfo.CacheConsistencyType
            $info.CacheMode = `
              $disk.ExtensionData.VFlashCacheConfigInfo.CacheMode
            $info.BlockSizeKB = `
              $disk.ExtensionData.VFlashCacheConfigInfo.BlockSizeInKB
            $info.VFlashModule = `
              $disk.ExtensionData.VFlashCacheConfigInfo.VFlashModule
        }

        $info
    }
}

Being able to see the current vFRC settings for a VMDK is useful, but what we really care about is being able to configure those settings. We created a function for that too! Take a look at Listing 5-7.

Listing 5-7: The Set-HarddiskVFRC function

function Set-HarddiskVFRC {
    <#  .SYNOPSIS
        Set the configuration of vFRC for a virtual machine hard disk.
        
        .DESCRIPTION
        Sets the vFRC configuration for a VM hard disk.  Will use 
        sane defaults if none are provided, setting the reserve to
        1GB with strong cache type and 4KB block size.
        
        .EXAMPLE
        Set vFRC to the defaults
        Set-HarddiskVFRC -Disk (Get-VM someVM | Get-VMHarddisk)
        
        .EXAMPLE
        Use the pipeline to get the vFRC status for all hard disks
        in a vApp
        Get-vApp "My Application" | Get-VM | Get-VMHarddisk | 
          Get-HarddiskVFRC
        
        .PARAMETER Disk
        [VMware.VimAutomation.ViCore.Impl.V1.VirtualDevice.HardDisk]
        The VM hard disk to modify
        
        .PARAMETER Enable
        [System.Boolean] 
        Enable vFRC for the VM hard disk
        
        .PARAMETER Disable
        [System.Boolean] 
        Disable vFRC for the VM hard disk
        
        .PARAMETER CacheMode
        [System.String] 
        The cache mode, "WriteBack" or "WriteThru"
        
        .PARAMETER CacheType
        [System.String] 
        The cache type, "strong" or "weak"
        
        .PARAMETER BlockSizeKB
        [System.Int] 
        The block size of the cache, 4-1024KB
        
        .PARAMETER ReservationMB
        [System.Int] 
        The reservation size for the disk, in MB.  4MB-409600MB
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.VirtualDevice.HardDisk]
        
        .OUTPUTS
        PSCustomObject
    #>
    [CmdletBinding(DefaultParameterSetName="EnableVfrc")]
    param (
        # the disk to enable/disable vFRC on
        [parameter(
            Mandatory=$true,
            ValueFromPipeline=$true
        )]
        [VMware.VimAutomation.VICore.Types.V1.VirtualDevice.HardDisk]
        $Disk
        ,

        # enable cache for this disk
        [parameter(
            Mandatory=$true,
            ParameterSetName="EnableVfrc"
        )]
        [Switch]$Enable
        ,

        # disable cache for this disk
        [parameter(
            Mandatory=$true,
            ParameterSetName="DisableVfrc"
        )]
        [Switch]$Disable
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableVfrc"
        )]
        [ValidateSet("WriteBack", "WriteThru")]
        [String]$CacheMode
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableVfrc"
        )]
        [ValidateSet("strong", "weak")]
        [string]$CacheType
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableVfrc"
        )]
        [ValidateSet(4,8,16,32,64,128,256,512,1024)]
        [Int]$BlocksizeKB
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableVfrc"
        )]
        [ValidateRange(4, 409600)]
        [Int]$ReservationMB
    )
    process {
        # get the owning VM's view
        $parentVm = Get-VM -Id $disk.Parentid

        if ($parentVm.Version -ne "v10") {
            Write-Warning "VM must be version 10"

        } else {
            $parentView = $parentVm | Get-View -Property Name

            # set the default values for the vFRC
            $VflashConfig = New-Object
VMware.Vim.VirtualDiskVFlashCacheConfigInfo

            # If we are disabling, set the reservation to 0
            if ($Disable) {
                $VflashConfig.ReservationInMB = 0
            }

            if ($Enable) {
                # if the user specified write thru, or no
                # value was provided, or no value is currently
                # set, default to write_thru
                if ($CacheMode -eq "WriteThru" -or
                    (
                        $CacheMode -eq $null -and
                        $disk.ExtensionData.VFlashCache`
ConfigInfo.CacheMode -eq $null
                    )
                ) {
                    $VflashConfig.CacheMode = [VMware.Vim.`
VirtualDiskVFlashCacheConfigInfoCacheMode]::write_thru
                } elseif ($CacheMode -eq "WriteBack") {
                    # only if the user specifies do we use
                    # write_back since it is dangerous
                    $VflashConfig.CacheMode = [VMware.Vim.`
VirtualDiskVFlashCacheConfigInfoCacheMode]::write_back
                }

                # will be a value specified, or null, which
                # will automatically use the default, or
                # keep the current setting
                $VflashConfig.BlockSizeInKB = $BlocksizeKB

                # if the user didn't specify, and the value
                # isn't already set, use strong
                if ($CacheType -eq $null -and $disk.`
ExtensionData.VFlashCacheConfigInfo.CacheConsistencyType `
                    -eq $null) {
                    $VflashConfig.CacheConsistencyType = `
                    [VMware.Vim.VirtualDiskVFlashCache`
ConfigInfoCacheConsistencyType]::strong
                } elseif ($CacheType -eq $null -and
                    $disk.ExtensionData.VFlashCache`
ConfigInfo.CacheConsistencyType -ne $null) {
                    # if it's already set, keep it the same
                    $VflashConfig.CacheConsistencyType = $null

                } else {
                    # use what was specified
                    $VflashConfig.CacheConsistencyType = `
                        [VMware.Vim.VirtualDiskVFlashCache`
ConfigInfoCacheConsistencyType]::$CacheType

                }

                # set a default of 1024MB, use what was
                #	provided, or leave it alone
                if ($ReservationMB -eq 0 -and
                    $disk.ExtensionData.VFlashCacheConfigInfo.`
                        ReservationInMB -eq $null) {
                    $VflashConfig.ReservationInMB = 1024
                } elseif ($ReservationMB -ne 0) {
                    $VflashConfig.ReservationInMB = `
                        $ReservationMB
                } else {
                    $VflashConfig.ReservationInMB = `
                        $disk.ExtensionData.`
                            VFlashCacheConfigInfo.`
                            ReservationInMB
                }

            }

            # specify the operation on the disk
            $deviceTask = New-Object VMware.Vim.VirtualDevice`
ConfigSpec
            $deviceTask.Operation = [VMware.Vim.VirtualDevice`
ConfigSpecOperation]::Edit
            $deviceTask.Device = $disk.ExtensionData

            # provide the new vFRC settings
            $deviceTask.Device.VFlashCacheConfigInfo = `
                $VflashConfig

            # specify the operation on the VM
            $vmTask = New-Object VMware.Vim.VirtualMachine`
ConfigSpec
            $vmTask.DeviceChange = $deviceTask

            # execute the spec against the VM
            $taskId = $parentView.ReconfigVM_Task( $vmTask )

            $task = Get-View $taskId

            # wait for the task to finish
            while (
                "running", "queued" -contains $task.Info.State
            ) {
                $task.UpdateViewData("Info")
                Start-Sleep -Seconds 1
            }

            # return an error or the current status on success
            if ($task.Info.State -eq "error") {
                Write-Error $task.info.Error.LocalizedMessage
            } else {
                Get-HardDisk -id $Disk.Id -VM $parentVm |
                    Get-HarddiskVFRC
            }
        }
    }
}

To take advantage of this function, simply pipe a virtual disk object into it and enable or disable the vFRC. Listing 5-8 shows how the command can be used to enable vFRC for all VMDKs of all virtual machines in a particular vApp:

Listing 5-8: Using the Set-HarddiskVFRC function

Get-VApp $name | Get-VM | Get-HardDisk |
  Set-HarddiskVFRC -Enable -ReservationMB 512

Name         : Hard disk 1
Reservation  : 512MB
CacheType    : strong
CacheMode    : write_thru
BlockSize    : 8KB
VFlashModule : vfc

Putting these together, you can take a set of virtual machines, determine if they are using vFRC, and enable any without cache, as demonstrated in Listing 5-9.

Listing 5-9: Enabling vFRC for a subset of VMs

Get-vApp ReadSensitiveWorkload |
    Get-VM |
    Get-HardDisk | Where-Object {
        ($_.Name -ne "Hard disk 1") -and
           (
            (Get-HarddiskVFRC $_).ReservationMB -eq $null
           )
       } | Foreach-Object {
       Set-HarddiskVFRC -Disk $_ -Enable -BlocksizeKB 4 -ReservationMB 128
    }

VM            : test2
DiskName      : Hard disk 2
ReservationMB : 128
CacheType     : strong
CacheMode     : write_thru
BlockSizeKB   : 4
VFlashModule  : vfc

VM            : test1
DiskName      : Hard disk 2
ReservationMB : 128
CacheType     : strong
CacheMode     : write_thru
BlockSizeKB   : 4
VFlashModule  : vfc

vFRC is a powerful feature that provides a significant boost to performance for VMDKs that need extra read IOPS; however, there are some catches you should be aware of:

  • SSD devices cannot be shared with VSAN.
  • Adjusting the size of the cache will cause the current contents to be discarded.
  • VMDKs must be specified—vFRC will not accelerate all read operations to/from the host.

If you have virtual machines that can benefit from increased read IOPS and decreased read latency and you have hosts with SSDs installed, then leveraging vFRC is an inexpensive way to provide the needed boost. Adding drives to your shared storage solution can quickly become expensive, whereas with vFRC you can easily manage the cost and balance the capacity so that only those VMs that require the additional capability get it, thus ensuring maximum efficiency.

Manage DRS Groups

Distributed Resource Scheduler (DRS) is one of the defining features of vCenter and vSphere. It enables a virtualization administrator to add servers into a pool (also known as a cluster), after which the software balances the resource consumption across them. This is a simple process that allows greater utilization of hardware. However, it hasn’t been without warts and a couple of features that would make life a lot easier.

Fortunately, in vCenter 5.1 one of the most frequently requested features, DRS groups, was added. By grouping hosts and VMs together, administrators can communicate the concept of locality and applications to vCenter and apply rules at that granularity.

Let’s say that you have two racks of servers in the same cluster and you want to make sure that your domain controllers stay in separate racks. With groups, this is trivial; you create a group for each rack and the VMs, and then create two affinity rules for the VMs, and the desired configuration is quickly achieved. This configuration can be done using the web or desktop clients, but that process is quite click-intensive. We have created three functions that create a DRS host group (Listing 5-10), a VM group (Listing 5-11), and finally an affinity rule for the two groups (Listing 5-12).

Listing 5-10: The New-DrsHostGroup function

function New-DrsHostGroup {
    <#  .SYNOPSIS
        Create a DRS host group.
        
        .DESCRIPTION
        Creates a DRS host group in the specified cluster using one,
        or more, VM hosts as members.
        
        .EXAMPLE
        Create a group with specific hosts
        New-DrsHostGroup -Cluster clusterName -VMHost host1,host2 `
          -GroupName MyGroup
        
        .EXAMPLE
        Use the pipeline to specify the cluster for the new DRS group
        Get-Cluster clusterName | New-DrsHostGroup -VMHost host1,host2 `
          -GroupName MyGroup
        
        .PARAMETER Cluster
        [System.String]
        The name of the cluster to create the group in.
        
        .PARAMETER VMHost
        [System.String][]
        An array of hosts to put into the newly created group.
        
        .PARAMETER GroupName
        [System.String]
        A name for the new group.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
    #>
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [Alias('Name')]
        [String]
        $Cluster
        ,

        [parameter(Mandatory=$true)]
        [String[]]
        $VMHost
        ,

        [parameter(Mandatory=$true)]
        [String]
        $GroupName
    )

    $clusterObj = Get-Cluster -Name $Cluster

    $clusterSpec = New-Object VMware.Vim.ClusterConfigSpecEx

    $hostGroup = New-Object VMware.Vim.ClusterGroupSpec

    # add, edit or remove the DRS group
    $hostGroup.operation = "add"

    # specify that this is a host group
    $hostGroup.Info = New-Object VMware.Vim.ClusterHostGroup

    # give it a name
    $hostGroup.Info.Name = $GroupName
    # add the host MoRefs

    $VMHost | Foreach-Object {

        $hostGroup.Info.Host += (Get-VMHost $_).Id
    }

    # add the group to the cluster settings specification
    $clusterSpec.GroupSpec += $hostGroup

    # execute the reconfigure method
    $clusterObj.ExtensionData.ReconfigureComputeResource(
        # provide the specification created above
        $clusterSpec,

        # set to true to update the cluster, set to false
        # to unconfigure the cluster, except for what was set
        # as a part of this specification
        $true
    )
}

This function is used to create DRS host groups. However, it can be modified very easily to edit or remove existing groups by changing line 31 from $hostGroup.operation = "add" to $hostGroup.operation = "edit" or $hostGroup.operation = "remove". This simple ability to specify what type of operation needs to be done is true of many of the modification specification tasks that are used by VMware’s SDK.

Note that the second parameter for the ReconfigureComputeResource method invocation, a Boolean option in addition to configuration specification, is very important. This specifies that we are updating the cluster’s configuration. Without it, any settings not provided in our specification will be unset, which could make for a very bad day!

Listing 5-11: The New-DrsVmGroup function

function New-DrsVmGroup {
    <#  .SYNOPSIS
        Create a DRS virtual machine group.
        
        .DESCRIPTION
        Creates a DRS virtual machine group in the specified 
        cluster using one, or more, VMs as members.
        
        .EXAMPLE
        Create a group with specific VMs
        New-DrsVmGroup -Cluster clusterName -VM vm1,vm2 `
          -GroupName MyVMGroup
        
        .EXAMPLE
        Use the pipeline to specify the cluster for the new DRS group
        Get-Cluster clusterName | New-DrsVmGroup -VM vm1,vm2 `
          -GroupName MyVMGroup
        
        .PARAMETER Cluster
        [System.String]
        The name of the cluster to create the group in.
        
        .PARAMETER VMH
        [System.String][]
        An array of VMs to put into the newly created group.
        
        .PARAMETER GroupName
        [System.String]
        A name for the new group.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        
    #>
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [Alias('Name')]
        [String]
        $Cluster
        ,

        [parameter(Mandatory=$true)]
        [String[]]
        $VM
        ,

        [parameter(Mandatory=$true)]
        [String]
        $GroupName
    )

    $clusterObj = Get-Cluster -Name $Cluster

    $clusterSpec = New-Object VMware.Vim.ClusterConfigSpecEx

    $vmGroup = New-Object VMware.Vim.ClusterGroupSpec

    # add, edit, or remove the VM group
    $vmGroup.operation = "add"

    # specify that this is a VM group
    $vmGroup.Info = New-Object VMware.Vim.ClusterVmGroup

    # give it a name
    $vmGroup.Info.Name = $GroupName

    # add the VMs to the group
    $VM | Foreach-Object {
        $vmGroup.Info.VM += (Get-VM $_).id
    }

    # add the VM group to the cluster specification
    $clusterSpec.GroupSpec += $vmGroup

    # execute the cluster reconfigure
    $clusterObj.ExtensionData.ReconfigureComputeResource(
        # provide the specification
        $clusterSpec,

        # update the cluster config
        $true
    )
}

This function is nearly identical to the function for creating a host group and has the same ability to be modified to edit or remove a VM group. The next function, in Listing 5-12, is used to set the group affinity by combining the virtual machine and host groups created using the previous functions with the logic to create rule sets.

Listing 5-12: The New-DrsGroupAffinity function

function New-DrsGroupAffinity {
    <#  .SYNOPSIS
        Create DRS affinity rule for a VM and host group.
        
        .DESCRIPTION
        Creates a DRS affinity group in the specified cluster using 
        the host and VM groups provided as members. If mandatory is
        false, then the rule is a "should" rule, not a "must" rule.
        
        .EXAMPLE
        Create a mandatory group
        Get-Cluster clusterName | New-DrsGroupAffinity `
          -HostGroup MyGroup -VmGroup MyVmGroup `
          -RuleName MyAffineGroup -Mandatory
        
        .PARAMETER Cluster
        [System.String]
        The name of the cluster to create the group in.
        
        .PARAMETER HostGroup
        [System.String]
        The name of the host group to add to the rule.
        
        .PARAMETER VmGroup
        [System.String]
        The name of the VM group to add to the rule.
        
        .PARAMETER RuleName
        [System.String]
        The name of the rule.
        
        .PARAMETER Mandatory
        [System.Boolean]
        If true, rule is a "must", otherwise it is a "should".
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        
    #>
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [Alias('Name')]
        [String]
        $Cluster
        ,

        [parameter(Mandatory=$true)]
        [String[]]
        $HostGroup
        ,

        [parameter(Mandatory=$true)]
        [String]
        $VmGroup
        ,

        [parameter(Mandatory=$true)]
        [String]
        $RuleName
        ,

        [parameter(Mandatory=$false)]
        [Switch]
        $Mandatory = $false
    )

    $clusterObj = Get-Cluster $Cluster

    $clusterSpec = New-Object VMware.Vim.ClusterConfigSpecEx

    $rule = New-Object VMware.Vim.ClusterRuleSpec

    # add, edit, remove the rule
    $rule.operation = "add"

    # the type of this object determines the type of rule being
    # created:
    #   ClusterVmHostRuleInfo = VM(s) (anti)affinity to host(s)
    #   ClusterAffinityRuleSpec = VMs will be together
    #   ClusterAntiAffinityRuleSpec = VMs will be separated
    #
    $rule.Info = New-Object VMware.Vim.ClusterVmHostRuleInfo

    # enable or disable the rule
    $rule.Info.enabled = $true

    # a name
    $rule.Info.name = $RuleName

    # this has different actions depending on the type of rule.
    #  - for ClusterVmHostRuleInfo:
    #    - setting mandatory to false is the equivalent of a
    #      "should" rule
    #    - setting mandatory to true is the equivalent of a
    #      "must" rule
    #  - for VM affinity and antiaffinity rules:
    #    - true will prevent the VMs from powering on if the
    #      rule will be violated
    #    - false will allow the VMs to be powered on and DRS
    #      will attempt to keep the rule in compliance
    $rule.Info.mandatory = $Mandatory

    # the name of the VM group
    $rule.Info.vmGroupName = $VmGroup

    # if we want to keep the VMs on the specified hosts, use an
    # affine group
    $rule.Info.affineHostGroupName = $HostGroup

    # alternately, to keep the VMs off the specified hosts, use
    # and antiaffine group
    # rule.Info.antiAffineHostGroupName = $HostGroup

    # add our rules to the cluster specification
    $clusterSpec.RulesSpec += $rule

    # execute the cluster reconfigure
    $clusterObj.ExtensionData.ReconfigureComputeResource(
        # provide the specification
        $clusterSpec,

        # update the cluster config
        $true
    )
}

Pay close attention to the comments in the function created using Listing 5-12. This example function provides the basis to configure many different kinds of DRS rules in your cluster. For example, if you want VMs to be kept off of a particular group of hosts, you would use an antiAffineHostGroupName rule in your function. This same pattern is followed when specifying DRS rules for individual VMs, rather than DRS groups.

Now that we have our three base functions, we can put them together to create DRS groups and a rule that will ensure that our hosts and VMs are kept together (see Listing 5-13).

Listing 5-13: Using DRS groups to enforce affinity

Get-Cluster $clustername | `
  New-DrsHostGroup -GroupName $hostGroup `
        -VMHost $host1,$host2
Get-Cluster $clustername | `
  New-DrsVmGroup -GroupName $vmGroup -VM $vm1,$vm2
Get-Cluster $clustername | `
    New-DrsGroupAffinity -HostGroup $hostGroup `
        -VmGroup $vmGroup -RuleName $ruleName -Mandatory:$false

Using these functions and their brethren capable of editing and removing the respective objects, it becomes easy to maintain affinity and anti-affinity rules for your VM and host groups. This is particularly useful where you are using a vSphere Metro Storage Cluster (vMSC) configuration. It is unwise to have VM storage traffic traversing the intersite links; those need to be using bandwidth for storage replication. Creating a scheduled task to maintain the correct locality affinity can significantly save on bandwidth between sites; it removes complexity during the provisioning process. Neither junior administrators nor an automated deployment system need to know or understand the underlying physical architecture and limitations. Instead your automation ensures that the VM layout is always optimal.

Use Fault Tolerance

VMware Fault Tolerance (FT) was first introduced with vSphere 4.0. FT is an extension of VMware High Availability (HA) that enables guaranteed zero downtime. At a high level, it works by creating a second VM on a compatible vSphere host and replicates every external input to the CPU from the primary VM to the secondary VM. This results in the processors executing the same internal code on a per-instruction basis. Then, if the primary VM dies for any reason, the secondary VM continues executing and picks up where the primary left off. The operating system has no knowledge that it just blinked and awakened on a different physical host. More importantly, your users won’t know either. So, how do you enable this uptime pixie dust? In PowerCLI, it’s one line (see Listing 5-14).

Listing 5-14: Enabling FT

(Get-VM "HMIC").ExtensionData.CreateSecondaryVM_Task($null)

Optionally, you could even designate which VMHost the secondary VM is created on by supplying the VMHost’s managed object reference, or MoRef (see Listing 5-15).

Listing 5-15: Specifying where the secondary VM should be created

$VMHost = Get-VMHost -Name 'vSphere01*'
$VM = Get-VM -Name 'HVMIC'
$VM.ExtensionData.CreateSecondaryVM_Task($VMHost.Id)

As we just showed, it’s simple to enable FT. It’s just as simple to disable, as Listing 5-16 shows.

Listing 5-16: Disabling FT

$VM = Get-VM -Name 'HVMIC' | Where-Object {
  $_.ExtensionData.Config.FtInfo.Role -eq 1}
$VM.ExtensionData.TurnOffFaultToleranceForVM()

You will find that this highly protected state carries with it some restrictions. For instance, you cannot modify any configuration or settings for the VM while it’s protected with FT. You will need to follow these steps:

  1. Disable FT on the VM.
  2. Make the change (virtual hardware, SvMotion, vSphere vStorage API for Data Protection [VADP]).
  3. Enable FT on the VM.

Fortunately, it’s relatively easy to wrap the whole change in a PowerCLI script. In Listing 5-17, we demonstrate changing the RAM allocation on an FT-protected VM.

Listing 5-17: Modifying FT-protected VMs

# Get the VM
$VM = Get-VM -Name 'HVMIC' | Where-Object {
  $_.ExtensionData.Config.FtInfo.Role -eq 1}
# Disable FT
$VM.ExtensionData.TurnOffFaultToleranceForVM()
# Add memory
Set-VM -VM $VM -MemoryMB 4096 -Confirm:$false
# Enable FT
$VM.ExtensionData.CreateSecondaryVM_Task($null)

We don’t feel FT replaces the need for application-level redundancy, and it does not replace backups. However, if your application users demand extreme availability and the virtual machine matches the constraints of FT, it is an excellent option with relatively little administrative overhead. Should you choose to enable FT in your virtual environment, PowerCLI is the glue that allows you to manage FT-protected VMs at scale.

Use Distributed Power Management

Distributed Power Management (DPM) is an extension of the Distributed Resource Scheduler (DRS). DPM focuses on maximizing the power efficiency of your virtual environment by powering physical hosts down when not needed and turning them back on when the additional capacity is required. DPM is enabled on a per-cluster basis and achieves these power savings by carefully balancing the load across a given cluster. Once enabled, DPM then carefully monitors the resource utilization of the cluster—and particularly of each host. When it determines that consolidating VMs onto fewer hosts will result in a host being unused, it will execute those vMotion operations and then power off the unused host. When an increase in load is detected DPM will power on hosts to ensure sufficient capacity to meet the demands of the environment. All in all, DPM is a fantastic technology and should be enabled on all environments.

Unfortunately as of this writing, PowerCLI doesn’t offer any cmdlets for managing DPM. We wrote some you can use until VMware offers official support. So, how can you find out if you’re running DPM? Listing 5-18 contains a function that gives you the answer.

Listing 5-18: The Get-DPM function

function Get-DPM {
    <#  .SYNOPSIS
        Get the current DPM status for a cluster.
        
        .EXAMPLE
        Get the DPM status for a cluster
        Get-Cluster clusterName | Get-DPM
        .PARAMETER Cluster
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        The cluster to check.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        
        .OUTPUTS
        PSCustomObj
    #>
    [CmdletBinding()]

    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [Alias('Name')]
        [String]
        $Cluster

    )
    process {
        # get the view's extended configuration data
        $clusterObj = Get-Cluster $Cluster
        $clusterView = $ClusterObj | Get-View -Property Name,ConfigurationEx

        $dpmInfo = $clusterView.ConfigurationEx.DpmConfigInfo

        # an anon object to hold only the data we care about
        $info = "" | Select-Object Name,Status,Threshold,Behavior

        # Set the properties in our anon object based on the
        # different sources.
        $info.Name = $clusterView.Name

        # use a friendly name instead of a boolean
        if ($dpmInfo.Enabled -eq $false) {
            $info.Status = "Disabled"
        } else {
            $info.Status = "Enabled"
        }

        $info.Behavior = $dpmInfo.DefaultDpmBehavior
        $info.Threshold = $dpmInfo.HostPowerActionRate

        # return the object
        $info

    }
}

Using the Get-DPM function, you can quickly get the status of DPM running across the environment in one line:

 Get-Cluster | Get-DPM

Once you’ve identified the clusters that are not running DPM, you can use the Set-DPM function shown in Listing 5-19 to configure DPM.

Listing 5-19: The Set-DPM function

function Set-DPM {
    <#  .SYNOPSIS
        Configures DPM for a cluster.
        
        .EXAMPLE
        Enable DPM for a cluster
        Get-Cluster clusterName | Set-DPM -Enable
        
        .EXAMPLE
        Enable DPM for a cluster and set it to manual
        Get-Cluster clusterName | Set-DPM -Enable -Behavior Manual
        
        .PARAMETER Cluster
        [System.String]
        The cluster to check.
        
        .PARAMETER Enable
        [System.Boolean]
        Enable DPM.
        
        .PARAMETER Disable
        [System.Boolean]
        Disable DPM.
        
        .PARAMETER Threshold
        [System.Integer]
        A value between 1 and 5 indicating the aggressiveness of DPM 
        actions.  1 is most aggressive, 5 is least.
        
        .PARAMETER Behavior
        [System.String]
        Manual or Automated, indicating whether DPM will automatically
        apply recommendations or wait for the user to apply.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.ClusterImpl]
        
        .OUTPUTS
        PSCustomObj
    #>
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true,
            ParameterSetName="EnableDpm"
        )]
        [parameter(
            Mandatory=$true,
            ValueFromPipelineByPropertyName=$true,
            ParameterSetName="DisableDpm"
        )]
        [Alias('Name')]
        [String]
        $Cluster
        ,

        [parameter(
            Mandatory=$true,
            ParameterSetName="EnableDpm"
        )]
        [Switch]
        $Enable
        ,

        [parameter(
            Mandatory=$true,
            ParameterSetName="DisableDpm"
        )]
        [Switch]
        $Disable
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableDpm"
        )]
        [ValidateRange(1, 5)]
        [Int]
        $Threshold
        ,

        [parameter(
            Mandatory=$false,
            ParameterSetName="EnableDpm"
        )]
        [ValidateSet("Automated", "Manual")]
        [String]
        $Behavior

    )
    process {
        # an array to hold messages
        $whatIf = @()

        # get the relevant config data
        $clusterObj = Get-Cluster $Cluster
        $clusterView = $clusterObj | Get-View -Property Name

        $dpmConfig = New-Object VMware.Vim.ClusterDpmConfigInfo

        # set the operation based on the Enable/Disable property
        # also, set the WhatIf operation
        if ($Disable) {
            $dpmConfig.Enabled = $false
            $whatIf += "Disabling DPM"
        }

        if ($Enable) {
            $dpmConfig.Enabled = $true
            $whatIf += "Enabling DPM"

            # set the remaining properties if provided
            if ($Behavior) {
                $dpmConfig.DefaultDpmBehavior = `
                    [VMware.Vim.DpmBehavior]::$Behavior
                $whatIf += "Setting behavior to: $($Behavior)"
            }

            if ($Threshold) {
                $dpmConfig.HostPowerActionRate = $Threshold
                $whatIf += "Setting Threshold to: $($Threshold)"
            }
        }

        # create a config spec and set our info
        $clusterConfig = New-Object `
            VMware.Vim.ClusterConfigSpecEx
        $clusterConfig.DpmConfig = $dpmConfig

        if ($PSCmdlet.ShouldProcess(
            $clusterView.Name,
            $whatIf -join ", "
            )
        ) {
            # execute the update
            $taskId = $clusterView.`
                ReconfigureComputeResource_Task(
                    $clusterConfig,
                    $true
                )

            $task = Get-View $taskId

            # wait for the update to finish
            while (
                "running", "queued" -contains $task.Info.State
            ) {
                $task.UpdateViewData("Info")
                Start-Sleep -Seconds 1
            }

            # return an error or the current status
            if ($task.Info.State -eq "error") {
                Write-Error $task.info.Error.LocalizedMessage
            } else {
                $clusterObj | Get-DPM
            }
        }
    }
}

Putting it all together, to enable DPM on any cluster where it is currently disabled, you would run the following:

Get-Cluster |
    Get-DPM |
    Where-Object { $_.Status -eq "Disabled" } |
    Set-DPM -Enable

You can also perform basic administration. For example, you can set the host power action rate to 4 and the default DPM behavior to automatic with just one line of PowerCLI:

Get-Cluster |
    Get-DPM |
    Where-Object { $_.Status -eq "Enabled" } |
    Set-DPM -Behavior Automated -Threshold 4 -Enable

Now that you can automate DPM, get out there and save some energy! In all seriousness, it’s understandable to be apprehensive about shutting down vSphere hosts. Our advice is to start conservatively and test DPM in your environment. Slowly, as you gain confidence and start to realize the power savings, you will naturally crank up the automation level. If you’re not currently using DPM, there is no reason not to begin testing. The power costs associated with a datacenter are one of the largest ongoing expenses associated with servers. Who knows? Cut the power bill and perhaps you can talk your boss into a trip to VMWorld!

Configure Host Profiles

Host profiles are used to ensure compliance across a series of hosts within vCenter Server. This is accomplished by identifying a reference host and creating a host profile. The host profile captures the configuration of that host and saves it into the vCenter Server database. At any time after that, you can test the configuration of a given vSphere host against that profile and report on compliance. If a host has fallen out of compliance, you simply reapply the profile. As of vSphere 6, host profiles currently cover the following configuration settings:

  • Advanced configuration options
  • Authentication
  • Date/time
  • Firewall
  • Groups
  • Memory reservations
  • Networking
  • Security
  • Services
    • Storage
    • Users

Each new version of vSphere increases the coverage of host profiles and eliminates many of the settings that previously would require further automation to complete configuration. Despite this, there are some notable items that cannot be configured or monitored via host profiles:

  1. Storage LUN multipathing Path Selection Plug-in (PSP) selection
  2. Network Selection of physical network adapters based on VLAN

Getting started with host profiles is a snap. Simply configure one host to your organization’s standards and create a new host profile. In Listing 5-20, we created a host profile for a cluster named Prod01 based on a vSphere host named vSphere01.

Listing 5-20: Creating a new host profile

New-VMHostProfile -Name Prod01 `
    -ReferenceHost (Get-VMHost vSphere01*) `
    -Description "Host profile for cluster Prod01"

Once the new profile is created, you can attach it to any vSphere host/cluster in vCenter Server. The code in Listing 5-21 associates the Prod01 profile to the Prod01 cluster, and then tests every host in the cluster for compliance.

Listing 5-21: Associating a host profile and checking for compliance

Apply-VMHostProfile -Entity (Get-Cluster prod01) `
    -Profile (Get-VMHostProfile prod01) `
    -AssociateOnly |
        Get-VMHost |
        Test-VMHostProfileCompliance

You could even take it a step further and apply your new profile, as shown in Listing 5-22.

Listing 5-22: Applying a host profile to any noncompliant host

Get-Cluster Prod01 |
Get-VMHost |
Test-VMHostProfileCompliance |
    ForEach-Object {
        $profile = Get-VMHostProfile $_.VMHostProfile
        Set-VMHost -State 'Maintenance' -VMHost $_.VMhost |
            Apply-VMHostProfile -Profile $Profile |
            Set-VMHost -State 'Connected' |
            Test-VMHostProfileCompliance
    }

Of course, no environment is static. From time to time, you will need to make changes to hosts under the control of a host profile. As fantastic as vMotion is, it does take quite a bit of time to evacuate a host—and applying a profile requires that a host be in Maintenance mode. Therefore, when you’re making changes we highly recommend using the following workflow:

  1. Script the change needed to update all affected vSphere hosts in PowerCLI.
  2. Update the host profile.
  3. Test for compliance.

For example, the script in Listing 5-23 adds a new NFS datastore, updates the host profile, and then scans for compliance.

Listing 5-23: Making changes on a cluster using host profiles

$cluster = Get-Cluster prod01

# Add the datastore
$cluster | Get-VMHost |
    New-Datastore -Name prod01_03 `
        -Nfs `
        -NfsHost 192.168.1.3 `
        -Path /vol/prod01_03

# get the profile for the cluster
$VMhostProfile = $cluster | Get-VMHostProfile

# update the profile from the reference host
$profileSpec = New-Object VMware.Vim.HostProfileHostBasedConfigSpec
$profileSpec.host = `
    (Get-View -Id $VMhostProfile.ReferenceHostId -Property Name).MoRef
$profileSpec.useHostProfileEngine = $true

$VMhostProfile.ExtensionData.UpdateHostProfile( $profileSpec )

# test compliance for all hosts
$cluster | Get-VMHost | Test-VMHostProfileCompliance

If you are fortunate enough to have the licensing, enjoy host profiles! They are a fantastic tool that truly simplifies the management of any size environment.

Configure Active Directory Integration

Active Directory (AD) integration has been refined over the last several versions of PowerCLI and now has been simplified down to just two commands: Get-VMHostAuthentication (Listing 5-24) and Set-VMHostAuthentication (Listing 5-25). Using AD to authenticate users for vSphere Hypervisor access is a simple, easy-to-maintain, and efficient method of ensuring that only authorized users are able to connect to the hosts using the CLI or vSphere Client. Using this method also provides a quick and easy way to ensure that when administrators join or leave your team, their access can quickly be updated from a single point.

Listing 5-24: Getting the current host authentication settings

Get-VMHost $hostname | Get-VMHostAuthentication

Domain             DomainMembershipStatus         TrustedDomains
------             ----------------------         --------------

Note that for the particular ESXi host in Listing 5-24 no Active Directory authentication has been defined; hence no domain membership is listed. To join the host to a domain, pipe the output of the Get-VMHostAuthentication cmdlet into the Set-VMHostAuthentication command.

Listing 5-25: Joining an ESXi host to a domain

$domainname = "powercli.lan"
$credential = Get-Credential
$hostname = "esxi-01.powercli.lan"

$splat = @{
    'Domain' = $domainname;
    'Credential' = $credential;
}

Get-VMHost $hostname |
    Get-VMHostAuthentication |
    Set-VMHostAuthentication @splat -JoinDomain

Now when you execute the Get-VMHostAuthentication against the host, you can see that it is joined to the domain.

By default the administrators group for the ESXi host is set to ESX Admins, but since this is a well-known group, it may be undesirable to leave it from a security perspective. You can change the administrators group for the host by adjusting the value of a particular advanced option: Config.HostAgent.plugins.hostsvc.esxAdminsGroup. You can use the web or desktop clients to modify the setting or use a simple PowerShell function, as shown in Listing 5-26.

Listing 5-26: The Set-VMHostADAdminGroup function

function Set-VMHostADAdminGroup {
    <#  .SYNOPSIS
        Sets the Active Directory group to be used for ESXi host
        administrators.
        
        .EXAMPLE
        Get-VMHost host1 | Set-VMHostADAdminGroup -Group "VM Admins"
        
        .PARAMETER VMHost
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
        The host to modify.
        
        .PARAMETER GroupName
        [System.String]
        The name of the group to assign as the ESXi administrator.
        
        .INPUTS
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
        
        .OUTPUTS
        PSCustomObj
    #>
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [parameter(
            Mandatory=$true,
            ValueFromPipeline=$true
        )]
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl]
        $VMHost

    ,   [Parameter(Mandatory=$true)]
        [String]$Group

    )
    process {
        $VMHost | Foreach-Object {
            if ($PSCmdlet.ShouldProcess(
                $_.Name,
                "Setting esxAdminsGroup to $($Group)"
            )) {
                # if the user approves, update the advanced
                # setting for this host
                $_ | Get-AdvancedSetting -Name `
                Config.HostAgent.plugins.hostsvc.esxAdminsGroup |
                    Set-AdvancedSetting -Value $Group -Confirm:$false |
                    Out-Null

                # create an anon object to return the current setting
                $obj = "" | Select-Object "AdminGroup"
                # get the current setting and populate the property
                $obj.AdminGroup = ($VMHost | Get-AdvancedSetting -Name `
                    Config.HostAgent.plugins.hostsvc.esxAdminsGroup).Value

                # return/display the current value
                $obj
            }
        }
    }
}

The Set-VMHostADAdminGroup function simplifies setting the administrators group by allowing you to pipeline the host object, as shown in Listing 5-27.

Listing 5-27: Using the Set-VMHostADAdminGroup cmdlet

$groupname = "vSphere Host Admins"
Get-VMHost $hostname | Set-VMHostADAdminGroup -Group $groupname

AdminGroup
----------
vSphere Host Admins

Many of these advanced features make the core of what differentiates VMware’s vSphere from the other hypervisors. Utilizing your infrastructure—and your hypervisor—to its fullest ensures that you are deriving the most value from your investment. Although the features are what motivate you to continue using ESXi as the hypervisor of choice, PowerCLI offers an incredibly robust and capable platform to provide the automation framework for all your tasks. By capitalizing on automation, you eliminate human error, misconfiguration, and the inevitable downtime that results.

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

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