我想通过 PowerShell 函数获取每个会话使用的内存。我只对断开连接的会话感兴趣。在任务管理器中,我可以看到每个 sessionID 使用的内存:
我尝试通过以下脚本在 PowerShell 中获取使用的内存(以 MB 为单位):
# Get all user sessions
$sessions = qwinsta | Where-Object { $_ -match 'Disc' }
$procs = get-process # | where-object {$_.ProcessName -ne "Idle"}
foreach ($session in $sessions)
{
$sessionId = ($session -split '\s+')[2]
$usrprocs = $procs | where-object {$_.SessionId -eq $sessionId}
$usrMem=0
foreach($proc in $usrprocs)
{
$usrMem = $usrMem + [int64]($proc.WorkingSet64/(1024*1024))
}
echo "$sessionId, $usrMem"
}
但这给了我以下结果:
20, 481
21, 451
22, 670
23, 763
24, 949
这远远低于任务管理器中列出的已用内存量。我如何获取每个会话的 RAM 量?
更新 根据 Vomit IT 的建议,我这样做了,但它仍然给我错误的值:
# Get all user sessions
$sessions = qwinsta | Where-Object { ($_ -match 'Disc') }
foreach ($session in $sessions)
{
$sessionId = ($session -split '\s+')[2]
$usrprocs = Get-Process | Where-Object { $_.SessionId -eq $sessionId }
$usrMem=0
foreach($proc in $usrprocs)
{
$usrMem = $usrMem + [int](Get-Counter -Counter "\Process($($proc.Name))\Working Set - Private").CounterSamples.CookedValue / 1KB
}
echo "$sessionId, $usrMem"
}
结果
20, 808288
22, 830872
23, 806404
24, 806312
25, 802892
答案1
PowerShell(最优)
谢谢 Vomit ;) 它按我想要的方式工作,并允许我查看每个断开连接的会话的 RAM 使用情况。我确实体验过它
Get-Counter
非常慢,循环中的每个调用都需要大约 1 秒。所以我选择使用Get-CimInstance -ClassName Win32_PerfRawData_PerfProc_Process
,然后将工作集设为私有。– 林克特
正如 OP 所强调的那样,的性能Get-Counter
不如Get-CimInstance
从相应类中检索属性值时那么理想。 PowerShell 的这个变体考虑到了这一点,如果这对您很重要,则可以提供更好的性能。
$session = quser | Where-Object { ($_ -match 'Disc') } 2>&1;
$sId = $session | ForEach-Object { ($_ -split '\s+')[2]};
$processes = Get-Process | Where-Object { $_.SessionId -in $sId };
foreach ($process in $processes) {
$workingSet = [int](Get-CimInstance -ClassName Win32_PerfRawData_PerfProc_Process -Filter "Name='$($process.Name)'").WorkingSetPrivate / 1KB;
"$($process.Id), $($workingSet)";
};
陷阱
请注意,上述解决方案WorkingSetPrivate
在访问类中的某些属性值时可能会出现问题。如有必要,请考虑添加条件逻辑以忽略 null 和零值,以获得更理想的输出。
foreach ($process in $processes) {
$instance = Get-CimInstance -ClassName Win32_PerfRawData_PerfProc_Process -Filter "Name='$($process.Name)'"
if ($instance.WorkingSetPrivate -ne $null -and $instance.WorkingSetPrivate -gt 0) {
$workingSet = [int]($instance.WorkingSetPrivate / 1KB)
"$($process.Id), $($workingSet)"
}
}
其他解决方案
将此解决方案相应地纳入您的任务中将解决此问题。此示例是一个简单的版本,可以精确匹配任务管理器正如您喜欢活动的私有 RAM 一样。
本质上这...
- 将
Get-Process
命令放入循环中ForEach-Object
以迭代每个返回的进程和属性值。 - 使用
PSCustomObject
,将存储PID
在一个字段中。 - 使用
Get-Counter
,指定Working Set - Private
返回,将其转换为[int]
,然后1 KB
在另一个字段中将其除以。
结果将返回一列,其中包含与您从任务管理器和那里的这些属性的选项卡视图中看到的内容相匹配的PID
另一列。Memory (active private)
Details
电源外壳
$session = quser | Where-Object { ($_ -match 'Disc') } 2>&1;
$sId = $session | ForEach-Object { ($_ -split '\s+')[2]};
Get-Process | Where-Object { $_.SessionId -in $sId } | ForEach-Object {
[PSCustomObject]@{
"PID" = $_.Id
"Memory (active private)" = [int](Get-Counter -Counter "\Process($($_.Name))\Working Set - Private").CounterSamples.CookedValue / 1KB
};
};
输出
PID Memory (active private)
--- -----------------------
16464 164
25920 164
11412 264
12284 712
18488 712
20084 712
3660 96952
10416 96952
18424 96952
1408 59000
PowerShell(另一种变体)
以下是 PowerShell 的另一种变体,使用ForEach
循环语句如果这很重要,它只会输出所需的逗号分隔的值,更类似于您现有的逻辑。
$session = quser | Where-Object { ($_ -match 'Disc') } 2>&1;
$sId = $session | ForEach-Object { ($_ -split '\s+')[2]};
$processes = Get-Process | Where-Object { $_.SessionId -in $sId };
foreach ($process in $processes) {
$workingSet = (Get-Counter -Counter "\Process($($process.Name))\Working Set - Private").CounterSamples.CookedValue / 1KB;
"$($process.Id), $([int]$workingSet)";
};
输出
16464, 164
25920, 164
11412, 264
12284, 728
18488, 728
20084, 728
3660, 97732
10416, 97732
18424, 97732
1408, 57576