No PowerShell, como posso analisar uma saída pré-formatada?

No PowerShell, como posso analisar uma saída pré-formatada?

Existem ferramentas para obter saída baseada em texto e canalizá-la para um objeto dinâmico que pode ser consultado como colunas?

Especificamente, estou invocando ..

query session /server:MYSERVER

.. que está produzindo ..

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

Esta é minha primeira tarefa em uma função de DevOps, agir de acordo com essa saída com base nas condições das colunas, mas depois de várias tentativas de canalizar para foreach etc., percebi que são apenas várias linhas de strings.

O que eu esperava era algo como ..

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

(Observe que não preciso necessariamente avaliar o nome de usuário, ou não apenas o nome de usuário, estou fazendo isso apenas neste exemplo.)

Obviamente isso não vai funcionar porque isso ..

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

.. gera isso ..

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

A única solução que encontrei é extrair manualmente as colunas usando String.Substring(). Eu esperava que houvesse ferramentas do PowerShell que automatizassem isso.

[[Isto é um exemplo,]] mas algumas colunas estão em branco e as colunas de largura fixa não têm a mesma largura entre si, portanto, analisar isso seria muito mais manual do que os exemplos aqui. Eu esperava que as atualizações da versão do Powershell pudessem ter ferramentas melhores, talvez?

Usando o Windows Server 2012 R2 (que possui PowerShell 4).

Responder1

Não há nada embutido.

No entanto, não deve ser muito difícil criar um auxiliar (em um módulo para fácil reutilização, é claro) que receba uma definição de cada coluna (por exemplo, nome, posição inicial, comprimento, tipo, ...; ou talvez critérios alternativos para separe as colunas se os comprimentos não puderem ser pré-determinados) e crie um objeto personalizado.

Responder2

Muitos desses utilitários pré-PowerShell consultam várias APIs subjacentes do Windows, como o WMI. Antes de me aprofundar na análise de texto, eu tentaria descobrir de onde o utilitário obtém suas informações e começaria a partir daí. Para o seu caso específico, não ficaria surpreso se ele realmente estivesse consultando a classe WMI Win32_LogonSession, que você pode enumerar facilmente usando o PowerShell - e recuperar objetos formatados corretamente. Essa abordagem pode não funcionar em todas as situações, mas seria um bom ponto de partida, pelo menos.

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

Pesquisando um pouco no Google, esta parece uma função promissora para o que você precisa: função get-loggedonuser

Responder3

Este é um comentário para a resposta de Richard.

Isto é o que eu inventei. Seria possível foreach{} em todas as linhas (exceto a primeira linha, que é $head) e passar para esta função.

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

informação relacionada