在 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"

透過一些谷歌搜索,這看起來是一個很有前途的函數,可以滿足您的需求: 取得登入使用者函數

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

相關內容