How to Configure Windows Reliability Monitor on Windows Server 2025

Windows Reliability Monitor is a built-in diagnostic tool that tracks system stability over time and presents a visual timeline of events that affect server reliability — including application crashes, Windows component failures, hardware errors, and software installations. Unlike event logs, which can contain thousands of unrelated entries, Reliability Monitor distils system health into a single numeric stability index on a scale of 1 to 10, plotted as a rolling graph. On Windows Server 2025, this tool is invaluable for quickly correlating a sudden degradation in server performance or recurring crashes with a specific software update, driver installation, or application failure — often in seconds rather than hours of manual log review. This guide covers the Reliability Monitor interface, its event categories, PowerShell-based extraction of reliability data, exporting history as XML, and correlating crash events with patch activity.

Prerequisites

  • Windows Server 2025 with Administrator or local Administrator privileges
  • No additional software installation required — Reliability Monitor is built into Windows
  • PowerShell 5.1 or later for scripted data extraction
  • Access to Windows Update history (optional, for patch correlation)

Step 1: Open Reliability Monitor

There are several ways to open Reliability Monitor on Windows Server 2025:

  • Run dialog: Press Win+R, type perfmon /rel, press Enter
  • Control Panel: Control Panel → System and Security → Security and Maintenance → Reliability Monitor (under Maintenance)
  • Search: Type “Reliability” in the Start menu search box and select View reliability history
  • PowerShell: Start-Process perfmon.exe -ArgumentList "/rel"
# Open Reliability Monitor from PowerShell
Start-Process -FilePath "perfmon.exe" -ArgumentList "/rel"

# Alternative — launch via WPF shell command
# Start-Process -FilePath "cmd.exe" -ArgumentList "/c perfmon /rel" -WindowStyle Normal

Step 2: Read the Reliability Graph and Stability Index

The Reliability Monitor displays a rolling 30-day graph with the stability index on the Y-axis (1–10, where 10 is perfectly stable) and dates on the X-axis. Below the graph, events are grouped into rows:

  • Application failures — application crashes and hangs (red circle with X)
  • Windows failures — Blue Screen of Death (BSOD), unexpected shutdowns, boot failures
  • Miscellaneous failures — WMI errors, disk errors, other component failures
  • Warnings — yellow triangles for non-critical issues
  • Information — blue circles indicating successful installations, Windows updates applied

Each point where the stability index drops sharply corresponds to a cluster of failure events on that date. Click any point on the graph to see the events that occurred that day in the lower pane. Double-click an event to open its full details dialog, which includes the faulting module, exception code, and crash dump path.

Step 3: Extract Reliability Data with PowerShell via WMI

The Win32_ReliabilityRecords WMI class provides programmatic access to all reliability events:

# Query all reliability records from the last 30 days
$cutoff = (Get-Date).AddDays(-30)

$records = Get-CimInstance -ClassName Win32_ReliabilityRecords |
    Where-Object { $_.TimeGenerated -ge $cutoff } |
    Sort-Object TimeGenerated -Descending

$records | Select-Object -First 20 @(
    @{ Name = "Date";        Expression = { $_.TimeGenerated } },
    @{ Name = "EventType";   Expression = { $_.EventIdentifier } },
    @{ Name = "SourceName";  Expression = { $_.SourceName } },
    @{ Name = "Message";     Expression = { $_.Message -replace 'r|n', ' ' | 
                                            Select-Object -First 1 } }
) | Format-Table -AutoSize -Wrap
# Get only failure-type events (application and Windows failures)
$failures = Get-CimInstance -ClassName Win32_ReliabilityRecords |
    Where-Object { $_.EventIdentifier -in @(1000, 1001, 1002, 6005, 6006, 6008, 41) } |
    Sort-Object TimeGenerated -Descending

# Group failures by day to identify problem dates
$failures | 
    Group-Object { $_.TimeGenerated.Date.ToString("yyyy-MM-dd") } |
    Select-Object @{ Name = "Date"; Expression = { $_.Name } }, Count |
    Sort-Object Date -Descending | 
    Format-Table -AutoSize

Step 4: Extract Reliability Data via Windows Event Logs

Reliability Monitor draws its data from several Windows Event Log sources. You can query these directly with Get-WinEvent for more detailed filtering:

