Как в PowerShell можно проанализировать предварительно отформатированный вывод?

Как в PowerShell можно проанализировать предварительно отформатированный вывод?

Существуют ли инструменты для обработки текстового вывода и передачи его в динамический объект, который можно запрашивать как столбцы?

В частности, я призываю ..

query session /server:MYSERVER

.. который выводит ..

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

Это моя первая задача в роли DevOps — действовать на основе этих выходных данных в зависимости от условий столбцов, но после нескольких попыток передать их в foreach и т. д. я понял, что это всего лишь несколько строк.

Я надеялся на что-то вроде...

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

(Обратите внимание, что мне не обязательно оценивать имя пользователя или только имя пользователя, я делаю это только в этом примере.)

Очевидно, это не сработает, потому что это...

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

.. выводит это ..

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

Единственное решение, которое я нашел, — это ручное извлечение столбцов с помощью String.Substring(). Я надеялся, что есть инструмент PowerShell, который автоматизирует это.

[[Это пример,]] но некоторые столбцы пустые, а столбцы фиксированной ширины не имеют одинаковой ширины между собой, поэтому разбор этого будет намного более ручным, чем примеры там. Я надеялся, что обновления версии Powershell, возможно, будут иметь лучший инструментарий?

Используем Windows Server 2012 R2 (с PowerShell 4).

решение1

Ничего встроенного нет.

Однако не должно быть слишком сложно создать помощника (конечно, в модуле для простоты повторного использования), который берет определение каждого столбца (например, имя, начальную позицию, длину, тип, ...; или, возможно, альтернативные критерии для разделения столбцов, если длину невозможно определить заранее) и создает пользовательский объект.

решение2

Многие из этих утилит до PowerShell запрашивают различные базовые API Windows, такие как WMI. Прежде чем углубляться в анализ текста, я бы попытался выяснить, откуда утилита берет информацию, и начать оттуда. В вашем конкретном случае я не удивлюсь, если она на самом деле запрашивает класс WMI Win32_LogonSession, который вы можете легко перечислить с помощью PowerShell — и получить обратно правильно отформатированные объекты. Такой подход может не работать во всех ситуациях, но это было бы хорошим местом для начала, по крайней мере.

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

Если немного погуглить, то это выглядит как многообещающая функция для того, что вам нужно: функция get-loggedonuser

решение3

Это комментарий к ответу Ричарда.

Вот что я придумал. Можно было бы foreach{} на всех строках (кроме первой строки, которая $head) и передать этой функции.

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

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