When running query session
or basic PowerShell commands like Get-WmiObject -Class Win32_LoggedOnUser
, you get limited information - mainly usernames and session start times. What's missing is crucial session state data (active/idle/disconnected) that's essential for server administration.
Here's an enhanced PowerShell script that retrieves comprehensive session information without remote execution or third-party tools:
function Get-UserSessions {
$sessions = query session | Where-Object { $_ -notmatch '^ SESSIONNAME' } | ForEach-Object {
$session = $_.Trim() -split '\s+'
[PSCustomObject]@{
Username = $session[1]
SessionID = $session[2]
State = $session[3]
SessionType = $session[0]
ConnectedTime = if ($session.Count -gt 4) { $session[4..($session.Count-1)] -join ' ' } else { $null }
}
}
# Get idle times using Win32_SessionProcess
$idleTimes = Get-WmiObject -Class Win32_SessionProcess | ForEach-Object {
$process = Get-WmiObject -Class Win32_Process -Filter "ProcessId = '$($_.ProcessId)'"
[PSCustomObject]@{
SessionID = $process.SessionId
IdleTime = (Get-Date) - $process.ConvertToDateTime($process.CreationDate)
}
}
# Combine data
foreach ($session in $sessions) {
$idleData = $idleTimes | Where-Object { $_.SessionID -eq $session.SessionID }
$session | Add-Member -NotePropertyName IdleMinutes -NotePropertyValue ($idleData.IdleTime.TotalMinutes)
}
return $sessions
}
Get-UserSessions | Format-Table -AutoSize
The script returns these key indicators:
- State: 'Active', 'Disc' (disconnected), or 'Listen'
- IdleMinutes: Minutes since last input (calculated from process creation time)
- SessionType: Console (local) or RDP-Tcp (remote)
To find only active non-idle sessions:
Get-UserSessions | Where-Object { $_.State -eq 'Active' -and $_.IdleMinutes -lt 5 }
To find disconnected sessions older than 1 hour:
Get-UserSessions | Where-Object { $_.State -eq 'Disc' -and $_.IdleMinutes -gt 60 }
The WMI queries add some overhead. For frequent monitoring, consider caching the idle time data or running it as a scheduled task that saves results to a log file.
While PowerShell's query user
or Get-WmiObject Win32_LoggedOnUser
provides basic logged-in user data, administrators often need deeper session state visibility. The native tools show session start times but lack critical details about whether sessions are active, disconnected, or idle.
Here are three built-in approaches with increasing levels of detail:
1. Enhanced PowerShell Query
# This provides more session state details than basic WMI queries
$sessions = qwinsta
$sessions | ForEach-Object {
if ($_ -match "(\d+)\s+(\w+)\s+(\w+)\s+(\w+)\s+([\w\s]+)") {
[PSCustomObject]@{
SessionID = $matches[1]
UserName = $matches[2]
SessionState = $matches[4]
IdleTime = $matches[5]
}
}
}
2. Using Terminal Services (RDS) Commands
# More detailed than PowerShell alone
query session /server:$env:COMPUTERNAME
3. Comprehensive Native Tool Combination
Combine multiple native commands for a complete picture:
# Get detailed session information
$output = cmd /c query user /server:$env:COMPUTERNAME
$sessions = $output | Select-Object -Skip 1 | ForEach-Object {
$parts = $_ -split '\s+'
[PSCustomObject]@{
Username = $parts[1]
SessionName = $parts[2]
ID = $parts[3]
State = $parts[4]
IdleTime = $parts[5]
LogonTime = $parts[6..($parts.Length-1)] -join ' '
}
}
$sessions | Format-Table -AutoSize
Key status indicators in the output:
- Active: Currently in use
- Disc: Disconnected session
- Idle: No input for period shown
- .: Session not initialized
For continuous monitoring, create a PowerShell scheduled task:
# Session monitoring script
while ($true) {
Clear-Host
query user /server:$env:COMPUTERNAME
Start-Sleep -Seconds 10
}
Once you've identified idle/disconnected sessions, manage them natively:
# Log off a specific session
logoff <sessionID> /server:$env:COMPUTERNAME
# Reset a disconnected session
tscon <sessionID> /dest:console