Rightsize Virtual Machines in bulk using PowerCLI

If you have attempted to rightsize or correct the CPU or RAM on a large amount of virtual machines you will know this is not always a quick task, while the ability to rightsize virtual machines in bulk does exist within later versions of vRealize Operations Manager (Now known as Aria Operations) this is grouped by cluster and only allows VMs to be sized to its recommended values.

I decided to take the exported CSV format of the rightsizing recommendations from vROps and use this to form the basis of a PowerCLI script that will achieve the same task but with the added benefits of allowing the list to be tailored to a certain group of VMs and also allow for some customisation of the CPU and RAM values if required.

N.B If you do not have vROps running in your environment creating a CSV with the same headings and manually adding the servers to be adjusted will work just as well.

Once you have the CSV file configured as you require save in an accessible location, for the purpose of this post I used C:\temp\rightsize.csv

On to the Script....

#Set vCenter Sever(s) where Virtual Machines that require rightsizing reside.
$vCenters='vc-l-01a.corp.local' #,'vc2'
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
Connect-VIServer -Server $vCenters -User administrator@vsphere.local -Password Password123

#Import the CSV File containing the list of servers to be rightsized.
$VMList = Import-Csv -Path C:\temp\rightsize.csv

#Loop through the servers one at a time, output the changes From and To on screen
Foreach($entry in $VMList){
    $vm = Get-VM -Name $entry.{VM Name}
    $VMVCServer = $global:DefaultVIServers | Where {$_.ServiceUri -eq $vm.ExtensionData.Client.ServiceUrl}
    Write-Host "Target VM   :"$vm.Name
    Write-Host "Status      :"$vm.PowerState
    Write-Host "VC / Cluster:"$VMVCServer.Name "/" $vm.VMHost.Parent.Name
    Write-Host "Current CPU :"$vm.NumCpu
    #Strip out the whole number value of CPU reduction
    $strcpu = $entry.{Recommended CPU Reduction}
    $cpu = $strcpu.Split('.')[0]
    Write-Host "Target  CPU :"$cpu
    Write-Host "Current RAM :"$vm.MemoryGB
    #Strip out the whole number value of the RAM reduction 
    $strram = $entry.{Recommended Memory Reduction}
    $ram = $strram.Split('.')[0]
    Write-Host "Target  RAM :"$ram
    pause
        #Power off VM if powered on, make the changes, power back on 
        If($vm.PowerState -ne "PoweredOff"){
            Shutdown-VMGuest -VM $vm -Confirm:$False
            Write-Host "Waiting for power down..."
            do{Sleep 5} while($vm.PowerState -eq "PoweredOn")
            If($cpu -ge 1){ 
            $vm | set-VM -NumCpu $cpu -Confirm:$False}
            If($ram -ge 1){
            $vm | set-VM -MemoryGB $ram -Confirm:$False}
            Sleep 2
            Start-VM -VM $vm -Confirm:$False
        }
        #If the VM is currently powered off just make the changes
        else{
            If($cpu -ge 1){
            $vm | set-VM -NumCpu $cpu -Confirm:$False}
            If($ram -ge 1){
            $vm | set-VM -MemoryGB $ram -Confirm:$False}
            Sleep 2
            } 
}
Write-Host "New VM config"
#Repeat the sizing loop confirming the changes 
Foreach($entry in $VMList){
    $vm = Get-VM -Name $entry.{VM Name}
    $VMVCServer = $global:DefaultVIServers | Where {$_.ServiceUri -eq $vm.ExtensionData.Client.ServiceUrl}
    Write-Host "Target VM   : "$vm.Name
    Write-Host "VC / Cluster:"$VMVCServer.Name "/" $vm.VMHost.Parent.Name
    Write-Host "Current CPU : "$vm.NumCpu
     $strcpu = $entry.{Recommended CPU Reduction}
    $cpu = $strcpu.Split('.')[0]
    Write-Host "Target  CPU : "$cpu
    Write-Host "Current RAM :"$vm.MemoryGB
    $strram = $entry.{Recommended Memory Reduction}
    $ram = $strram.Split('.')[0]
    Write-Host "Target  RAM :"$ram
    If($vm.NumCpu -eq $cpu){ Write-Host -ForegroundColor Green "VM CPU change complete" }
    If($vm.NumCpu -ne $cpu -And $cpu -ne 0){ Write-Host -ForegroundColor Red "VM CPU change failed, check manually" }
    If($vm.NumCpu -ne $cpu -And $cpu -eq 0){ Write-Host -ForegroundColor Yellow "No CPU Changes Required" }
    If($vm.MemoryGB -eq $ram){ Write-Host -ForegroundColor Green "VM RAM change complete" }
    If($vm.MemoryGB -ne $ram -And $ram -ne 0){ Write-Host -ForegroundColor Red "VM RAM change failed, check manually" }
    If($vm.MemoryGB -ne $ram -And $ram -eq 0){ Write-Host -ForegroundColor Yellow "No RAM Changes Required" }
} 

This script above is for decreasing the size of VMs, there is a slight difference in the CSV headings when exporting the rightsizing "increase" list from vROps. I have included sample files at the bottom of this post. There is nothing to stop you editing a single CSV file to allow for the increasing and decreasing of VMs in a single execution of the script.

Details of the changes to be made are shown and confirmation requested...

If Powered on the VM is powered off and the changes are made...

The final section of the code outputs the change detail on a per VM basis...

Code Samples:

I hope this is of use and thanks for reading