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.
- Create vCenter clusters
- Add ESXi hosts to vCenter clusters
- Create distributed switch and port groups
- Migrate hosts from vSwitch to distributed switch
- Create additional VM kernel ports
- Remove vSwitch0 from all hosts
- Create (sub) folders in vCenter
- DRS host groups
- Create and populate datastore clusters
- Change local ESXi host datastore names
- Supporting files
- 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
}
}
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
}
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
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
}
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
}
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
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
}
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
}
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
}
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
}
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"
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)
}
}
}
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.
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,