VMware Cloud Community
Butcha
Contributor
Contributor

Selecting VM's using Get-Stat and Conditional IF Statements

Hello all!

I am back once again with another slight puzzle with PowerCLI. By the way, before I start I just want to say how much that I have learned from this community! I'm quite certain that I couldnt have ever come this far with my VMware powershell scripting had it not been for some of the brilliant minds here!

So, lately, I have been trying to use VM performance statistics as filters to get at the one's that are mostly sitting there idle within our infrastructure. I have tried this a few different ways, but so far, nothing works just as I need it.

$cpu_usage = Get-Stat -Entity $_ -Stat cpu.usage.average -MaxSamples 5

$mem_usage = Get-Stat -Entity $_ -Stat mem.usage.average -MaxSamples 5

$cpu_usage <----


was inserted for debugging purposes......used it just to see what the value of the variable was at each time the script looped

$mem_usage<----


was inserted for debugging purposes......used it just to see what the value of the variable was at each time the script looped

----


Break Point -

*note: if I simply enter only the above section of code in my editor, which is powergui, I can see the beginnings of my desired result. The powershell console section of powergui will display the results of the Get-Stat commands for every VM in this cluster.

It is here that things dont add up:

{ Write-Output $_.Name | Out-File -FilePath "C:\Scripts\vmstats.txt" -Append}

What this seems to do is enter every powered on VM into my output file, which is not what Im shooting for. From the result of just stopping my script at the breakpoint above, I can see something like the following in the console section of the powergui application:

Value : 4.49 Timestamp : 7/30/2009 7:00:00 PM MetricId : cpu.usage.average Unit : % Description : CPU usage as a percentage over the collected in

Interval:

Instance :

As you can see, its the performance data that Im actually pulling on these VM's. I will see this for all VM's in the cluster.

Question for clarity: should I be able to use the label of each attribute, when specifying something specific about the object that contains the result of Get-Stat? i.e $cpu_usage.value <----here I am calling the "value" attribute, which I would think pertains to the "value" listing on the above result. The $cpu_usage object contains the Get-Stat command and parameters, and the .value would specify only the field labeled "value". If I wanted the timestamp, I should be able to say $cpu_usage.Timestamp. Am I correct in my thinkin on this? As it turns out, right now, the script is simply ignoring both of the Get-Stat object parameters in the IF statement and only applying the powered on condition.

0 Kudos
5 Replies
LucD
Leadership
Leadership

You are correct in assuming that you can use the property name of the FloatSampleImpl object (that's what Get-Stat is returning).

The reason your If-statement is not working is because the $cpu_usage and the $mem_usage variables both contain an array of FloatSampleImpl objects not just one FloatSampleImpl object.

The solution is to change the -Maxsamples parameter on both Get-Stat cmdlets.

$cluster = <Cluster-name>

Get-VM -Location $cluster | %{

	$cpu_usage = Get-Stat -Entity $_ -Stat cpu.usage.average -MaxSamples 1
	$mem_usage = Get-Stat -Entity $_ -Stat mem.usage.average -MaxSamples 1

	if ($_.PowerState -eq "PoweredOn" -and $cpu_usage.value -lt 50 -and $mem_usage.value -lt 50) {
		Write-Output $_.Name | Out-File -FilePath "C:\Scripts\vmstats.txt" -Append
	}
}

Note1 I changed your foreach-statement and used the pipeline with the Foreach-Object cmdlet. It's a bit subjective but I feel this is more legible.

Note2 the variable $_ is a variable that is used by PowerShell to represent the current object that you received from the pipeline. You can use this variablename yourself in your scripts but I think it is somewhat confusing.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Butcha
Contributor
Contributor

LucD,

Thanks for your quick response!

Using some of the info you provided and a little more research, I have modified my script to focus on the cpu metric only, to simplify the script, at least initially so I can get it working.

foreach ($vm in $vms) { $cpu_usage = Get-Stat -Entity $vm -Stat cpu.usage.average -Start (get-date).AddDays(-4) -Finish (get-date) -IntervalMins 120

This Get-Stat line seems to work good, although I do get errors regarding the specific perf counter, cpu.usage.average, not being available for certain VM's....mostly Linux VM's. Any reason why that would be the case?

My next question is regarding what Im using for criteria in my IF statement:

if ($vm.PowerState -eq "PoweredOn" -and $cpu_usage.value -lt 5)

I'm wanting to check if $cpu_usage.value is less than 5%. Am I using the correct value to specify 5%? or is there some decimal that I should be using?

I can find tons of example scripts where these metrics are being gathered for ALL VM's or an entire group of VM's, but I really only need the VM's whose metrics fall into this particular criteria. Anyway, who wants to manually look through this data pertaining to 1000+ VM's? LOL......

0 Kudos
LucD
Leadership
Leadership

Your latest Get-Stat cmdlet will also return an array of FloatSampleImpl objects.

On average you would get (4 x 24 x 60) / 120 = 48 objects. But it could be more or less objects depending on the available statistical data.

You could test on the average over this four-day period (or take the minimum or maximum value which is also possible with the Measure-Object cmdlet).

Something like this

foreach ($vm in $vms) {
     $cpu_usage = (Get-Stat -Entity $vm -Stat cpu.usage.average -Start (get-date).AddDays(-4) -Finish (get-date) -IntervalMins 120 | Measure-Object -Property Value -Average).Average
     ...
}

Between the round brackets I use the Get-Stat cmdlet and pipe the resulting objects to the Measure-Object cmdlet.

I ask the Measure-Object cmdlet to give me the average of the values in the Value property.

The result is (again) an object and from this object I only want the Average property which I store in the $cpu_usage variable.

For your 2nd question, the metric your are using cpu.usage.average returns percentages (as can be seen in the Unit property of the FloatSampleImpl object).

Your test is correct.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Butcha
Contributor
Contributor

LucD,

This light that you have shed on the fact that Get-Stat was returning an array of values instead of just one was the key! So, in such a case, we'd have to compute our own averages of the sample data. Now, I am understanding and getting somewhere.

I try as much as possible to research and learn things on my own before bothering you guys with questions that probably seem basic at best, but there just isnt enough documentation on every cmdlet yet. Thanks again very much!!

0 Kudos
LucD
Leadership
Leadership

You're welcome.

As a suggestion, Hal's book goes way further then the PowerCLI cmdlet help.

Get your boss to buy you that book. It will save you hours of searching. Smiley Wink


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos