Useful vSphere PowerCLI scripts

I have been creating and using PowerCLI scripts for vSphere a lot again lately. And I thought it was a good idea to finally take all the snippets I collected and created over time and put them into one spot. The scripts in this post come in to play after the ESXi hosts are installed and the vCenter is up and running. If you are interested in deploying vCenter automatically you should check out my blog post about migrating from embedded to external PSC. In this post I will go over using the vcsa install tool. In here it is all PowerCLI, check out the scripts below.

  1. Create vCenter clusters
  2. Add ESXi hosts to vCenter clusters
  3. Create distributed switch and port groups
  4. Migrate hosts from vSwitch to distributed switch
  5. Create additional VM kernel ports
  6. Remove vSwitch0 from all hosts
  7. Create (sub) folders in vCenter
  8. DRS host groups
  9. Create and populate datastore clusters
  10. Change local ESXi host datastore names
  11. Supporting files
  12. Modules

As you can see, there are quite a few scripts here so this blog post will be longer then usual.

1. Create vCenter clusters

This script is used to create the initial datacenter object and multiple vCenter clusters. The script can configure all of the major settings  for HA and DRS. Some of the functions are not available in the latest version of vSphere PowerCLI. Things like Admission Control, Datastore Heartbeat, VMCP Settings or VM Monitoring are missing from the New-Cluster cmdlet. To enable this functionality I made use of some extra modules (more details below).

# ------------------------------------------------------------------------------------------------------------------
# Script to create vSphere clusters including the most common settings
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Modules are psm1 files located in the user profile under \My Documents\WindowsPowerShell\Modules\<modulen_name>\<module_name.psm1> and are imported here
# to add functionality that is not yet present in the default cmdlets

Import-Module AdmissionConfig
Import-Module DsHeartBeatConfig
Import-Module VMCPSettings
Import-Module VMMonitoring

# Create initial datacenter object

$location = Get-Folder -NoRecursion
New-Datacenter -Name "Datacenter1" -Location $location

# Import and loop through a CSV file containing the clusters names, admission controll CPU and MEM percentage and if it is a stretched cluster

Import-Csv clusters.txt | Foreach-Object {

New-Cluster -Name $_.name -DrsAutomationLevel FullyAutomated -DrsEnabled -EVCMode "intel-haswell" -HAAdmissionControlEnabled -HAEnabled -HAIsolationResponse DoNothing -Location "Datacenter1" -VMSwapfilePolicy WithVM

Get-cluster -name $_.name | Set-HAAdmissionControlPolicy -percentCPU $_.admissionCPU -percentMem $_.admissionMEM

Get-Cluster -name $_.name | Set-DatastoreHeartbeatConfig -Option allFeasibleDs

Get-Cluster -name $_.name | Set-VMCPSettings -enableVMCP:$True -VmStorageProtectionForPDL restartAggressive -VmStorageProtectionForAPD restartConservative -VmReactionOnAPDCleared none -Confirm:$false

#Stretched clusters get extra settings

if ($_.isStretched -eq "true") {

    # To set the VM Monitoring values
    Set-ClusterDasVmMonitoring -cluster $_.name -Option vmMonitoringOnly -interval 50 -maxfail 3

    # Set advanced settings
    New-AdvancedSetting -Entity $_.name -Type ClusterHA -Name das.isolationaddress[0] -Value 10.10.10.1 -Confirm:$false
    New-AdvancedSetting -Entity $_.name -Type ClusterHA -Name das.isolationaddress[1] -Value 10.10.20.1 -Confirm:$false
    New-AdvancedSetting -Entity $_.name -Type ClusterHA -Name das.heartbeatdsperhost -Value 4 -Confirm:$false
    New-AdvancedSetting -Entity $_.name -Type ClusterHA -Name das.usedefaultisolationaddress -Value false -Confirm:$false
    }
}

Back to index

2. Add ESXi hosts to vCenter clusters

After adding the required clusters it is time to bring the ESXi hosts in. This script will add ESXi hosts to vCenter based on a comma separated file. Hosts are placed in maintenance mode and added to the correct cluster. Finally the hosts are taken out of maintenance mode.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to add new ESXi hosts to the vCenter server and in the different clusters based on a CSV file
# with the hostname and the destination cluster.
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

Import-Csv hosts.txt | Foreach-Object {

  Add-VMHost $_.hostname -Location (Get-Datacenter "Datacenter1") -User root -Password VMware1! -RunAsync -force:$true -Confirm:$false
  Get-VMHost -Name $_.hostname | Set-VMHost -State Maintenance
  Get-VMHost -Name $_.hostname | Move-VMHost -Destination $_.cluster -RunAsync -Confirm:$false
  Get-VMHost -Name $_.hostname | Set-VMHost -State Connected

}

Back to index

