在 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 的实用程序会查询各种底层 Windows API,例如 WMI。在深入研究文本解析之前,我会尝试找到实用程序从哪里获取信息并从那里开始。对于您的特定情况,如果它实际上查询 Win32_LogonSession WMI 类,我不会感到惊讶,您可以使用 PowerShell 轻松枚举该类 - 并返回正确格式化的对象。这种方法可能不适用于所有情况,但至少它是一个很好的起点。

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

通过谷歌搜索,你会看到这个功能看起来非常有希望满足你的需要: get-loggedonuser 函数

答案3

这是对理查德的回应的评论。

这就是我想到的。一个是对所有行(第一行除外,即 $head)进行 foreach{},然后传递给此函数。

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

相关内容