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
}