When troubleshooting performance issues on Windows Server 2012, especially those occurring during unattended operations, traditional monitoring tools like Task Manager or Process Monitor fall short. The key requirements are:
- Service-based operation (no RDP session dependency)
- Long-duration monitoring (24+ hours)
- Process-level CPU usage tracking
- Historical data analysis capability
Windows Performance Monitor (PerfMon) is the built-in tool that meets all these requirements. Here's how to set it up:
# PowerShell script to create a data collector set
$DataCollectorSetName = "24h_CPU_Process_Monitor"
$OutputPath = "C:\PerfLogs\CPU_Monitoring"
# Create the data collector set
logman create counter $DataCollectorSetName -o $OutputPath -f bin -v mmddhhmm -max 1000 -c "\Process(*)\% Processor Time" "\Processor(_Total)\% Processor Time" -si 15
To capture both process names and CPU usage:
- Create a new Data Collector Set in Performance Monitor
- Add these counters:
- \Process(*)\% Processor Time
- \Process(*)\ID Process
- Set sample interval to 15-30 seconds
- Configure output as binary log (.blg) for efficient storage
To ensure monitoring continues after disconnection:
# Start the collector set and configure for service operation
logman start $DataCollectorSetName
logman update $DataCollectorSetName -b 01/01/2024 00:00:00 -e 01/02/2024 00:00:00
schtasks /create /tn "CPU_Monitor" /tr "logman start $DataCollectorSetName" /sc once /st 23:50 /ru "SYSTEM"
When performance issues occur, use PowerShell to parse the logs:
# PowerShell analysis script
$logPath = "C:\PerfLogs\CPU_Monitoring\*.blg"
$timeOfInterest = "03:15 AM"
$data = Import-Counter $logPath
$problemData = $data | Where-Object {$_.TimeStamp -like "*$timeOfInterest*"}
$processes = $problemData.CounterSamples |
Where-Object {$_.Path -like "*\Process(*)\% Processor Time*"} |
Sort-Object -Property CookedValue -Descending |
Select-Object -First 10
$processes | ForEach-Object {
$processName = $_.Path.Split(')')[0].Split('(')[1]
[PSCustomObject]@{
Time = $_.TimeStamp
Process = $processName
CPU = [math]::Round($_.CookedValue, 2)
PID = ($problemData.CounterSamples |
Where-Object {$_.Path -like "*\Process($processName)\ID Process*"}).CookedValue
}
} | Format-Table -AutoSize
For more advanced monitoring, consider:
- Windows Event Forwarding for centralized logging
- PowerShell DSC for configuration management
- Third-party tools like PRTG or Zabbix
When troubleshooting intermittent performance issues on Windows Server 2012, the main obstacles are:
- Group Policy enforced session timeouts (10 minutes idle disconnect)
- Need for 24/7 monitoring capability
- Requirement for process-level CPU attribution
- Historical data analysis capability
Windows Performance Monitor (PerfMon) can be configured as a service through Data Collector Sets. Here's how to set it up:
# PowerShell script to create and start a Data Collector Set
$DataCollectorSetName = "ProcessCPUUsage"
$OutputDirectory = "C:\\PerfLogs\\ProcessCPU"
# Create the data collector set
logman create counter $DataCollectorSetName -o $OutputDirectory -f csv -v mmddhhmm -c "\Process(*)\% Processor Time"
# Set sample interval to 15 seconds
logman update $DataCollectorSetName -si 15
# Start the collector
logman start $DataCollectorSetName
For more detailed analysis, WPR provides ETW-based tracing:
# Start recording with process CPU profile
wpr -start CPU -start GeneralProfile -filemode
# After 24 hours, stop and save
wpr -stop C:\\PerfLogs\\ProcessCPU.etl
For CSV output from PerfMon, use PowerShell to analyze:
# Find peak CPU usage periods
$data = Import-Csv "C:\\PerfLogs\\ProcessCPU\\*.csv" |
Where-Object { $_.'Process(*)\% Processor Time' -gt 80 }
# Group by process and show max CPU
$data | Group-Object "Process Name" |
Select-Object Name,
@{Name="MaxCPU";Expression={($_.Group | Measure-Object -Property "Process(*)\% Processor Time" -Maximum).Maximum}}
To make this persistent across reboots:
# Create scheduled task to start monitoring at startup
$action = New-ScheduledTaskAction -Execute "logman.exe" -Argument "start ProcessCPUUsage"
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName "Process CPU Monitor" -Action $action -Trigger $trigger -User "SYSTEM"
For graphical analysis of collected data:
- Use Performance Monitor to load the CSV and create graphs
- Import ETL files into Windows Performance Analyzer (WPA)
- Use PowerShell's Out-GridView for quick filtering