Most of the times I prefer to not bind VMs to a specific host, but sometimes it saves lots of money on licenses. I used this script to keep Windows VMs running on less hosts then my cluster size, in order to report less Host usage for the SPLA reports. You can use DRS Group to place selected VMs on selected hosts, to automate this you can chose to tag the VMs and place them in the right group.

First we start with creating a Host Group, VM Group and TAGs in vCenter. Use the variables you define in the script to make it work. After you've created them tag some VMs and some Hosts and run this script. The DRS rule will be made and the VMs will be added to the group. The result will be that those VMs will only run on the selected hosts.

Run this script manually to check if everything works as expected, afterwards you can schedule it to run on a regular basis.

  #variables to change
  $vmgroup = "SPLA VM Group"
  $hostgroup = "SPLA Host Group"
  $vmtag = "Windows SPLA"
  $hosttag = "SPLA Host"
  $ruleName = "Windows SPLA"
  $tag_cat = "SPLA"
  $ruleEnable = $true
  $vcenter = "vcenter.comp.lan"
  $user = "sa_vcenter"

  Write-Output "Connecting to vCenter $vcenter"
  $password = Get-VICredentialStoreItem -Host $vcenter -User $user
  Connect-VIServer -Server $vcenter -User $user -Password $password.Password | Out-Null

  $clusters = Get-Cluster -server $vcenter
  Write-Output "Found $($clusters.count) clusters"

  foreach($cluster in $clusters){
      Write-Output "Processing cluster $($cluster)"
      $tagHosts = @()
      $tagVMs = @()
      $tagExists = $false
      $vmTagExists = $false
      $hostGroupExists = $false
      $vmGroupExists = $false

  #Check if DRS groups exists
  $drsHostGroup = Get-DrsClusterGroup -Cluster $cluster -Type VMHostGroup -ErrorAction SilentlyContinue
  $drsVMGroup = Get-DrsClusterGroup -Cluster $cluster -Type VMGroup -Name $vmgroup -ErrorAction SilentlyContinue
      Write-Verbose "DRS Host group found"
      $hostGroupExists = $true
      Write-Verbose "DRS VM group found"
      $vmGroupExists = $true

  #Retrieve vms and check if the tag exists
  $vms = $cluster | Get-VM
  foreach($vm in $vms){
      $vmTagAssigned = $vm | Get-TagAssignment -Category $tag_cat
          foreach($vmtagA in $vmTagAssigned){
              if($vmtagA.Tag.Name -eq $vmtag){
                  $tagVMs += $vm
                  $vmTagExists = $true


  #VMs found but no hosts found
  if($vmTagExists -and !$hostTagExists){
      Write-Verbose "VMs with tag exists, but there are no hosts with a tag!"

  #Create VM Group if tag is found and group is not found
  if(!$vmGroupExists -and $vmTagExists){
      Write-Verbose "Creating DRS VM group"
      New-DrsClusterGroup -Name $vmtag -Cluster $cluster -VM $tagVMs -WhatIf
      $drsVMGroup = Get-DrsClusterGroup -Cluster $cluster -Type VMGroup -Name $vmtag -ErrorAction SilentlyContinue
          $vmGroupExists = $true
      Write-Verbose "VM tag doesn't exist, no need for the group."

  #Check if VM are a member of the DRS group
  if($vmGroupExists -and $vmTagExists){
      foreach($tagVM in $tagVMs){
              $drsVMGroup | Set-DrsClusterGroup -Add -VM $sqlVM

  #Check DRS Rule
  if($hostGroupExists -and $vmGroupExists){
      $drsRules = Get-DrsVMHostRule -Cluster $cluster -Type ShouldRunOn -VMHostGroup $drsHostGroup -VMGroup $drsVMGroup
          #Rule doesn't exist
          Write-Verbose "Creating DRS rule"
          New-DrsVMHostRule -Name $ruleName -Cluster $cluster -VMHostGroup $drsHostGroup -VMGroup $drsVMGroup -Type MustRunOn -Enabled:$ruleEnable -WhatIf
  disconnect-VIServer $vcenter -Confirm:$false

Previous Post Next Post