PowerShell (最適)

PowerShell (最適)

PowerShell 関数を使用して、セッションごとに使用されているメモリを取得したいと考えています。切断されたセッションのみに関心があります。タスク マネージャーでは、セッション ID ごとに使用されているメモリを確認できます。

ここに画像の説明を入力してください

次のスクリプトを使用して、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、 をPID1 つのフィールドに格納します。
  • を使用しGet-CounterWorking 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

サポートリソース

関連情報