3. Create Distributed switch and port groups

This script creates a single distributed switch and several port groups. The port group settings like VLAN, load balancing scheme and active uplinks are set as well.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to create the VDSwitch and all needed portgroups and their individual settings
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Create VDswitch

$vds_name = "VDS-01"
$vds = New-VDSwitch -Name $vds_name -Location (Get-Datacenter -Name "Datacenter1") -mtu 9000 -LinkDiscoveryProtocol LLDP -LinkDiscoveryProtocolOperation Listen -confirm:$false

# Create DVPortgroups

$pg1 = New-VDPortgroup -Name "PG-10-ESXi" -Vds $vds
$pg2 = New-VDPortgroup -Name "PG-20-Prod" -Vds $vds -VlanId 20
$pg3 = New-VDPortgroup -Name "PG-30-vMotion1" -Vds $vds -VlanId 30
$pg4 = New-VDPortgroup -Name "PG-30-vMotion2" -Vds $vds -VlanId 30
$pg5 = New-VDPortgroup -Name "PG-40-FT" -Vds $vds -VlanId 40

# Adjust DVPortgroup Setting Load Based Teaming

Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg1 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy LoadBalanceLoadBased
Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg2 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy LoadBalanceLoadBased
Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg5 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy LoadBalanceLoadBased

# Adjust DVPortgroup Setting Active Uplinks

Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg3 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort uplink1
Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg3 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -UnusedUplinkPort uplink2
Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg4 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort uplink2
Get-VDSwitch -Name $vds | Get-VDPortgroup -Name $pg4 | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -UnusedUplinkPort uplink1

Back to index

4. Migrate hosts from standard switch to distributed switch

This script is an important one and can save you a lot of hours. The process of moving multiple ESXi hosts from a standard switch to a distributed switch can be a time consuming task. This script will do it all for you based on a list of hosts. The base for this script came from William Lam who created this back in 2013.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to migrate all hosts in the different clusters to the VDSwitch
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Get VDSwitch object

$vds_name = "VDS-01"
$vds = Get-VDSwitch -Name $vds_name

# Set vmnic name

$nic1 = vmnic0
$nic2 = vmnic1
$nic3 = vmnic2
$nic4 = vmnic3

  # Loop through CSV file with hosts

  Import-Csv hosts.txt | Foreach-Object {

  # Add ESXi host to VDS

  Write-Host "Adding" $_.hostname "to" $vds_name
  $vds | Add-VDSwitchVMHost -VMHost $_.hostname

  # Migrate first 2 nics to VDS

  Write-Host "Adding $nic1 and $nic2 to" $vds_name
  $vmhostNetworkAdapter = Get-VMHost $_.hostname | Get-VMHostNetworkAdapter -Physical -Name $nic1
  $vds | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -Confirm:$false
  $vmhostNetworkAdapter = Get-VMHost $_.hostname | Get-VMHostNetworkAdapter -Physical -Name $nic2
  $vds | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -Confirm:$false

  # Migrate Management VMkernel interface to VDS

  $mgmt_portgroup = "PG-10-ESXi"
  $dvportgroup = Get-VDPortGroup -name $mgmt_portgroup -VDSwitch $vds
  $vmk = Get-VMHostNetworkAdapter -Name vmk0 -VMHost $_.hostname
  Write-Host "Migrating" $vmk "to" $vds_name
  Set-VMHostNetworkAdapter -PortGroup $dvportgroup -VirtualNic $vmk -confirm:$false

  # Migrate last 2 nics to VDS

  Write-Host "Adding $nic3 and $nic4 to" $vds_name
  $vmhostNetworkAdapter = Get-VMHost $_.hostname | Get-VMHostNetworkAdapter -Physical -Name $nic3
  $vds | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -Confirm:$false
  $vmhostNetworkAdapter = Get-VMHost $_.hostname | Get-VMHostNetworkAdapter -Physical -Name $nic4
  $vds | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -Confirm:$false
}

Back to index

5. Create additional VM kernel ports

To create additional VM kernel ports for things like vMotion or Fault Tolerance Logging on all hosts you can use this PowerCLI script.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to create VMK ports other then the management VMK port
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Get VDSwitch and Portgroup objects

$vds = Get-VirtualSwitch -Name "VDS-01"
$pg1 = Get-VirtualPortGroup -Name "PG-30-vMotion1"
$pg2 = Get-VirtualPortGroup -Name "PG-30-vMotion2"
$pg3 = Get-VirtualPortGroup -Name "PG-40-FT"

# Loop through CSV file with hostnames to add VMK's to each host

