2 votos

Obtención del uso de RAM por sesión de inicio de sesión en PowerShell

Quiero obtener la memoria utilizada por sesión a través de una función PowerShell. Sólo me interesan las sesiones desconectadas. En el administrador de tareas, puedo ver la memoria utilizada por sessionID:

enter image description here

He intentado obtener la mem usada en MB en PowerShell a través del siguiente script:

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

Pero esto me da el siguiente resultado:

20, 481
21, 451
22, 670
23, 763
24, 949

Que no se acerca ni de lejos a las mem usadas que aparecen en el administrador de tareas. ¿Cómo puedo obtener la memoria RAM por sesión?

Actualización Basado en la sugerencia de Vomit IT, hice esto, pero todavía me da los valores incorrectos:

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

resultado

20, 808288
22, 830872
23, 806404
24, 806312
25, 802892

2voto

PJ Mahoney Puntos 889

PowerShell (el más óptimo)

Gracias Vomit ;) que funciona como yo quería, y me permitió ver la RAM por sesión desconectada. Experimenté que Get-Counter es muy lento, cada llamada en un bucle tarda ~1 seg. Así que opté por Get-CimInstance -ClassName Win32_PerfRawData_PerfProc_Process y entonces obtener el conjunto de trabajo privado. - rinkert

Como destaca la OP, el rendimiento de Get-Counter no es tan óptimo como Get-CimInstance al recuperar valores de propiedades de la clase correspondiente. Esta variación de PowerShell incorpora esta consideración, ofreciendo un rendimiento mejorado si es de importancia para usted.

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

Un Gotcha

Tenga en cuenta que la solución anterior puede tener problemas para acceder a determinadas WorkingSetPrivate valores de propiedad en la clase. Considere la posibilidad de añadir lógica condicional para ignorar los valores nulos y cero para una salida más deseable, si es necesario.

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

Otras soluciones

Incorporar esta solución a su tarea en consecuencia resolverá este problema. Este ejemplo es una versión simple y precisa para que coincida con los valores mostrados en el Gestor de tareas como prefieras para la RAM privada activa.

Esencialmente esto...

  • Pone el Get-Process en un comando ForEach-Object para iterar cada proceso devuelto y los valores de las propiedades.
  • Utiliza un PSCustomObject , dentro de almacenar el PID en un campo.
  • Utiliza Get-Counter especificando el Working Set - Private a devolver, lanzándolo a un [int] y dividiéndolo por 1 KB en otro campo.

Los resultados devolverán una columna con el PID y otra columna con el Memory (active private) que coincide con lo que se ve desde el Administrador de tareas y el Details para esas propiedades.

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
    };
};

Salida

  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 (otra variante)

Aquí hay otra variación en PowerShell usando un comando ForEach declaración de bucle que emite sólo los valores separados por comas deseados de forma más similar a la lógica existente en caso de que esto importe.

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

Salida

16464, 164
25920, 164
11412, 264
12284, 728
18488, 728
20084, 728
3660, 97732
10416, 97732
18424, 97732
1408, 57576

Recursos de apoyo

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X