PowerShell (наиболее оптимальный)

PowerShell (наиболее оптимальный)

Я хочу получить память, используемую для сеанса, через функцию PowerShell. Меня интересуют только отключенные сеансы. В диспетчере задач я могу увидеть память, используемую для сеанса ID:

введите описание изображения здесь

Я попытался получить объем памяти, используемый в МБ, в PowerShell с помощью следующего скрипта:

# 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 ;) это работает так, как я хотел, и позволило мне увидеть использование оперативной памяти на отключенный сеанс. Я столкнулся с тем, что 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 и zero для получения более желательного вывода, если это необходимо.

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)"
    }
}

Другие решения

Внедрение этого решения в вашу задачу соответствующим образомрешит эту проблему. Этот пример является простой версией и точным для соответствия значениям, показанным вДиспетчер задачкак вам больше нравится для активной частной оперативной памяти.

По сути это...

  • Помещает Get-Processкоманду в ForEach-Objectцикл для итерации каждого возвращенного процесса и значений свойств.
  • Использует PSCustomObject, сохраняя PIDв одном поле.
  • Использует Get-Counter, указывая Working Set - Privateвозвращаемое значение, приводя его к типу , [int]а затем делит его на 1 KBв другом поле.

Результаты вернут столбец с PIDи другой столбец с Memory (active private)соответствующим тем, что вы видите в диспетчере задач, и Detailsпредставление вкладок для этих свойств.

PowerShell

$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

Поддерживающие ресурсы

Связанный контент