PowerCLI

 View Only

 Script to retrieve the historical CPU stats of ESXi Host

siprasad's profile image
siprasad posted Apr 28, 2025 06:00 AM

There is a request to retrieve the historical stats of CPU on ESXi Host. Fetching this info realtime in itself is taking time, especially when you have multiple cores as the get-stat -stat cpu.usage.average pulls all the core information. This becomes harder when we run for a few days. Wondering if there is a way to pull "Past Year" stats of cpu.usage.average and filter only the Instance value which is eq ""

Something like below

get-vmhost esxihost|(get-stat -stat cpu.usage.average |?{$_.InstanceID -eq ""}) -Start $startTime -Finish $endTime

ITSavant's profile image
ITSavant

Instance stats (per core) are only retained for up to 1 hour as far as I can tell.

This works:
$VMhost | Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddMinutes(-61) -Finish (Get-Date).AddMinutes(-59) -IntervalSecs 30

This returns nothing:
$VMhost | Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddMinutes(-62) -Finish (Get-Date).AddMinutes(-60) -IntervalSecs 30

Once you start looking back further, like a year, you are only going to get a whole system roll up average
$VMhost | Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddYears(-1) -Finish (Get-Date)

or for demonstration:

$VMhost | Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddDays(-365) -Finish (Get-Date).AddDays(-334) -IntervalMins 1440

StephenMoll's profile image
StephenMoll

You can pull historical stats, however you can only get them from vCenter, and as the data ages it gets rolled up into longer and longer sample periods.

So for example if you use "-intervalsecs" switch and try and get 30 second samples from a time period more than 1 hour ago from the current time, I have found the results unreliable. The commandlet is supposed to use the next nearest rollup period, but I have found this to be unreliable at times. (Using vSphere 7u3)

In the past hour, you can get stats with a period of 20 seconds [Performance Intervals]

After 1 hour, these 20 second samples get rolled up into 5 minute samples.

5 min sample are kept for one day, and then then those older than one day get rolled into 30 minute samples.

After a month they are rolled up into 30 minute samples, which means that if you want to get data covering the last year, you will need to keep in mind how coarse the samples are.

For summation stats (e.g. CPU Readiness Summation) this can make long term statistically view look bad, when in reality it isn't. 

When I wanted to do some analysis of stats a few months ago, I had a script that would fetch the "-realtime" stats and append the data to a file, so that I had access to the 20 second samples for periods longer than the past hour. There isn't anything that can do this for you that I am aware of, unless you make use of something like vROPS, or other analysis tools like Splunk. We did not have these options so created a script.

It simply gathered the realtime data (20 second period) and save it every hour.

tbrock47's profile image
tbrock47

I believe the granularity is based on the interval selected. This is user configurable in vCenter. You're likely pulling the 20 second interval which includes those granular core details. I believe the 5-minute interval is where those core stats are dropped. (-IntervalMin 5)

Here is a snipped of some code I wrote in a larger Cluster Utilization script that I run weekly that uses a 30 minute interval.

$finishDate = Get-Date
$startDate = ($finishDate).AddDays(-7)
$IntervalSecs = 1800 #30 minutes
$allArray = @()
ForEach ($vCenter in ($global:DefaultVIServers | Sort-Object Name)) {
    $array = @()
    Get-Cluster -Server $vCenter | ForEach-Object {
        if ($PSItem.ExtensionData.Host) {
            #host details / stats
            $hostDetails = $PSItem | Get-VMHost | `
                Select-Object Name,
            @{N = 'HostCpu'; E = { [int]$_.NumCpu } },
            @{N = 'HostMemGB'; E = { [int]$_.MemoryTotalGB } },
            @{N = 'CpuStats'; E = { $_ | Get-Stat -Stat cpu.usage.average -Start $startDate -Finish $finishDate -IntervalSecs $intervalSecs -EA Ignore} },
            @{N = 'MemStats'; E = { $_ | Get-Stat -Stat mem.usage.average -Start $startDate -Finish $finishDate -IntervalSecs $intervalSecs -EA Ignore } }