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.
https://app.box.com/s/4lxyezl55blfnsf1kk9m
The script can be run as below:
./Get-IdleVMs.ps1 -CpuMhz 200 -DiskIO 15 -NetworkIO 2 -Percentage 85 -Days 10 -vCenter server1.domain.local
this didnt work for me throw error “Export-Csv : A parameter cannot be found that matches parameter name ‘Pathe’.
At D:\SYDABR\VMware Scripts\Get-IdleVMs.ps1:37 char:27
+ $Output|Export-Csv -Pathe: <<<< \idlevms.csv -NoTypeInformation
+ CategoryInfo : InvalidArgument: (:) [Export-Csv], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ExportCsvCommand
"
LikeLike
Export-Csv : Cannot bind argument to parameter ‘InputObject’ because it is null.
At D:\SYDABR\VMware Scripts\Get-IdleVMs.ps1:37 char:19
+ $Output|Export-Csv <<<< -Path E:\idlevms.csv -NoTypeInformation
+ CategoryInfo : InvalidData: (:) [Export-Csv], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportCsvCommand
LikeLike
I keep getting an error:
Param ([string] $CPUMhz = “100”, [string] $DiskIO = “20”, [string] $NetworkIO = …
+ ~~~~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
LikeLike