This is a very common topic that I’m sure has thousands of results on your preferred search engine. Have you attempted to search for it? My initial search shows dozens of possible solutions.
this does seem to be a common topic for Powershellers. I wrote something a long time ago that used CIM and the same Win32_ComputerSystem class to pull the logged on user. Something like this inside a try/catch:
Coincidentally just this past Friday I was helping someone make a Lock-Screen function and ran in to what you did; if the user is connected via RDP that Win32_ComputerSystem class won’t tell us their username. I went back to the googs and scoured the internet trying to find a better way and my end result was that there isn’t really a native Powershell way that’s reliable. So, I used my wrapper function for quser so I could key off of object properties.
Function Invoke-Quser {
<#
.SYNOPSIS
A wrapper for Quser.exe to return Powershell objects
.DESCRIPTION
Executes Quser locally or against a remote computer and returns the results as Powershell objects
.PARAMETER ComputerName
Remote computername for use with "/SERVER" parameter within Quser.exe
.PARAMETER UserorSession
If you know the username, sessionID number, or Session type you can pass that to this parameter.
.EXAMPLE
PS C:\> Invoke-Quser
Username : John123
SessionID : 1
SessionName : Console
State : Active
LogonTime : 2/17/2022 8:27:00 AM
.Notes
Version: 1.3
Author: C. Bodett
Creation Date: 5/11/2022
Purpose/Change: Changed the split method on the user info row to be more like github.com/UNT-CAS/QuserObject implementation. Borrowed a lot of their methodology from that module and used it here.
#>
[cmdletbinding()]
Param (
[Parameter(Mandatory = $false, Position = 0)]
[String]$ComputerName = "Localhost",
[Parameter(Mandatory = $false)]
[String]$UserorSession
)
if ($ComputerName -eq "Localhost") {
$Qcmd = '{0} {1}'
} else {
$Qcmd = '{0} {1} /SERVER:{2}'
}
$Quser = $Qcmd -f 'quser.exe', $UserorSession, $ComputerName
try {
$Results = (Invoke-Expression $Quser) 2>&1
} catch {
$Results = $Error[0].Exception.Message
}
if ($LASTEXITCODE -eq 0) {
$QUserOutput = Foreach ($Result in ($Results | Select-Object -Skip 1)) {
$ParsedLine = $Result -split '\s{2,}'
[System.Collections.Generic.List[String]]$SessionInfo = $ParsedLine | Select-Object -Skip 1
if ($SessionInfo.Count -eq 4) {
# session name is blank. adding a blank entry to the array
$SessionInfo.Insert(0,'')
}
$IdleTime = if ($SessionInfo[3] -eq "none" -or $SessionInfo[3] -eq '.') {
"none"
} else {
If ($SessionInfo[3] -as [Int]) {
$SessionInfo[3] = "0:$($SessionInfo[3])"
}
[Timespan]$QuserIdle = $SessionInfo[3].Replace('+','.')
$QuserIdle
}
$UserInfo = [PSCustomObject]@{
ComputerName = $ComputerName
Username = $ParsedLine[0].TrimStart('>').Trim()
SessionID = [Int]$SessionInfo[1]
SessionName = $SessionInfo[0]
State = $SessionInfo[2]
IdleTime = $IdleTime
LogonTime = Get-Date $SessionInfo[4]
}
$UserInfo
}
return $QUserOutput
} else {
Write-Warning $Results.Exception.message
}
}
Try this out. Bare in mind that if there are multiple users signed in (even if disconnected) Invoke-Quser will return multiple objects, so code appropriately for that.
not PS but this seems to work for both console and RDP:
query user /server:$ServerName
Also keep in mind you can pretty easily run two commands instead of 1 if you need two different pieces of data, and just create a PowerShell function that makes it all into a pretty output.
I do see quser mentioned a ton just from a few google searches, so greyout’s probably works as well, but the one liner above is super easy.
A bit ironic I’ve never needed to really do this in my workplace heh.