KPI – Uptime ESXi and VMs

KPIs, or Key Performance Indicators, in an IT system context are measurable metrics used to evaluate the performance, reliability, and efficiency of the system. These indicators help Key Performance Indicators, or KPIs, are measurable metrics used to assess the performance, reliability, and efficiency of an IT system. They help organizations track key aspects like system uptime, response times, error rates, user satisfaction, and resource usage. By reviewing KPIs, IT teams can pinpoint areas for improvement, ensure they align with business goals, and keep the system running at its best.organizations monitor critical aspects such as system uptime, response times, error rates, user satisfaction, and resource utilization. By analyzing KPIs, IT teams can identify areas for improvement, ensure alignment with business goals, and maintain optimal system performance.

Uptime

System uptime is the amount of time a system—usually a computer or network—is up and running, without any interruptions. This info is useful because it gives a clear picture of the system’s reliability and performance, helping organizations provide consistent service, spot potential problems, and keep users happy.

On the VMware Infrastructure, useful uptime information is to understand the time the ESXi, vCenter, and the VMs running on it have been up. Please note that VM uptime from the hypervisor perspective does not provide all the answers; it only indicates the time since the last boot. Additional evaluation should also be conducted at the OS and/or application level. The hypervisor perspective doesn’t provide all the answers; it only indicates the time since the last boot. Additional surveying should also be conducted on the OS and/or application levels.

Script to measure uptime

Here’s a PowerCLI script that gathers uptime info from multiple vCenters and exports it to an Excel file (“.xlsx”). Each vCenter gets its own sheet, along with separate sheets for ESXi hosts and Virtual Machines (VMs). The VM sheet includes a row for the vSphere Cluster and one for the ESXi host.

# Load modules
Import-Module VMware.PowerCLI -ErrorAction Stop
Import-Module ImportExcel -ErrorAction Stop

Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

# Prompt for vCenters
$vCenters = Read-Host "Enter comma-separated vCenter FQDNs/IPs"
$vCenterList = $vCenters -split "," | ForEach-Object { $_.Trim() }

# Optional cluster filter
$clusterFilter = Read-Host "Enter cluster name to filter by (leave blank for all clusters)"

# Get credentials
$cred = Get-Credential
$now = Get-Date

foreach ($vCenter in $vCenterList) {
    Write-Host "`n🔗 Connecting to $vCenter ..."
    try {
        $vcConnection = Connect-VIServer -Server $vCenter -Credential $cred -ErrorAction Stop
    } catch {
        Write-Warning "❌ Could not connect to $vCenter: $_"
        continue
    }

    $vcenterData = @()
    $esxiData = @()
    $vmData = @()

    #### 1. ESXi Hosts (filtered)
    $esxiHosts = if ($clusterFilter -ne "") {
        Get-Cluster -Name $clusterFilter -ErrorAction SilentlyContinue | Get-VMHost
    } else {
        Get-VMHost
    }

    foreach ($host in $esxiHosts) {
        $bootTime = $host.ExtensionData.Summary.Runtime.BootTime
        $uptime = ($now - $bootTime).TotalDays
        $esxiData += [PSCustomObject]@{
            Name       = $host.Name
            UptimeDays = [math]::Round($uptime, 2)
            LastBoot   = $bootTime
        }
    }

    #### 2. VCSA Uptime via REST
    $session = Get-View SessionManager
    $sessionID = $global:DefaultVIServer.SessionId
    $vcsaApi = "https://$vCenter/rest/appliance/system/uptime"

    $cookie = New-Object System.Net.Cookie
    $cookie.Name = "vmware-api-session-id"
    $cookie.Value = $sessionID
    $cookie.Domain = $vCenter

    $handler = New-Object System.Net.Http.HttpClientHandler
    $handler.CookieContainer = New-Object System.Net.CookieContainer
    $handler.CookieContainer.Add($cookie)

    $client = New-Object System.Net.Http.HttpClient($handler)
    $response = $client.GetAsync($vcsaApi).Result

    if ($response.IsSuccessStatusCode) {
        $data = $response.Content.ReadAsStringAsync().Result | ConvertFrom-Json
        $uptimeSec = $data.value
        $uptimeDays = [math]::Round($uptimeSec / 86400, 2)
        $bootTime = $now.AddSeconds(-$uptimeSec)

        $vcenterData += [PSCustomObject]@{
            Name       = $vCenter
            UptimeDays = $uptimeDays
            LastBoot   = $bootTime
        }
    } else {
        Write-Warning "⚠️ Could not retrieve VCSA uptime for $vCenter"
        $vcenterData += [PSCustomObject]@{
            Name       = $vCenter
            UptimeDays = "Unavailable"
            LastBoot   = "Unavailable"
        }
    }

    #### 3. Powered-on VMs (filtered, with cluster & host)
    $vms = if ($clusterFilter -ne "") {
        Get-Cluster -Name $clusterFilter -ErrorAction SilentlyContinue | Get-VM | Where-Object { $_.PowerState -eq "PoweredOn" }
    } else {
        Get-VM | Where-Object { $_.PowerState -eq "PoweredOn" }
    }

    foreach ($vm in $vms) {
        try {
            $bootTime = $vm.ExtensionData.Summary.Runtime.BootTime
            $host = ($vm.VMHost).Name
            $cluster = ($vm | Get-Cluster).Name
            if ($bootTime) {
                $uptime = ($now - $bootTime).TotalDays
                $vmData += [PSCustomObject]@{
                    Name       = $vm.Name
                    Cluster    = $cluster
                    Host       = $host
                    UptimeDays = [math]::Round($uptime, 2)
                    LastBoot   = $bootTime
                }
            } else {
                $vmData += [PSCustomObject]@{
                    Name       = $vm.Name
                    Cluster    = $cluster
                    Host       = $host
                    UptimeDays = "Unavailable"
                    LastBoot   = "Unavailable"
                }
            }
        } catch {
            Write-Warning "⚠️ Could not get uptime for VM $($vm.Name)"
        }
    }

    #### 4. Export to Excel
    $cleanName = $vCenter -replace "[^a-zA-Z0-9]", "_"
    $clusterSuffix = if ($clusterFilter -ne "") { "_$clusterFilter" } else { "" }
    $outputPath = "$env:USERPROFILE\Desktop\Uptime_${cleanName}${clusterSuffix}.xlsx"

    $excelParams = @{
        Path = $outputPath
        AutoSize = $true
        BoldTopRow = $true
        FreezeTopRow = $true
    }

    $vcenterData | Export-Excel @excelParams -WorksheetName "vCenter"
    $esxiData    | Export-Excel @excelParams -WorksheetName "ESXi Hosts" -Append -WorksheetOrder 1
    $vmData      | Export-Excel @excelParams -WorksheetName "Virtual Machines" -Append -WorksheetOrder 2

    Write-Host "✅ Excel report saved: $outputPath"

    Disconnect-VIServer -Server $vCenter -Confirm:$false
}

VM Sheet Output Example:

NameClusterHostUptimeDaysLastBoot
appserver01ProdClusteresxi03.lab3.122025-06-15 12:30:00
db01ProdClusteresxi02.lab4.892025-06-14 08:10:00

Leave a Reply

Your email address will not be published. Required fields are marked *

Share on Social Media