VMware Cloud Community
bottomofbarrel
Contributor
Contributor

powercli script to capture cpu & mem usage stats

i am new to powercli and am not a good scriptor yet however, i need a script that will capture the max, min, avg cpu & mem usage stats per esxhost & vm for the past month and import into excel so i can create a pivot chart. key is i need to see the cpu/mem usage data per vm per host. can anyone help me with this. i have spent the last two weeks trying to work with powercli to do this and i am unable produce the results i want.

171 Replies
jeveenj
Enthusiast
Enthusiast

Hi,

You can try below code snippet. It will create two CSV files, one for Hosts and other for VMs.

Connect-VIServer <server> -User <user> -Password <password>
$allvms = @()
$allhosts = @()
$hosts = Get-VMHost
$vms = Get-Vm

foreach($vmHost in $hosts){
  $hoststat = "" | Select HostName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin
  $hoststat.HostName = $vmHost.name
  
  $statcpu = Get-Stat -Entity ($vmHost)-start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat cpu.usage.average
  $statmem = Get-Stat -Entity ($vmHost)-start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat mem.usage.average

  $cpu = $statcpu | Measure-Object -Property value -Average -Maximum -Minimum
  $mem = $statmem | Measure-Object -Property value -Average -Maximum -Minimum
  
  $hoststat.CPUMax = $cpu.Maximum
  $hoststat.CPUAvg = $cpu.Average
  $hoststat.CPUMin = $cpu.Minimum
  $hoststat.MemMax = $mem.Maximum
  $hoststat.MemAvg = $mem.Average
  $hoststat.MemMin = $mem.Minimum
  $allhosts += $hoststat
}
$allhosts | Select HostName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin | Export-Csv "c:\Hosts.csv" -noTypeInformation

foreach($vm in $vms){
  $vmstat = "" | Select VmName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin
  $vmstat.VmName = $vm.name
  
  $statcpu = Get-Stat -Entity ($vm)-start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat cpu.usage.average
  $statmem = Get-Stat -Entity ($vm)-start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat mem.usage.average

  $cpu = $statcpu | Measure-Object -Property value -Average -Maximum -Minimum
  $mem = $statmem | Measure-Object -Property value -Average -Maximum -Minimum
  
  $vmstat.CPUMax = $cpu.Maximum
  $vmstat.CPUAvg = $cpu.Average
  $vmstat.CPUMin = $cpu.Minimum
  $vmstat.MemMax = $mem.Maximum
  $vmstat.MemAvg = $mem.Average
  $vmstat.MemMin = $mem.Minimum
  $allvms += $vmstat
}
$allvms | Select VmName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin | Export-Csv "c:\VMs.csv" -noTypeInformation

Hope this helps.

-If you found this information useful, please consider awarding points for Correct or Helpful.
bottomofbarrel
Contributor
Contributor

iwill try this and get back to you. thank you so much for your time and interest to help me.

Reply
0 Kudos
bottomofbarrel
Contributor
Contributor

Hi Jeveenj, how can i change the timeframe that the stats are aggregated? I need to show the stats in a graph that shows stats per hour up to one day then aggregate the per hour per day stats for the last month. I apologize for not making myself clear enough the first time. the stats your script captures are perfect but i cant show what's happening per hour in a full day over the course of last months worth of cpu and mem stats. I'm playing with the get-date command in your script but i'm new at this and its going to take time to figure out scripting in powershell. any help is more than appreciated. Thanks again,

John

Reply
0 Kudos
LucD
Leadership
Leadership

Have a look at my PowerCLI & vSphere statistics – Part 2 – Come together post.

It shows how to aggregate 30 minute intervals into 1 hour intervals.

And if you look at PowerCLI & vSphere statistics – Part 1 – The basics you will see that with the Historical INterval 3 and 4 it's impossible to get hourly statistics.

If you want hourly statistics, you will have to collect them within a week and store them somewhere for later use (like a monthly report).

____________

Blog: LucD notes

Twitter: lucd22


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

Reply
0 Kudos
nute
Contributor
Contributor

Hi,

hope you can help with the below...

1.> How can I limit all fields of the output to less decimal places?  To be honest, even no decimal places. I'd be happy with all outputs rounded to the nearest percent or MB for clarity.

2.> any way to speed the running of the script?    perhaps an average over less captures.  Do I just set the maxsamples to a lower value?

All help appreciated

Thanks

/nute

Reply
0 Kudos
LucD
Leadership
Leadership

1) The .Net way is to call the Round function. Something like this

$value = 1.1234567

$roundedValue = [Math]::Round($value,0)

This will round the number to 0 decimal places

An laternative is to use the [int] cast

$roundedValue = [int]$value

2) Making a script faster can depend on many factors and of course what exactly is used in the script.

If you are referring to the script above, you can do the Get-Stat call for all VMHost in 1 go.

This will be considerable faster than making individual calls.

To extract the data for each VMHost, you can use the Group-Object cmdlet. See my PowerCLI & vSphere statistics – Part 4 – Grouping post for examples of the Group-Object cmdlet.

The same applies for the Get-Stat calls for the VMs.


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

Reply
0 Kudos
nute
Contributor
Contributor

Thanks for the quick reply

1.> please excuse my ignorance, I am new to Powerscripting.   Where in the original script would I add the .Net or Int call?

2.> Accepted I depends on the scale of what the script is being run against.  I am more interested in the per VM min/max/avg stats than host level at the moment.  So I have commented out the host section of the script for now. Running against approximately 150 VMs across 2 clusters.

Appreciate the help.  Your information and replies have already helped alot on my learning curve with PowerCLI

/nute

Reply
0 Kudos
LucD
Leadership
Leadership

