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 이전 유틸리티 중 다수는 WMI와 같은 다양한 기본 Windows API를 쿼리합니다. 텍스트 구문 분석을 자세히 알아보기 전에 유틸리티가 정보를 가져오는 위치를 찾아 거기서부터 시작하겠습니다. 특별한 경우에는 PowerShell을 사용하여 쉽게 열거할 수 있는 Win32_LogonSession WMI 클래스를 실제로 쿼리하고 올바른 형식의 개체를 다시 가져오더라도 놀라지 않을 것입니다. 이 접근 방식은 모든 상황에서 작동하지 않을 수도 있지만 적어도 시작하기에는 좋은 방법입니다.

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

약간의 인터넷 검색을 통해 이것은 필요한 기능에 대한 유망한 기능처럼 보입니다. get-loggedonuser 함수

답변3

이것은 Richard의 답변에 대한 의견입니다.

이것이 내가 생각해 낸 것입니다. 모든 라인($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;
}

관련 정보