PowerCLI: Discover Idle VMs

There are a number of operations management tools available which can allow you to discover virtual machines which can be categorised as idle, where they continue to run  with a low utilisation profile and can be part of the overall VM sprawl in your environment.

I was recently investigating how to retrieve Idle VMs based on their CPU, Disk and Network usage by querying statistical information from vCenter, this was all possible using PowerCLI and math functions within Powershell.

Firstly we will connect to the VI server and  retrieve a collection of VMs and filter these to only return VMs where the Power State is equal to ‘PoweredOn’.

Connect-VIServer server1.domain.local
$VMs = Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"} 

For each virtual machine retrieved in the collection we will want to retrieve statistical information for the following stats:

  • cpu.usagemhz.average
  • disk.usage.average
  • net.usage.average

For each stat retrieved we will want to use a date range where the start date is thirty days in the past and the finish date is the current date.  For Each metric retrieved we will count the number of objects in total and count the number of objects returned where the value is less or equal that specified  and then use the match function within Powershell to calculate this as a percentage.

In this example, the following thresholds were used:

Stat Unit Value
cpu.usagemhz.average Mhz 100
disk.usage.average KBps 20
net.usage.average KBps 1
$Output =ForEach ($VM in $VMs) 
    $CPUStat = Get-Stat -Entity $VM.Name -Stat cpu.usagemhz.average -Start (Get-Date).AddDays(-30) -Finish (Get-Date) 
    $CPUIdle = $CPUStat | Where-Object {$_.Value -le "100"} 
    $CPUDetection = ($CPUIdle.Count / $CPUStat.Count) *100 
    $DiskStat = Get-Stat -Entity $VM.Name -Stat disk.usage.average -Start (Get-Date).AddDays(-30) -Finish (Get-Date) 
    $DiskIdle = $DiskStat | Where-Object {$_.Value -le "20"} 
    $DiskDetection = ($DiskIdle.Count / $DiskStat.Count) * 100

    $NetworkStat = Get-Stat-Entity $VM.Name-Stat net.usage.average -Start (Get-Date).AddDays(-30) -Finish (Get-Date) 
    $NetworkIdle = $NetworkStat | Where-Object {$_.Value -le "1"} 
    $NetworkDetection = ($NetworkIdle.Count / $NetworkStat.Count) * 100

Now that we have retrieved the statistical information and calculated the percentage of samples that were less or equal to the  threshold value we will identity VMs that are believed to be idle by specifying that 90% of the returned samples were below the threashold limit for each stat retrieved and output this information to include the VM Name and the average value of each metric for the date range.

If ($CPUDetection -ge "90"-and $DiskDetection -ge "90"-and $NetworkDetection -ge "90")
        "" | Select @{N="Name";E={$VM.Name}},
        @{N="CPU Usage (Mhz)";E={[Math]::Truncate(($CPUStat.Value | Measure-Object-Average).Average)}},
        @{N="Disk I/O Usage (KBps)";E={[Math]::Truncate(($DiskStat.Value | Measure-Object-Average).Average)}},
        @{N="Network I/O Usage (KBps)";E={[Math]::Truncate(($NetworkStat.Value | Measure-Object-Average).Average)}}
$Output | Export-Csv -Path D:\Output\IdleVMS.csv -NoTypeInformation

The above can be downloaded in full from the below, where the values can be modified to meet your requirements, the default is to use the above values as above.


The script can be run as below:

 ./Get-IdleVMs.ps1 -CpuMhz 200 -DiskIO 15 -NetworkIO 2 -Percentage 85 -Days 10 -vCenter server1.domain.local

PowerCLI: Retrieve VMs where CPU or Memory Reservation has been enabled

The below script block will retrieve VMs where either or both CPU and Memory reservation has been configured and return the value by using the Get-VM cmdlet and retriving the value of both the ‘ExtensionData.ResourceConfig.CpuAllocation.Reservation’ and ‘ExtensionData.ResourceConfig.MemoryAllocation.Reservation’ properties.


$VMs = Get-VM | Where-Object {$_.ExtensionData.ResourceConfig.MemoryAllocation.Reservation -ne "0" -or $_.ExtensionData.ResourceConfig.CpuAllocation.Reservation -ne "0"}
ForEach ($VM in $VMs)
    "" | Select @{N="Name";E={$VM.Name}},
    @{N="CPU Reservation";E={$VM.ExtensionData.ResourceConfig.CpuAllocation.Reservation}},
    @{N="Memory Reservation";E={$VM.ExtensionData.ResourceConfig.MemoryAllocation.Reservation }} 

Retrieve collection of Microsoft Windows Server 2003 VMs using PowerCLI

As the extended support end date looms nearer for Windows Server 2003 R2  or to be more precise 14/07/2015 (http://support.microsoft.com/lifecycle/search/default.aspx?alpha=Windows+Server+2003+R2) a number of you may still be running editions of this operating system.

An easy way to discover this using PowerCLI is to use the Get-VM cmdlet and filter the results where the ‘Guest.OSFullName’ property is like ‘Microsoft Windows Server 2003’

Get-VM | Where-Object {$_.Guest.OSFullName -like "Microsoft Windows Server 2003*"} | Select Name

Now you have a collection of VMs which you will probably be looking to upgrade before the extended support end date.