Import-Csv hosts.txt | Foreach-Object {

  New-VMHostNetworkAdapter -VMHost $_.hostname -PortGroup $pg1 -VirtualSwitch $vds -Mtu 9000 -VMotionEnabled:$true
  New-VMHostNetworkAdapter -VMHost $_.hostname -PortGroup $pg2 -VirtualSwitch $vds -Mtu 9000 -VMotionEnabled:$true
  New-VMHostNetworkAdapter -VMHost $_.hostname -PortGroup $pg3 -VirtualSwitch $vds -Mtu 9000 -FaultToleranceLoggingEnabled:$true
}

Back to index

6. Remove vSwitch0 from all hosts

After all ESXi hosts are migrated to a distributed switch you might want to remove the by default created vSwitch0. The following script removes that from all hosts in a specific vCenter.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to remove vSwitch0 from all hosts after they are migrated to the Distributed Switch
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

Write-Host "Removing virtual switch vSwitch0"
Remove-VirtualSwitch -VirtualSwitch vSwitch0 -Confirm:$false

Back to index

7. Create (sub) folders in vCenter

If you need to create a lot of folders in vCenter this script will come in handy. The top level scripts are created under the hidden ‘vm’ folder. Subfolders are created based on the top level folders that where created.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to create a vCenter folder structure
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Set datacenter

$datacenter = Datacenter1

# Create top level folders

$location = Get-Datacenter -Name $datacenter | Get-Folder -Name "vm"
$folders = 
"Management",
"VRM",
"Templates",
"Jump Hosts",
"Automation",
"Backup",
"vCenter",
"vCenter Update Manager",
"SQL"

foreach ($folder in $folders) {
    New-Folder -Name $folder -Location $location
    }

# Create sub-folders Automation

$location_automation = Get-Datacenter -Name $datacenter | Get-Folder -Name "Automation"
$aut_folders = 
"vROps",
"vRO",
"vRLI",
"vRA",
"NSX"

foreach ($folder in $aut_folders) {
    New-Folder -Name $folder -Location $location_automation
    }

# Create sub-folders NSX

$location_nsx = Get-Datacenter -Name $datacenter | Get-Folder -Name "NSX"
$nsx_folders = 
"dLR's",
"Load Balancers",
"Edge Service Gateways",
"Controllers"

foreach ($folder in $nsx_folders) {
    New-Folder -Name $folder -Location $location_nsx
    }

Back to index

8. DRS host groups

At the moment of writing this script uses cmdlets that are only available in the latest version of vSphere PowerCLI. I am using PowerCLI version 6.5.4 at this time. The two cmdlets used to create and edit DRS host groups need to be used together. The reason for this is that New-DrsClusterGroup can only add one host when creating the DRS host group. To add additional hosts the Set-DrsClusterGroup must be used to add the remaining hosts.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to create DRS affinity host groups for multiple stretched clusters
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

# Create array per stretched cluster to hold hosts belonging to that cluster

$siteA_C1 = New-Object System.Collections.ArrayList
$siteA_C2 = New-Object System.Collections.ArrayList
$siteB_C1 = New-Object System.Collections.ArrayList
$siteB_C2 = New-Object System.Collections.ArrayList

# Create variables for each cluster

$cluster1 = "Cluster1"
$cluster2 = "Cluster2"

# Create variables for each group name per cluster

$drsgrpA = "Site-A-Hosts"
$drsgrpB = "Site-B-Hosts"


# Loop through CSV file to add hosts to the correct arrays

Import-Csv hosts.txt | Foreach-Object {

    if ($_.site -eq "dcr" -and $_.cluster -eq $cluster1) {
      $siteA_C1.Add($_.hostname)
    }

    if ($_.site -eq "wpr" -and $_.cluster -eq $cluster1) {
      $siteB_C1.Add($_.hostname)
    }

    if ($_.site -eq "dcr" -and $_.cluster -eq $cluster2) {
      $siteA_C2.Add($_.hostname)
    }

    if ($_.site -eq "wpr" -and $_.cluster -eq $cluster2) {
      $siteB_C2.Add($_.hostname)
    }
}

# Create host DRS groups in Automation cluster

New-DrsClusterGroup -Name $drsgrpA -Cluster $cluster1 -VMHost $siteA_C1[0] -Confirm:$false
$siteA_C1.RemoveAt(0)

New-DrsClusterGroup -Name $drsgrpB -Cluster $cluster1 -VMHost $siteB_C1[0] -Confirm:$false
$siteB_C1.RemoveAt(0)

foreach ($h in $siteA_C1) {
    $C1_grp_A = Get-DrsClusterGroup -Cluster $cluster1 -Name $drsgrpA
    Set-DrsClusterGroup -DrsClusterGroup $C1_grp_A -Add -VMHost $h
}

foreach ($h in $siteB_C1) {
    $C1_grp_B = Get-DrsClusterGroup -Cluster $cluster1 -Name $drsgrpB
    Set-DrsClusterGroup -DrsClusterGroup $C1_grp_B -Add -VMHost $h
}