# Application crashes — Application event log, Event ID 1000
Get-WinEvent -LogName "Application" -FilterHashtable @{
    LogName   = "Application"
    Id        = @(1000, 1001, 1002)
    StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message |
    ForEach-Object {
        [PSCustomObject]@{
            Time      = $_.TimeCreated
            EventID   = $_.Id
            Level     = $_.LevelDisplayName
            Fault     = ($_.Message -split "`n")[0]
        }
    } | Format-Table -AutoSize -Wrap

# Windows failures — System event log (unexpected shutdowns, BSOD)
Get-WinEvent -FilterHashtable @{
    LogName   = "System"
    Id        = @(41, 6005, 6006, 6008)
    StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, Message |
    ForEach-Object {
        [PSCustomObject]@{
            Time    = $_.TimeCreated
            EventID = $_.Id
            Summary = ($_.Message -split "`n")[0]
        }
    } | Format-Table -AutoSize -Wrap
# Query the Reliability Events log directly (if available)
try {
    Get-WinEvent -LogName "Microsoft-Windows-Reliability-Events/Operational" -MaxEvents 50 |
        Select-Object TimeCreated, Id, LevelDisplayName, Message |
        Format-Table -AutoSize -Wrap
} catch {
    Write-Warning "Reliability Events operational log not available. Using WMI fallback."
    Get-CimInstance -ClassName Win32_ReliabilityStabilityMetrics |
        Sort-Object StartMeasurementDate -Descending |
        Select-Object -First 30 |
        Select-Object @{ N="Date"; E={ $_.StartMeasurementDate } },
                      @{ N="StabilityIndex"; E={ [math]::Round($_.SystemStabilityIndex, 2) } } |
        Format-Table -AutoSize
}

Step 5: Read the Stability Index Programmatically

The Win32_ReliabilityStabilityMetrics WMI class provides the daily stability index values that Reliability Monitor plots on the graph:

# Get daily stability index for the past 30 days
$metrics = Get-CimInstance -ClassName Win32_ReliabilityStabilityMetrics |
    Sort-Object StartMeasurementDate -Descending |
    Select-Object -First 30

$metrics | ForEach-Object {
    $index = [math]::Round($_.SystemStabilityIndex, 2)
    $bar   = "#" * [math]::Max(1, [int]($index))
    [PSCustomObject]@{
        Date           = $_.StartMeasurementDate.ToString("yyyy-MM-dd")
        StabilityIndex = $index
        Graph          = $bar
    }
} | Format-Table -AutoSize

# Alert if stability index drops below threshold
$latest = $metrics | Select-Object -First 1
if ($latest.SystemStabilityIndex -lt 5) {
    Write-Warning "ALERT: Stability index is $([math]::Round($latest.SystemStabilityIndex, 2)) — investigate recent failures"
} else {
    Write-Host "Stability index: $([math]::Round($latest.SystemStabilityIndex, 2)) — OK"
}

Step 6: Export Reliability History as XML

Reliability Monitor has a built-in export function in the GUI (Save reliability history link in the lower-left corner of the window), which generates an XML file. You can also export programmatically:

# Export reliability records to XML
$exportPath = "C:ReportsReliabilityHistory_$(Get-Date -Format 'yyyyMMdd').xml"
New-Item -ItemType Directory -Path "C:Reports" -Force | Out-Null

$records = Get-CimInstance -ClassName Win32_ReliabilityRecords |
    Sort-Object TimeGenerated -Descending

$xmlDoc = [xml]""

foreach ($r in $records) {
    $event = $xmlDoc.CreateElement("Event")
    $event.SetAttribute("date",      $r.TimeGenerated.ToString("s"))
    $event.SetAttribute("source",    $r.SourceName)
    $event.SetAttribute("eventId",   $r.EventIdentifier)
    $event.SetAttribute("message",   ($r.Message -replace '[&"'']', ' '))
    $xmlDoc.DocumentElement.AppendChild($event) | Out-Null
}

$xmlDoc.Save($exportPath)
Write-Host "Reliability history exported to: $exportPath"
Get-Item $exportPath | Select-Object Name, Length, LastWriteTime

Step 7: Correlate Crashes with Windows Update Patch Installations

One of the most common uses of Reliability Monitor is correlating server instability with patch installation dates. The Information events in Reliability Monitor record Windows Update installations. Cross-reference these with failure events:

# Get Windows Update installation history
$updateSession = New-Object -ComObject Microsoft.Update.Session
$searcher = $updateSession.CreateUpdateSearcher()
$histCount = $searcher.GetTotalHistoryCount()
$history   = $searcher.QueryHistory(0, [math]::Min($histCount, 50))

$updates = $history | ForEach-Object {
    [PSCustomObject]@{
        Date        = $_.Date
        Title       = $_.Title
        ResultCode  = switch ($_.ResultCode) {
            0 { "Not started" }
            1 { "In progress" }
            2 { "Succeeded" }
            3 { "Succeeded with errors" }
            4 { "Failed" }
            5 { "Aborted" }
        }
        KB = if ($_.Title -match "(KBd+)") { $Matches[1] } else { "N/A" }
    }
} | Sort-Object Date -Descending

Write-Host "=== Recent Windows Updates ==="
$updates | Select-Object -First 15 | Format-Table -AutoSize

# Get crashes on the same days as update installations
Write-Host "`n=== Checking for failures on update days ==="
$updateDates = $updates | Select-Object -ExpandProperty Date | 
               ForEach-Object { $_.Date }

$crashes = Get-CimInstance -ClassName Win32_ReliabilityRecords |
    Where-Object { $_.EventIdentifier -in @(1000, 1001, 6008, 41) }

foreach ($ud in ($updateDates | Select-Object -Unique)) {
    $sameDayCrashes = $crashes | Where-Object { $_.TimeGenerated.Date -eq $ud }
    if ($sameDayCrashes) {
        Write-Warning "Crash events on $($ud.ToString('yyyy-MM-dd')) — same day as a Windows Update:"
        $sameDayCrashes | Select-Object SourceName, Message | Format-List
    }
}
# Generate a combined reliability + patch timeline report
$report = @()

# Add update events
$updates | Select-Object -First 20 | ForEach-Object {
    $report += [PSCustomObject]@{
        Date    = $_.Date
        Type    = "WindowsUpdate"
        Detail  = "$($_.KB) — $($_.Title.Substring(0, [math]::Min(60, $_.Title.Length)))"
    }
}

# Add failure events
Get-CimInstance -ClassName Win32_ReliabilityRecords |
    Where-Object { $_.EventIdentifier -in @(1000, 1001, 6008, 41) } |
    Select-Object -First 20 | ForEach-Object {
        $report += [PSCustomObject]@{
            Date    = $_.TimeGenerated
            Type    = "Failure"
            Detail  = "$($_.SourceName): $(($_.Message -split "`n")[0])"
        }
    }

$report | Sort-Object Date -Descending | Format-Table Date, Type, Detail -AutoSize -Wrap

Step 8: Action Center Integration and Automated Monitoring

Windows Action Center on Server 2025 surfaces Reliability Monitor alerts when the stability index drops significantly. You can also create a scheduled task to automatically check and email the stability index:

# Create a scheduled task that checks stability daily and writes a log
$scriptBlock = @'
$metric = Get-CimInstance Win32_ReliabilityStabilityMetrics | 
    Sort-Object StartMeasurementDate -Descending | 
    Select-Object -First 1
$index = [math]::Round($metric.SystemStabilityIndex, 2)
$msg = "$(Get-Date -Format s) | Server: $env:COMPUTERNAME | Stability Index: $index"
Add-Content -Path "C:ReportsReliabilityLog.txt" -Value $msg
if ($index -lt 6) {
    # Trigger an event in the Application log for monitoring tools to pick up
    Write-EventLog -LogName Application -Source "ReliabilityCheck" `
        -EventId 9001 -EntryType Warning `
        -Message "Server stability index is $index — review Reliability Monitor"
}
'@

$scriptPath = "C:ScriptsCheck-Reliability.ps1"
New-Item -ItemType Directory -Path "C:Scripts" -Force | Out-Null
Set-Content -Path $scriptPath -Value $scriptBlock

# Register the event log source if it doesn't exist
if (-not [System.Diagnostics.EventLog]::SourceExists("ReliabilityCheck")) {
    New-EventLog -LogName Application -Source "ReliabilityCheck"
}

# Register the scheduled task
$trigger  = New-ScheduledTaskTrigger -Daily -At "07:00"
$action   = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NonInteractive -File $scriptPath"
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit "00:05:00"

Register-ScheduledTask `
    -TaskName "Daily-ReliabilityCheck" `
    -Trigger $trigger `
    -Action $action `
    -Settings $settings `
    -RunLevel Highest `
    -Description "Daily reliability index check for Windows Server 2025"

Write-Host "Scheduled task registered: Daily-ReliabilityCheck"

Conclusion

Windows Reliability Monitor on Windows Server 2025 is often underutilised despite being one of the fastest tools available for answering the question “what changed on this server before it started behaving badly?” By combining the GUI’s visual stability timeline with PowerShell extraction of WMI reliability records, Windows Update history correlation, and automated daily monitoring tasks, you create a low-overhead stability tracking system that requires no additional software. The exported XML history and correlated crash-versus-patch timelines are especially valuable when communicating server health to stakeholders or during post-incident reviews, providing a clear, timestamped narrative of system events.