Powershell get a value from 'query user' and not the headers etc

Task, get the ID from the query user command, I'm trying to get the ID value from the the command 'query user',

Example:PS>  query user

 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME

>administrator         rdp-tcp#0           3  Active          .  04/25/2013 08:43

I'm trying to use psexec and attach to the session.

psexec \\\pc -i sessionid somecommand

how would I go about getting the ID and only the ID from the above query? this is what I've tried so far, among other things...

PS>  query user |Select-Object $_.ID

USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME

>administrator         rdp-tcp#0           3  Active          .  04/25/2013 08:43

I would think this is easy but apparently I am having a brain fart, ideally I like to do this:

$IDValue = query user | Get_the_ID_somehow

psexec \\\pc -i $IDValue somecommand..

thanks in advance.


Since "query user" is not an object you cannot use it as an object in powershell unless you contruct a custom PSObject, so

$IDValue = query user | Select-Object ID
will not work.

I would use something like this:

$users = query user ;
$IDs = @() ;

for ($i=1; $i -lt $users.Count;$i++) {
  # using regex to find the IDs
  $temp = [string]($users[$i] | Select-String -pattern "\s\d+\s").Matches ;
  $temp = $temp.Trim() ;
  $IDs += $temp ;
}

I needed the same today, so here's how I solved it:

function Get-TSSessions {
    param(
        $ComputerName = "localhost"
    )

    query user /server:$ComputerName |
    #Parse output
    ForEach-Object {
        # trim spaces at beginning and end
        $_ = $_.trim() 
        # insert , at specific places for ConvertFrom-CSV command
        $_ = $_.insert(22,",").insert(42,",").insert(47,",").insert(56,",").insert(68,",")
        # Remove every space two or more spaces
        $_ = $_ -replace "\s\s+",""
        # for debug purposes, comment out above row and uncomment row below
        #$_ = $_ -replace "\s","_"

        # output to pipe
        $_

    } |
    #Convert to objects
    ConvertFrom-Csv
}

If you now run Get-TSSessions, it returns an array of objects for each user that Powershell understands.

Here's an example that shows which disconnected users are running chrome.exe:

foreach ($user in GET-TSSessions)
{

    if($user.state -ne "Active")
    {   #User is not active
        $user
        tasklist /FI '"USERNAME eq '$user.USERNAME'"' /FI "IMAGENAME eq chrome.exe"
    }
    else
    {
        "User "+$user.USERNAME+" is currently active."
    }

}

Here is a PowerShell wrapper function for 'query user' / 'quser'. It parses the text output and gives you actual PowerShell objects that you can query for the individual attributes you are interested in, like the session ID.

So you can do things like:

$IDValue = Get-LoggedInUser -ComputerName server1 | where { $_.username -eq 'administrator' } | select-object -ExpandProperty id

Here is the function code:

function Get-LoggedInUser
{
<#
    .SYNOPSIS
        Shows all the users currently logged in

    .DESCRIPTION
        Shows the users currently logged into the specified computernames

    .PARAMETER ComputerName
        One or more computernames

    .EXAMPLE
        PS C:\> Get-LoggedInUser
        Shows the users logged into the local system

    .EXAMPLE
        PS C:\> Get-LoggedInUser -ComputerName server1,server2,server3
        Shows the users logged into server1, server2, and server3

    .EXAMPLE
        PS C:\> Get-LoggedInUser  | where idletime -gt "1.0:0" | ft
        Get the users who have been idle for more than 1 day.  Format the output
        as a table.

        Note the "1.0:0" string - it must be either a system.timespan datatype or
        a string that can by converted to system.timespan.  Examples:
            days.hours:minutes
            hours:minutes
#>

    [CmdletBinding()]
    param
    (
        [ValidateNotNullOrEmpty()]
        [String[]]$ComputerName = $env:COMPUTERNAME
    )

    $out = @()

    ForEach ($computer in $ComputerName)
    {
        try { if (-not (Test-Connection -ComputerName $computer -Quiet -Count 1 -ErrorAction Stop)) { Write-Warning "Can't connect to $computer"; continue } }
        catch { Write-Warning "Can't test connect to $computer"; continue }

        $quserOut = quser.exe /SERVER:$computer 2>&1
        if ($quserOut -match "No user exists")
        { Write-Warning "No users logged in to $computer";  continue }

        $users = $quserOut -replace '\s{2,}', ',' |
        ConvertFrom-CSV -Header 'username', 'sessionname', 'id', 'state', 'idleTime', 'logonTime' |
        Add-Member -MemberType NoteProperty -Name ComputerName -Value $computer -PassThru

        $users = $users[1..$users.count]

        for ($i = 0; $i -lt $users.count; $i++)
        {
            if ($users[$i].sessionname -match '^\d+$')
            {
                $users[$i].logonTime = $users[$i].idleTime
                $users[$i].idleTime = $users[$i].STATE
                $users[$i].STATE = $users[$i].ID
                $users[$i].ID = $users[$i].SESSIONNAME
                $users[$i].SESSIONNAME = $null
            }

            # cast the correct datatypes
            $users[$i].ID = [int]$users[$i].ID

            $idleString = $users[$i].idleTime
            if ($idleString -eq '.') { $users[$i].idleTime = 0 }

            # if it's just a number by itself, insert a '0:' in front of it. Otherwise [timespan] cast will interpret the value as days rather than minutes
            if ($idleString -match '^\d+$')
            { $users[$i].idleTime = "0:$($users[$i].idleTime)" }

            # if it has a '+', change the '+' to a colon and add ':0' to the end
            if ($idleString -match "\+")
            {
                $newIdleString = $idleString -replace "\+", ":"
                $newIdleString = $newIdleString + ':0'
                $users[$i].idleTime = $newIdleString
            }

            $users[$i].idleTime = [timespan]$users[$i].idleTime
            $users[$i].logonTime = [datetime]$users[$i].logonTime
        }
        $users = $users | Sort-Object -Property idleTime
        $out += $users
    }
    Write-Output $out
}