# Create host DRS groups in NEI cluster

New-DrsClusterGroup -Name $drsgrpA -Cluster $cluster2 -VMHost $siteA_C2[0] -Confirm:$false
$siteA_C2.RemoveAt(0)

New-DrsClusterGroup -Name $drsgrpB -Cluster $cluster2 -VMHost $siteB_C2[0] -Confirm:$false
$siteB_C2.RemoveAt(0)

foreach ($h in $siteA_C2) {
    $C2_grp_A = Get-DrsClusterGroup -Cluster $cluster2 -Name $drsgrpA
    Set-DrsClusterGroup -DrsClusterGroup $C2_grp_A -Add -VMHost $h
}

foreach ($h in $siteB_C2) {
    $C2_grp_B = Get-DrsClusterGroup -Cluster $cluster2 -Name $drsgrpB
    Set-DrsClusterGroup -DrsClusterGroup $C2_grp_B -Add -VMHost $h
}

Back to index

9. Create and populate datastore clusters

This script speaks for it self. It will create datastore clusters and add data stores to it. It will do this based on a comma separated file.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to create datastore clusters and populate them according to a predefined list
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

$location = "Datacenter1"

Import-Csv DSClusters.txt | Foreach-Object {

  $exists = Get-DatastoreCluster -Name $_.DCname -ErrorAction SilentlyContinue

    If ($exists) {
      Write-Host Datastore Cluster with name $_.DCname already exists.
    }

    Else {
      New-DatastoreCluster -Name $_.DCname -Location $location
      Set-DatastoreCluster -DatastoreCluster $_.DCname -IOLatencyThresholdMillisecond 15 -IOLoadBalanceEnabled $false -SdrsAutomationLevel Disabled -SpaceUtilizationThresholdPercent 80
    }
}

Import-Csv DSClusters.txt | Foreach-Object {

  Move-Datastore -Confirm:$false -Datastore $_.DSname -Destination $_.DCname
}

Back to index

10. Change local datastore name on ESXI hosts

If you deploy a lot of ESXi hosts with local storage you will notice a lot if Datastore1 (x)’s in your environment. To rename them all to a more friendly name.

# ------------------------------------------------------------------------------------------------------------------
# PowerCLI script to change local datastore names ie. datastore1 (1) -> hostname-local
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

Import-Csv hosts.txt | ForEach-Object {
    get-vmhost -name $_.hostname | Get-Datastore | where {$_.name -match "datastore1"} | Set-Datastore -name $_.DSname
}

Back to index

11. Supporting files

In several scripts I am looping through a comma separated file, the formatting for these files are as follows.

clusters.txt

"name","admissionCPU","admissionMEM","isStretched"
"Cluster1",50,50,"true"
"Cluster2",50,50,"true"
"Cluster3",33,33,"false"

hosts.txt

"hostname","site","cluster","DSname"
"esx0001.home.local","site-a","Cluster1","esx0001-local"
"esx0002.home.local","site-b","Cluster1","esx0002-local"
"esx0003.home.local","site-a","Cluster2","esx0003-local"
"esx0004.home.local","site-b","Cluster2","esx0004-local"

DSClusters.txt

"DSname","DCname"
"DS-STR-C1-A-001-001","DC-DS-STR-C1-A-001"
"DS-STR-C1-A-001-002","DC-DS-STR-C1-A-001"
"DS-STR-C1-B-001-001","DC-DS-STR-C1-B-001"
"DS-STR-C1-B-001-002","DC-DS-STR-C1-B-001"
"DS-STR-C2-A-001-001","DC-DS-STR-C2-A-001"
"DS-STR-C2-A-001-002","DC-DS-STR-C2-A-001"
"DS-STR-C2-B-001-001","DC-DS-STR-C2-B-001"
"DS-STR-C2-B-001-002","DC-DS-STR-C2-B-001"

Back to index

12. Modules

The first script (create clusters) uses additional code to enhance the feature set of the script. This extra code comes in the form of modules.  Some of these modules I found on the internet because I was not familiar with this kind of scripting. I modified some of the code but left the original authors in the remarks where applicable, so all credits go to them. Module files have a specific extension, psm1.
They need to be  stored in \My Documents\WindowsPowerShell\Modules\<module_name>\<module_name.psm1>.

AdmissionConfig

This module lets you set admission control policy to a specific percentage.

