多实例进程场景下PowerShell监控脚本报错求助(op_Division缺失)
解决PowerShell多实例进程CPU/内存监控脚本报错问题
问题描述
在Windows Server上用PowerShell脚本记录指定进程的CPU和内存使用率时,单实例进程场景运行正常,但存在同名多实例进程时,脚本无输出且抛出错误:
Method invocation failed because [System.Object[]] does not contain a method named 'op_Division'
已确认$processList = Get-Process -Name myMap | Select-Object -ExpandProperty ProcessName能正确获取进程列表。
错误原因
- CPU计算逻辑问题:当进程存在多实例时,
Get-Counter "\Process($processName*)\% Processor Time"返回的CookedValue是数组,直接对数组执行除法操作(除以进程数)会触发类型错误,因为PowerShell不支持数组与数字的直接除法运算。 - 内存计算逻辑问题:多实例场景下,
Get-Process -Name $processName返回的是进程对象数组,$process.WorkingSet64会返回所有实例的内存值数组,直接做除法得到的也是数组,无法正确写入CSV。
修复方案
方案1:汇总多实例进程的CPU和总内存(按进程名统计)
修改脚本中的CPU和内存计算逻辑,处理数组对象:
$processList = Get-Process -Name myMap | Select-Object -ExpandProperty ProcessName | Get-Unique $outputFile = "D:\Users\vin\Performance_Srcipts\output\mymap.csv" # 写入CSV表头 "Timestamp,ProcessName,%CPU,TotalMemory(MB)" | Out-File -FilePath $outputFile -Encoding UTF8 For ($i = 0; $i -lt 10; $i++) { foreach ($processName in $processList) { # 一次性获取所有实例,避免重复调用 $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue if ($processes) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $processCount = $processes.Count # 处理CPU统计:先获取所有实例的CPU值,求和后除以进程数 $cpuValues = try { (Get-Counter -Counter "\Process($processName*)\% Processor Time").CounterSamples.CookedValue } catch { @(0) } $totalCpu = ($cpuValues | Measure-Object -Sum).Sum $avgCpu = [math]::Round($totalCpu / $processCount, 2) # 处理内存统计:汇总所有实例的内存 $totalMemory = ($processes.WorkingSet64 | Measure-Object -Sum).Sum $totalMemoryMB = [math]::Round($totalMemory / 1MB, 2) # 写入CSV "$timestamp,$processName,$avgCpu,$totalMemoryMB" | Out-File -FilePath $outputFile -Append -Encoding UTF8 } } Start-Sleep -Seconds 5 } Write-Host "Process monitoring completed. Data saved to $outputFile"
方案2:单独记录每个进程实例的CPU和内存(按实例统计)
如果需要监控每个实例的单独数据,修改遍历逻辑:
$processName = "myMap" # 直接指定进程名,无需提前获取列表 $outputFile = "D:\Users\vin\Performance_Srcipts\output\mymap.csv" # 写入CSV表头,增加PID区分实例 "Timestamp,ProcessName,PID,%CPU,Memory(MB)" | Out-File -FilePath $outputFile -Encoding UTF8 For ($i = 0; $i -lt 10; $i++) { $processes = Get-Process -Name $processName -ErrorAction SilentlyContinue if ($processes) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # 获取所有实例的CPU计数器 $cpuCounters = try { Get-Counter -Counter "\Process($processName*)\% Processor Time" | Select-Object -ExpandProperty CounterSamples } catch { @() } foreach ($proc in $processes) { # 匹配当前进程实例的CPU值(通过计数器实例名匹配,格式为"myMap#1"、"myMap#2") $counterInstance = "$processName#$($proc.Id)" $cpuValue = ($cpuCounters | Where-Object { $_.InstanceName -eq $counterInstance }).CookedValue $cpu = if ($cpuValue) { [math]::Round($cpuValue, 2) } else { 0 } $memoryMB = [math]::Round($proc.WorkingSet64 / 1MB, 2) # 写入每个实例的数据 "$timestamp,$processName,$($proc.Id),$cpu,$memoryMB" | Out-File -FilePath $outputFile -Append -Encoding UTF8 } } Start-Sleep -Seconds 5 } Write-Host "Process monitoring completed. Data saved to $outputFile"
关键修改说明
- 对
Get-Counter返回的数组值,先用Measure-Object -Sum求和,再做除法运算,避免直接操作数组。 - 多实例场景下,一次性获取所有进程对象,减少重复调用
Get-Process提升效率。 - 方案2中通过进程ID匹配对应的CPU计数器实例,确保每个进程的CPU值对应正确。
内容的提问来源于stack exchange,提问作者Vineet
相关产品推荐
相关产品推荐