1) You could do the conversion when you assign the values

  $vmstat.CPUMax = [int]$cpu.Maximum
  $vmstat.CPUAvg = [int]$cpu.Average
  $vmstat.CPUMin = [int]$cpu.Minimum
  $vmstat.MemMax = [int]$mem.Maximum
  $vmstat.MemAvg = [int]$mem.Average
  $vmstat.MemMin = [int]$mem.Minimum

2) I would do only 1 call to Get-Stat, outside the foreach loop

$stats = Get-Stat -Entity $vms-start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat "cpu.usage.average","mem.usage.average"

You can then use the Group-Object to split out the individual VM

Inside each group you can use the where clause to filter out the Memory and the CPU values.

$stats | Group-Object -Property Entity | %{

   $cpu = $_.Group | where {$_.MetricId -eq "cpu.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

   $mem = $_.Group | where {$_.MetricId -eq "mem.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

   ... 

}


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

Reply
0 Kudos
nute
Contributor
Contributor

Top notch!  Great help.  Thanks

Reply
0 Kudos
802Joe
Contributor
Contributor

Nute / LuCD,

Can one of you please post the final script?  I've tried piecing together the pieces, but I can't seem to get it to work.  😕

Greatly Appreciative,

Joe

Reply
0 Kudos
LucD
Leadership
Leadership

The following is for the VMs, the ESX(i) hosts loop is similar

Connect-VIServer <server> -User <user> -Password <password>
$allvms = @()
 $vms = Get-Vm

$stats
= Get-Stat -Entity $vms -start (get-date).AddDays(-30) -Finish (Get-Date)-MaxSamples 10000 -stat "cpu.usage.average","mem.usage.average"  $stats | Group-Object -Property Entity | %{   $vmstat = "" | Select VmName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin
  $vmstat.VmName = $_.name   $cpu = $_.Group | where {$_.MetricId -eq "cpu.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum
  $mem = $_.Group | where {$_.MetricId -eq "mem.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum
 
$vmstat.CPUMax = [int]$cpu.Maximum   $vmstat.CPUAvg = [int]$cpu.Average   $vmstat.CPUMin = [int]$cpu.Minimum   $vmstat.MemMax = [int]$mem.Maximum   $vmstat.MemAvg = [int]$mem.Average   $vmstat.MemMin = [int]$mem.Minimum    $allvms += $vmstat
}
$allvms | Select VmName, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin | Export-Csv "c:\VMs.csv" -noTypeInformation


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

Reply
0 Kudos
802Joe
Contributor
Contributor

Uh, I was so close!  This is awesome, thanks again!

2 things that I noticed, just for reference:

     1.  I have a few VMs in my environment that are not turned on, and haven't been for a while.  I had to modify the script a little bit to only include powered-on VMs, as I was getting an error running it against all VMs. I just changed $vms = Get-VM to $vms = Get-VM | where {$_.PowerState -eq "PoweredOn"}

     2.  Although my script runs fine, and the VMs.csv is created successfully, with all the VMs listed, I still show a value of 0 for all metrics.  Come to find out, the 'Metric' value didn't exist and was actually 'MetricId'.  I just had to change the 'where' statement in the $cpu and $mem calcs from where {$_.Metric -eq "cpu.usage.average"} to where {$_.MetricId -eq "cpu.usage.average"}

Hope that helps someone.  Thanks again LucD!

~Joe

Reply
0 Kudos
LucD
Leadership
Leadership

  1. If a VM has been powered off for a longer time, there will be no statistical data in the vCenter database. Also watch out with for example a VM that has been powered on for a couple of minutes and you ask for the statistical data of yesterday. To avoid that, you can add the "-ErrorAction SlientlyContinue" parameter on the Get-Stat cmdlet.
  2. Thanks for discovering that typo, shame on me :smileyblush:. I have corrected the property in the previous answers.


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

Reply
0 Kudos
MauroBonder
VMware Employee
VMware Employee

Hi Luc,

How are you ?

I´d like know how i can do to get clusters and create a column in cvs with classification of each hosts putting corresponding cluster

Example

host1          cluster     min     max     avg

vmware1     lab-1          x          y          z

thank you

*Please, don't forget the awarding points for "helpful" and/or "correct" answers. *Por favor, não esqueça de atribuir os pontos se a resposta foi útil ou resolveu o problema.* Thank you/Obrigado
Reply
0 Kudos
LucD
Leadership
Leadership

The simplest, but not most efficient, way is to use the Get-Cluster cmdlet.

Suppose you have the ESX(i) in $vmhost, then you can do

$cluster = (Get-Cluster -VMHost $vmhost).Name


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

Reply
0 Kudos
2012vm
Contributor
Contributor

Hi

I am looking for the script which you are talking about for generating my weekly report to my client.

I tried using this script but got errors.

can you share the script which you are using.

Thanks in advance!!!

Reply
0 Kudos
2012vm
Contributor
Contributor

Hi LucD,

Thanks for sharing!!!!

Actually i tried using this script where i got errors and didn't get any output just got a blank csv file.

I have started using the PCLI Scripts newly.

Can you please help me in using this script and get my report done.

Actually we are planning to get weekly report for CPU & Memory usage for both the ESX & VM.

Thanks in advance!!

Reply
0 Kudos
LucD
Leadership
Leadership

Which script are you trying to use (there are several in this thread) ?

And which errors are you getting ?


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

Reply
0 Kudos
2012vm
Contributor
Contributor

Hi jeevanj,

I have used this scripts. Thnaks for providing it is very useful.

Actually i am new to this scripting. (just running the script and retriving data from it)

But what modifications i can do so that i can have this information daily so that i can plot some graphs which i can use for my weekly report.

Please help me in this.....

Thanks in advance!!!

Reply
0 Kudos