1

Is there existing tooling to take text-based output and pipe it to a dynamic object that can be queried as columns?

Specifically, I'm invoking ..

query session /server:MYSERVER

.. which is outputting ..

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

This is my first task in a DevOps role, to act upon this output based on conditions of the columns, but after multiple tries to pipe into foreach etc I realized that it's all just multiple lines of strings.

What I was hoping for was something like ..

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

(Note that I do not necessarily need to evaluate the Username, or not only the Username, I am only doing so in this example.)

Obviously this won't work because this ..

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

.. outputs this ..

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

The only solution I've found is manually extracting the columns using String.Substring(). I was hoping there was PowerShell tooling that automated this.

[[This is an example,]] but some columns are blank, and the fixed-width columns are not the same width between each other, so parsing this would be much more manual than the examples there. I was hoping that Powershell version updates might have better tooling perhaps?

Using Windows Server 2012 R2 (which has PowerShell 4).

stimpy77
  • 429
  • 1
  • 5
  • 12

3 Answers3

2

There is nothing built in.

However it shouldn't be too hard to create a helper (in a module for easy reuse of course) that takes a definition of each column (eg. name, starting position, length, type, ...; or perhaps alternate criteria to separate the columns if lengths cannot be pre-determined) and creates a custom object.

Richard
  • 5,309
  • 1
  • 22
  • 20
1

This is a comment for Richard's response.

This is what I came up with. One would foreach{} on all the lines (except the first line, which is $head) and pass to this function.

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;
}
stimpy77
  • 429
  • 1
  • 5
  • 12
0

A lot of these pre-PowerShell utilities query various underlying Windows APIs, such as WMI. Before digging into text parsing I'd try and find where the util gets its info from and start from there. For your particular case, I wouldn't be surprised if it actually is querying the Win32_LogonSession WMI class, which you can easily enumerate using PowerShell - and get properly formatted objects back. This approach may not work in all situations, but it would be a good place to start, at least.

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

With a bit of googling, this looks like a promising function for what you need: get-loggedonuser function

Trondh
  • 4,191
  • 23
  • 27