function Set-HAAdmissionControlPolicy{
<#
.SYNOPSIS
Set the Percentage HA Admission Control Policy

.DESCRIPTION
Percentage of cluster resources reserved as failover spare capacity

.PARAMETER  Cluster
The Cluster object that is going to be configurered 

.PARAMETER percentCPU
The percent reservation of CPU Cluster resources

.PARAMETER percentMem
The percent reservation of Memory Cluster resources

.EXAMPLE
PS C:\> Set-HAAdmissionControlPolicy -Cluster $CL -percentCPU 50 -percentMem 50

.EXAMPLE
PS C:\> Get-Cluster | Set-HAAdmissionControlPolicy -percentCPU 50 -percentMem 50

.NOTES
Author: Niklas Akerlund / RTS
Date: 2012-01-19
#>
   param (
   [Parameter(Position=0,Mandatory=$true,HelpMessage="This need to be a clusterobject",
    ValueFromPipeline=$True)]
    $Cluster,
    [int]$percentCPU = 25,
    [int]$percentMem = 25
    )
    
    if(Get-Cluster $Cluster){
    
        $spec = New-Object VMware.Vim.ClusterConfigSpecEx
        $spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
        $spec.dasConfig.admissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
        $spec.dasConfig.admissionControlPolicy.cpuFailoverResourcesPercent = $percentCPU
        $spec.dasConfig.admissionControlPolicy.memoryFailoverResourcesPercent = $percentMem
    
        $Cluster = Get-View $Cluster
        $Cluster.ReconfigureComputeResource_Task($spec, $true)
    }
}

 

DSHeartBeatConfig

If there is a need to configure data store heart beating, you can include this module.

Function Get-DatastoreHeartbeatConfig  {
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)]
            [String[]]$Cluster
            )
   Get-Cluster $Cluster  | select Name,@{E={$_.ExtensionData.Configuration.DasConfig.HBDatastoreCandidatePolicy};L="Heartbeat Policy"}
   }
   
Function Set-DatastoreHeartbeatConfig {
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)]
            [String[]]$Cluster,
            [ValidateSet("allFeasibleDs","userSelectedDs","allFeasibleDsWithUserPreference")]
            [String[]]$Option
           )
   
    $Spec = New-Object VMware.Vim.ClusterConfigSpecEx
    $Spec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo

    $ClusterName = Get-Cluster $Cluster

    if ($Option -eq "allFeasibleDs"){
        $Spec.DasConfig.HBDatastoreCandidatePolicy = "allFeasibleDs"
        $ClusterName.ExtensionData.ReconfigureComputeResource_Task($Spec, $true)
    }
    elseif ($Option -eq "userSelectedDs"){
        $Datastores = Get-Datastore | Out-Gridview -Title "Select only two datastores" -Passthru
        $Spec.dasConfig.heartbeatDatastore = New-Object VMware.Vim.ManagedObjectReference[](2)
        $Spec.dasConfig.heartbeatDatastore[0] = New-Object VMware.Vim.ManagedObjectReference
        $Spec.dasConfig.heartbeatDatastore[0].type = "Datastore"
        $Spec.dasConfig.heartbeatDatastore[0].Value = $Datastores[0].ExtensionData.MoRef.Value
        $Spec.dasConfig.heartbeatDatastore[1] = New-Object VMware.Vim.ManagedObjectReference
        $Spec.dasConfig.heartbeatDatastore[1].type = "Datastore"
        $Spec.dasConfig.heartbeatDatastore[1].Value = $Datastores[1].ExtensionData.MoRef.Value
        $Spec.DasConfig.HBDatastoreCandidatePolicy = "userSelectedDs"
        $ClusterName.ExtensionData.ReconfigureComputeResource_Task($Spec, $true)
    }
    elseif ($Option -eq "allFeasibleDsWithUserPreference"){
        $Datastores = Get-Datastore | Out-Gridview -Title "Select only two datastores" -Passthru
        $Spec.dasConfig.heartbeatDatastore = New-Object VMware.Vim.ManagedObjectReference[](2)
        $Spec.dasConfig.heartbeatDatastore[0] = New-Object VMware.Vim.ManagedObjectReference
        $Spec.dasConfig.heartbeatDatastore[0].type = "Datastore"
        $Spec.dasConfig.heartbeatDatastore[0].Value = $Datastores[0].ExtensionData.MoRef.Value
        $Spec.dasConfig.heartbeatDatastore[1] = New-Object VMware.Vim.ManagedObjectReference
        $Spec.dasConfig.heartbeatDatastore[1].type = "Datastore"
        $Spec.dasConfig.heartbeatDatastore[1].Value = $Datastores[1].ExtensionData.MoRef.Value
        $Spec.DasConfig.HBDatastoreCandidatePolicy = "allFeasibleDsWithUserPreference"
        $ClusterName.ExtensionData.ReconfigureComputeResource_Task($Spec, $true)
    }
}

 

VMCPSettings

Another feature that is not available in the default New-Cluster cmdlet is VCMP. This module can get and set the different settings for VCMP.

