Blog

March 8, 2013
Category: microsoft, virtualisation, vmware
Tags: load-balancing, vcenter, virtual-machine, vmware-esx, windows-powershell, windows-task-scheduler

VMware Host Cluster VM memory balancing script implementation

I recently found a replacement DRS script using PowerCLI from Scott Warren's Blog http://www.scottwarren.info/2011/03/24/scripting-a-drs-replacement-using-powercli/

I wanted to run this as a daily task to ensure that my standard edition ESX cluster was load balanced.

Firstly I needed to create the folders on the Vcenter server to store the scripts and log files.

In the root directory C: I created two folders VMware Logs and Scheduled tasks.

You will need to download PowerCLI from VMware, ensure you download the correct version that matches your environment.

I then created two scripts.

1. Copy the powershell script from Scott Warrens blog in to the notepad and save as VMware Drs Script.ps1

Set-StrictMode -version 2

function GetPercentages(){ # get all the hosts $objHosts = get-vmhost;

# loop through each of the hosts and calculate the percentage of memory used
   foreach($objHost in $objHosts){
           $objHost | add-member NoteProperty PercentMemory ($objHost.MemoryUsageMB/$objHost.MemoryTotalMB \*100)
           $objHost
   }

}

function GetVMToMove($strHost, $arrAllVMs){ #get all the VMs that are powered on on this host $objVMs = get-vm | where {($_.Host.Name -eq $strHost) -and ($_.PowerState -eq "PoweredOn")}

# check to see if there is a static file
   if(test-path "balanced.csv"){
           # read in the static file
           $arrStatic = import-csv "balanced.csv"

# loop through all the static entries
           foreach($objStatic in $arrStatic){
                   #echo $objStatic.VM;
                   $objVM = $objVM | where {$\_.Name -ne ($objStatic.Name)}
           }
   }

# sort based on the amount of memory used$objVMs = $objVMs | sort "Memory\*"

# return the VM using the least amount of RAM
   $objVMs\[0\];

}

get all the VMs

$arrAllVMs = get-vm | where {$_.PowerState -eq "PoweredOn"}

check to see if there is a static file

if(test-path "balanced2.csv"){ # read in the static file $arrStatic = import-csv "balanced.csv"

# move the static VMs to the correct location
   echo "Moving static VMs to the correct host."

# loop through all the VMs
   foreach($objStatic in $arrStatic){
           # get the VM
           $objVM = get-VM $objStatic.Name;

# check to see if the VM is not on the correct host
           if($objVM.Host.Name -ne $objStatic.Host){
                   echo ("Moving " + $objStatic.Name);
                   #move the VM
                   $objVM | move-vm -destination (get-vmhost $objStatic.Host)
           }
   }

}

a flag to indicate that we moved a VM

$bMoved = $true;

keep looping through the list until no VMs have been moved

while($bMoved){ # get the hosts with percentages $objHosts = GetPercentages | sort PercentMemory -descending | select Name, PercentMemory

# calculate the average memory
   $intAverage = 0;
   $intCount = 0;
   foreach($objHost in $objHosts){
           $intAverage += $objHost.PercentMemory;
           $intCount++;
   }
   $intAverage /= $intCount;

# display the average memory used
   echo ("Average is " + $intAverage);

# display the hosts so it's easier to know what's going on
   $objHosts | select Name, PercentMemory;

# determine the host with the least amount of RAM used$strDest = $objHosts\[$objHosts.Count-1\].Name;

# this is a flag to see if anything has been moved$bMoved = $false;

# loop through the hosts
   foreach($objHost in $objHosts){
           # check to see if this is more than 10% of the average
           if($objHost.PercentMemory -gt ($intAverage + 10)){
                   # get the name of the VM to move
                   $objVM = GetVMToMove $objHost.Name

# display some output to let the user know what is being moved
                   echo ('Moving ' +$objVM.Name + " from " + $objHost.Name);

#move the VM$objVM | move-vm -destination (get-vmhost $strDest);

# flag that a VM has been moved$bMoved = $true;
           }
   }

}

2.open Notepad again and copy the following script:

Set-ExecutionPolicy -ExecutionPolicy remotesigned -Force; add-pssnapin VMware.VimAutomation.Core; Connect-VIServer vcenter; & "C:\Scheduled tasks\Vmware DRS Script.ps1" >>c:\Log\VMHOSTCluster.log

change the name of Vcenter to your Vcenter server name and save the script as Run_DRS_script.ps1.

You will need to test this by running the following in the Run prompt:

powershell "C:\Scheduled_tasks\Run_DRS_Script"

once completed, check the log folder to see if a log file has been generated. You would also see Vm's migrating if there was a requirement to load balance.

Once happy you will need to create a task using Task Scheduler.

Open Task Scheduler and create a new task.

[](

ensure you select Run whether user is logged on or not. I would recommend creating a service account for this. ensure the account has the appropriate permissions.

select the tick box: run with Highest Privileges .

[](

Set the time and date the frequency of times you want this to Run

[](

[](

[](

Enter PowerShell into the program/script and in the Add arguments field enter:

"C:\Scheduled_tasks\Run_DRS_Script"

Once you have finished, confirm the settings and ok out of the create task. You should then run the task to ensure it works and look at the task logs and log folder to ensure that the script has run successfully.