Quser to PSObject
I have been using Quser for years and I was wondering how to parse the data out to Powershell. The best way to do this is to convert the output into a csv and then convert it from the csv to a psobject. Let us get started. First we output the quser to a variable.
$Users = Quser /server:"$($env:COMPUTERNAME)" 2> $null
In this example, we are going to grab the local computer’s logged-in information. Here is what the output looks like:
PS C:\Users\david> Quser /server:"$($env:COMPUTERNAME)" 2> $null
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
david console 11 Active 1:05 9/5/2021 9:29 PM
susan 12 Disc 1:05 9/6/2021 11:14 AM
Next, we replace the first (^) > with nothing. It doesn’t look like much but it adds the spacing needed.
$Users = $Users -Replace '^>',''
Here is the output.
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
david console 11 Active 1:08 9/5/2021 9:29 PM
susan 12 Disc 1:08 9/6/2021 11:14 AM
Now we will replace the tabs with commas.
$Users = $Users -Replace '\s{2,}',','
USERNAME,SESSIONNAME,ID,STATE,IDLE TIME,LOGON TIME
david,console,11,Active,1:08,9/5/2021 9:29 PM
susan,12,Disc,1:08,9/6/2021 11:14 AM
From here we want to go through each line and remove the last item if it has too many spaces. This happens when you run this command on a server. You will need to go through each line by line with a foreach loop.
$users = foreach ($User in $Users) {
if ($User.Split(',').count -eq 5) {
Write-Output ($User -replace '(^[^,]+)','$1,')
} else {
Write-Output $User
}
}
Splitting the user by the comma, we need only 4 not 5. So we remove the first of the last object. If it is 4, we do nothing special and just reintroduce the original $user.
USERNAME,SESSIONNAME,ID,STATE,IDLE TIME,LOGON TIME
david,console,11,Active,1:08,9/5/2021 9:29 PM
susan,,12,Disc,1:08,9/6/2021 11:14 AM
Now we take that $user csv and convert it to a psobject using convertfrom-csv.
$users = $users | ConvertFrom-Csv
USERNAME : david
SESSIONNAME : console
ID : 11
STATE : Active
IDLE TIME : 1:08
LOGON TIME : 9/5/2021 9:29 PM
USERNAME : susan
SESSIONNAME :
ID : 12
STATE : Disc
IDLE TIME : .
LOGON TIME : 9/6/2021 11:14 AM
Next, we need to do some house cleaning. Sometimes the Idle time will show up as a dot. We don’t want that. We want it to show up as null. We do this by finding all the dot Idle times and setting that idle time to null with a foreach-object.
$users | where-object { $_."IDLE TIME" -like "." } | ForEach-Object { $_."IDLE TIME" = $null }
USERNAME : david
SESSIONNAME : console
ID : 11
STATE : Active
IDLE TIME : 1:08
LOGON TIME : 9/5/2021 9:29 PM
USERNAME : susan
SESSIONNAME :
ID : 12
STATE : Disc
IDLE TIME :
LOGON TIME : 9/6/2021 11:14 AM
Finally, we output the information by just putting the $users. That’s it yall. Lets put it together.
The Script
$Users = Quser /server:"$($env:COMPUTERNAME)" 2> $null
$Users = $Users -Replace '^>',''
$Users = $Users -Replace '\s{2,}',','
$users = foreach ($User in $Users) {
if ($User.Split(',').count -eq 5) {
Write-Output ($User -replace '(^[^,]+)','$1,')
} else {
Write-Output $User
}
}
$users = $users | ConvertFrom-Csv
$users | where-object { $_."IDLE TIME" -like "." } | ForEach-Object { $_."IDLE TIME" = $null }
$Users
Another Way
Another way to do this is to grab a process from the machine that everyone logged in would be using. Something like explorer. We do this with the get-ciminstance and the wmi object win32_process.
Get-ciminstance -ClassName win32_process -filter 'name ="explorer.exe"'
ProcessId Name HandleCount WorkingSetSize VirtualSize
--------- ---- ----------- -------------- -----------
10576 explorer.exe 2805 142168064 2204137693184
18900 explorer.exe 2404 185618432 2204239441920
Then we pipe this information into Invoke-CimMethod and use the GetOwner method to grab the owner information.
Get-ciminstance -ClassName win32_process -filter 'name ="explorer.exe"' | Invoke-CimMethod -MethodName GetOwner
Domain ReturnValue User PSComputerName
------ ----------- ---- --------------
DESKTOP-XXXX0LB 0 david
2
From here we grab the user information using a .user.
(Get-ciminstance -ClassName win32_process -filter 'name ="explorer.exe"' | Invoke-CimMethod -MethodName GetOwner).user