function Get-VMCPSettings {
<#	
	.NOTES
	===========================================================================
	 Created on:   	10/27/2015 9:25 PM
	 Created by:   	Brian Graf
     Twitter:       @vBrianGraf
     VMware Blog:   blogs.vmware.com/powercli
     Personal Blog: www.vtagion.com

     Modified on:  	10/11/2016
	 Modified by:  	Erwan Quélin
     Twitter:       @erwanquelin
     Github:        https://github.com/equelin    
	===========================================================================
	.DESCRIPTION
    This function will allow users to view the VMCP settings for their clusters

    .PARAMETER Cluster
    Cluster Name or Object

    .PARAMETER Server
    vCenter server object

    .EXAMPLE
    Get-VMCPSettings

    This will show you the VMCP settings for all the clusters

    .EXAMPLE
    Get-VMCPSettings -cluster LAB-CL

    This will show you the VMCP settings of your cluster

    .EXAMPLE
    Get-VMCPSettings -cluster (Get-Cluster Lab-CL)

    This will show you the VMCP settings of your cluster

    .EXAMPLE
    Get-Cluster | Get-VMCPSettings

    This will show you the VMCP settings for all the clusters
#>
    [CmdletBinding()]
    param
    (
    [Parameter(Mandatory=$False,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage='What is the Cluster Name?')]
    $cluster = (Get-Cluster -Server $Server),

    [Parameter(Mandatory=$False)]
    [VMware.VimAutomation.Types.VIServer[]]$Server = $global:DefaultVIServers
    )

    Process {

        Foreach ($Clus in $Cluster) {

            Write-Verbose "Processing Cluster $($Clus.Name)"

            # Determine input and convert to ClusterImpl object
            Switch ($Clus.GetType().Name)
            {
                "string" {$CL = Get-Cluster $Clus  -Server $Server -ErrorAction SilentlyContinue}
                "ClusterImpl" {$CL = $Clus}
            }

            If ($CL) {
                # Work with the Cluster View
                $ClusterMod = Get-View -Id "ClusterComputeResource-$($CL.ExtensionData.MoRef.Value)" -Server $Server

                # Create Hashtable with desired properties to return
                $properties = [ordered]@{
                    'Cluster' = $ClusterMod.Name;
                    'VMCP Status' = $clustermod.Configuration.DasConfig.VmComponentProtecting;
                    'Protection For APD' = $clustermod.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmStorageProtectionForAPD;
                    'APD Timeout Enabled' = $clustermod.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.EnableAPDTimeoutForHosts;
                    'APD Timeout (Seconds)' = $clustermod.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmTerminateDelayForAPDSec;
                    'Reaction on APD Cleared' = $clustermod.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmReactionOnAPDCleared;
                    'Protection For PDL' = $clustermod.Configuration.DasConfig.DefaultVmSettings.VmComponentProtectionSettings.VmStorageProtectionForPDL
                }

                # Create PSObject with the Hashtable
                $object = New-Object -TypeName PSObject -Prop $properties

                # Show object
                $object
            }
        }
    }
}

