En PowerShell, ¿cómo puedo analizar una salida preformateada?

En PowerShell, ¿cómo puedo analizar una salida preformateada?

¿Existen herramientas para tomar resultados basados ​​en texto y canalizarlos a un objeto dinámico que pueda consultarse como columnas?

Específicamente, estoy invocando...

query session /server:MYSERVER

.. que está dando salida ..

SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE 
services                                    0  Disc                        
console           Jon                       1  Active  

Esta es mi primera tarea en una función de DevOps, actuar sobre este resultado en función de las condiciones de las columnas, pero después de varios intentos de canalizar hacia foreach, etc., me di cuenta de que son solo varias líneas de cadenas.

Lo que esperaba era algo como...

query session /server:MYSERVER | foreach `
{ `
    if ($_.Username -eq "Jon") `
    {`
        custom-action $_.ID `
    } `
}

(Tenga en cuenta que no necesariamente necesito evaluar el nombre de usuario, o no solo el nombre de usuario; solo lo hago en este ejemplo).

Obviamente esto no funcionará porque esto...

query session /server:192.168.1.103 | foreach { echo $_.GetType() }

.. genera esto ..

IsPublic IsSerial Name                                     BaseType                                                    
-------- -------- ----                                     --------                                                    
True     True     String                                   System.Object                                               
True     True     String                                   System.Object                                               
True     True     String                                   System.Object     

La única solución que encontré es extraer manualmente las columnas usando String.Substring(). Esperaba que hubiera herramientas de PowerShell que automatizaran esto.

[[Esto es un ejemplo,]] pero algunas columnas están en blanco y las columnas de ancho fijo no tienen el mismo ancho entre sí, por lo que analizar esto sería mucho más manual que los ejemplos allí. Esperaba que las actualizaciones de la versión de Powershell tuvieran mejores herramientas, ¿quizás?

Usando Windows Server 2012 R2 (que tiene PowerShell 4).

Respuesta1

No hay nada incorporado.

Sin embargo, no debería ser demasiado difícil crear una ayuda (en un módulo para una fácil reutilización, por supuesto) que tome una definición de cada columna (por ejemplo, nombre, posición inicial, longitud, tipo,...; o tal vez criterios alternativos para separe las columnas si las longitudes no se pueden predeterminar) y crea un objeto personalizado.

Respuesta2

Muchas de estas utilidades anteriores a PowerShell consultan varias API de Windows subyacentes, como WMI. Antes de profundizar en el análisis de texto, intentaría encontrar de dónde obtiene la información la utilidad y comenzar desde allí. Para su caso particular, no me sorprendería si realmente estuviera consultando la clase WMI Win32_LogonSession, que puede enumerar fácilmente usando PowerShell y recuperar objetos formateados correctamente. Es posible que este enfoque no funcione en todas las situaciones, pero al menos sería un buen punto de partida.

$users = get-wmiobject -query "Select * from Win32_LogonSession"

Con un poco de búsqueda en Google, parece una función prometedora para lo que necesitas: función get-loggedonuser

Respuesta3

Este es un comentario para la respuesta de Richard.

Esto es lo que se me ocurrió. Uno buscaría{} en todas las líneas (excepto la primera línea, que es $head) y pasaría a esta función.

Function ParseFixedWidthCols($head,$line) {
    $colnamematches = $head | select-string "(\s*\w+\b\s*)" -allmatches | foreach { $_.matches }
    $cols = @()
    for ($ci=0; $ci -lt $colnamematches.Count; $ci++) {
        $col = $colnamematches[$ci].Value
        $cols += $col
    }
    $col = $cols[0]
    $ret = New-Object PSObject
    $cc = 0
    for ($ci=0; $ci -lt $cols.Count; $ci++) {
        $value = $line.Substring($cc, $cols[$ci].Length)
        $ret | Add-Member -MemberType NoteProperty -name $cols[$ci].Trim() -value $value.Trim()
        $cc += $cols[$ci].Length
    }
    return ret;
}

información relacionada