function Set-VMCPSettings {
<#	
	.NOTES
	===========================================================================
	 Created on:   	10/27/2015 9:25 PM
	 Created by:   	Brian Graf
     Twitter:       @vBrianGraf
     VMware Blog:   blogs.vmware.com/powercli
     Personal Blog: www.vtagion.com

     Modified on:  	10/11/2016
	 Modified by:  	Erwan Quélin
     Twitter:       @erwanquelin
     Github:        https://github.com/equelin    
	===========================================================================
	.DESCRIPTION
    This function will allow users to enable/disable VMCP and also allow
    them to configure the additional VMCP settings
    For each parameter, users should use the 'Tab' button to auto-fill the
    possible values.

    .PARAMETER Cluster
    Cluster Name or Object

    .PARAMETER enableVMCP
    Enable or disable VMCP

    .PARAMETER VmStorageProtectionForPDL
    VM Storage Protection for PDL settings. Might be:
    - disabled
    - warning
    - restartAggressive

    .PARAMETER VmStorageProtectionForAPD
    VM Storage Protection for APD settings. Might be:
    - disabled
    - restartConservative
    - restartAggressive
    - warning

    .PARAMETER VmTerminateDelayForAPDSec
    VM Terminate Delay for APD (seconds).

    .PARAMETER VmReactionOnAPDCleared
    VM reaction on APD Cleared. Might be:
    - reset
    - none

    .PARAMETER Server
    vCenter server object

    .EXAMPLE
    Set-VMCPSettings -cluster LAB-CL -enableVMCP:$True -VmStorageProtectionForPDL `
    restartAggressive -VmStorageProtectionForAPD restartAggressive `
    -VmTerminateDelayForAPDSec 2000 -VmReactionOnAPDCleared reset 

    This will enable VMCP and configure the Settings on cluster LAB-CL

    .EXAMPLE
    Set-VMCPSettings -cluster LAB-CL -enableVMCP:$False -VmStorageProtectionForPDL `
    disabled -VmStorageProtectionForAPD disabled `
    -VmTerminateDelayForAPDSec 600 -VmReactionOnAPDCleared none 

    This will disable VMCP and configure the Settings on cluster LAB-CL

    .EXAMPLE
    Set-VMCPSettings -enableVMCP:$False -VmStorageProtectionForPDL `
    disabled -VmStorageProtectionForAPD disabled `
    -VmTerminateDelayForAPDSec 600 -VmReactionOnAPDCleared none 

    This will disable VMCP and configure the Settings on all clusters available
#>
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="High")]
    param
    (
        [Parameter(Mandatory=$true,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage='What is the Cluster Name?')]
        $cluster,
        
        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='$True=Enabled $False=Disabled')]
        [bool]$enableVMCP,

        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='Actions that can be taken in response to a PDL event')]
        [ValidateSet("disabled","warning","restartAggressive")]
        [string]$VmStorageProtectionForPDL,
        
        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='Options available for an APD response')]
        [ValidateSet("disabled","restartConservative","restartAggressive","warning")]
        [string]$VmStorageProtectionForAPD,
        
        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='Value in seconds')]
        [Int]$VmTerminateDelayForAPDSec,
        
        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='This setting will instruct vSphere HA to take a certain action if an APD event is cleared')]
        [ValidateSet("reset","none")]
        [string]$VmReactionOnAPDCleared,
        
        [Parameter(Mandatory=$False)]
        [VMware.VimAutomation.Types.VIServer[]]$Server = $global:DefaultVIServers
    )

    Process {

        Foreach ($Clus in $Cluster) {

            Write-Verbose "Processing Cluster $Clus"

            # Determine input and convert to ClusterImpl object
            Switch ($Clus.GetType().Name)
            {
                "string" {$CL = Get-Cluster $Clus -Server $Server -ErrorAction SilentlyContinue}
                "ClusterImpl" {$CL = $Clus}
                default {Throw 'Please provide a cluster name or object'}
            }

            If ($CL) {

                # Get the actual configuration of the Cluster
                $ActualSettings = Get-VMCPSettings -Cluster $CL -Server $Server

                # Show actual settings in the verbose mode
                Write-Verbose "[$($CL.Name)] Actual VMCP settings "
                Write-Verbose $ActualSettings

                # Create the object we will configure
                $settings = New-Object VMware.Vim.ClusterConfigSpecEx
                $settings.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
                
                # Based on $enableVMCP switch 
                if ($enableVMCP -eq $false)  { 
                    $settings.dasConfig.vmComponentProtecting = "disabled"
                } 
                elseif ($enableVMCP -eq $true) { 
                    $settings.dasConfig.vmComponentProtecting = "enabled" 
                }  

                #Create the VMCP object to work with
                $settings.dasConfig.defaultVmSettings = New-Object VMware.Vim.ClusterDasVmSettings
                $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings = New-Object VMware.Vim.ClusterVmComponentProtectionSettings

                #Storage Protection For PDL
                If ($PSBoundParameters.ContainsKey('VmStorageProtectionForPDL')) {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForPDL = $VmStorageProtectionForPDL
                } else {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForPDL = $ActualSettings.'Protection For PDL'
                }

                #Storage Protection for APD
                If ($PSBoundParameters.ContainsKey('VmStorageProtectionForAPD')) {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = $VmStorageProtectionForAPD
                } else {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = $ActualSettings.'Protection For APD'
                }

                #Storage Protection for APD
                If ($PSBoundParameters.ContainsKey('VmStorageProtectionForAPD')) {
                    switch ($VmStorageProtectionForAPD) {
                        "disabled" {
                            # If Disabled, there is no need to set enable Timeout Value
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = 'disabled'
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.enableAPDTimeoutForHosts = $false
                        }

                        "restartConservative" {
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = 'restartConservative'
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.enableAPDTimeoutForHosts = $true
                        }

                        "restartAggressive" {
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = 'restartAggressive'
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.enableAPDTimeoutForHosts = $true
                        }

                        "warning" {
                            # If Warning, there is no need to enable the Timeout Value
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = 'warning'
                            $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.enableAPDTimeoutForHosts = $false
                        }
                    }
                } else {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmStorageProtectionForAPD = $ActualSettings.'Protection For APD'
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.enableAPDTimeoutForHosts = $ActualSettings.'APD Timeout Enabled'
                }

                #APD Timeout Enabled
                If ($PSBoundParameters.ContainsKey('VmTerminateDelayForAPDSec')) {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmTerminateDelayForAPDSec = $VmTerminateDelayForAPDSec
                } else {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmTerminateDelayForAPDSec = $ActualSettings.'APD Timeout (Seconds)'
                }
                
                # Reaction On APD Cleared
                If ($PSBoundParameters.ContainsKey('VmReactionOnAPDCleared')) {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmReactionOnAPDCleared = "$VmReactionOnAPDCleared"
                } else {
                    $settings.dasConfig.defaultVmSettings.vmComponentProtectionSettings.vmReactionOnAPDCleared = $ActualSettings.'Reaction on APD Cleared'
                }

                # Execute API Call
                If ($pscmdlet.ShouldProcess($CL.Name,"Modify VMCP configuration")) {
                    $modify = $true
                    $ClusterMod = Get-View -Id "ClusterComputeResource-$($CL.ExtensionData.MoRef.Value)" -Server $Server
                    $Task = $ClusterMod.ReconfigureComputeResource_Task($settings, $modify)
                }

                # Wait for the reconfiguration task to finish to show the result
                If ($Task) {
                    $TaskID = "Task-" + $($Task.Value)
                    Get-Task -Id $TaskID -Server $Server | Wait-Task | Out-Null
                    Get-VMCPSettings -Cluster $CL -Server $Server
                }
            }
        }
    }
}

 

VMMonitoring

The final module I used can set the VM Monitoring settings.

# ------------------------------------------------------------------------------------------------------------------
# Module to set VM Monitoring settings when configuring a cluster with HA (this is not yet part of the new-cluster
# cmdlet
#
# By Wesley van Ede, www.dutchvblog.com
#
# ------------------------------------------------------------------------------------------------------------------

function Set-ClusterDasVmMonitoring {

    param
    (
    [Parameter(Mandatory=$False,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage='What is the Cluster Name?')]
    [String[]]$cluster,
    [ValidateSet("vmMonitoringDisabled", "vmMonitoringOnly", "vmAndAppMonitoring")]
    [String[]]$Option,
    [int]$interval = 30,
    [int]$minup = 120,
    [int]$maxfail = 3,
    [int]$failwin = 3600
    )

    if(Get-Cluster $cluster){

    $spec = New-Object VMware.Vim.ClusterConfigSpecEx
    $spec.dasConfig = New-Object VMware.Vim.ClusterDasConfigInfo

        if ($option -eq "vmMonitoringDisabled" ) {
            $spec.dasConfig.vmMonitoring = "vmMonitoringDisabled"
            $spec.dasConfig.defaultVmSettings = New-Object VMware.Vim.ClusterDasVmSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings = New-Object VMware.Vim.ClusterVmToolsMonitoringSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.failureInterval = $interval
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.minUpTime = $minup
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailures = $maxfail
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailureWindow = $failwin

            $clusterobj = Get-Cluster -Name $cluster
            $clusterview = Get-View $clusterobj.Id
            $clusterview.ReconfigureComputeResource_Task($spec, $true)
            }

        elseif ($option -eq "vmMonitoringOnly" ) {
            $spec.dasConfig.vmMonitoring = "vmMonitoringOnly"
            $spec.dasConfig.defaultVmSettings = New-Object VMware.Vim.ClusterDasVmSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings = New-Object VMware.Vim.ClusterVmToolsMonitoringSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.failureInterval = $interval
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.minUpTime = $minup
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailures = $maxfail
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailureWindow = $failwin

            $clusterobj = Get-Cluster -Name $cluster
            $clusterview = Get-View $clusterobj.Id
            $clusterview.ReconfigureComputeResource_Task($spec, $true)
            }

        elseif ($option -eq "vmAndAppMonitoring" ) {
            $spec.dasConfig.vmMonitoring = "vmAndAppMonitoring"
            $spec.dasConfig.defaultVmSettings = New-Object VMware.Vim.ClusterDasVmSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings = New-Object VMware.Vim.ClusterVmToolsMonitoringSettings
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.failureInterval = $interval
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.minUpTime = $minup
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailures = $maxfail
            $spec.dasConfig.defaultVmSettings.vmToolsMonitoringSettings.maxFailureWindow = $failwin

            $clusterobj = Get-Cluster -Name $cluster
            $clusterview = Get-View $clusterobj.Id
            $clusterview.ReconfigureComputeResource_Task($spec, $true)
            }

    }
}

Back to index

Conclusion

This has become a monster blog post because of all the scripts. Usually I write a conclusion at the end. For now I would like to say, hopefully these PowerCLI scripts are of use to you. Please feel free to change or enhance as you see fit. And please leave a comment if there is anything I could do to make these more efficient or better in general.

One Reply to “Useful vSphere PowerCLI scripts”

  1. HI
    Is there any script for compute_cluster to display all the data stores under the cluster, along with that finding out which datastore under cluster has more capacity.

    Please provide the script,

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.