Public/OS/Get-UserSession.ps1
|
FUNCTION Get-UserSession { [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string[]]$ComputerName = $env:COMPUTERNAME ) $Sessions = @() foreach ($computer in $ComputerName) { Write-Verbose "Querying $computer..." try { $quserOutput = quser /server:$computer 2>$null if (!$quserOutput) { Write-Verbose "No sessions or quser failed on $computer" continue } # Skip header line $lines = $quserOutput | Select-Object -Skip 1 foreach ($line in $lines) { # Clean > symbol for current session and collapse multiple spaces $cleanLine = $line -replace '^\s*>', '' -replace '\s{2,}', ' ' # Split into tokens $tokens = $cleanLine.Trim() -split '\s+' # Handle two formats: # Active/connected: Username SessionName ID State IdleTime LogonTime... # Disconnected: Username ID State IdleTime LogonTime... if ($tokens.Count -ge 5) { $idx = 0 $session = [PSCustomObject]@{ UserName = $tokens[$idx++].Trim() SessionName = $null ID = $null State = $null IdleTime = $null LogonTime = $null } # If second token looks like session name (contains letters or #) IF ($tokens[2] -eq "Disc") { } ELSEIF ($tokens[$idx] -match 'rdp-tcp|console|#|\w') { $session.SessionName = $tokens[$idx++] } $session.ID = $tokens[$idx++] $session.State = $tokens[$idx++] # Idle time is next $idleRaw = $tokens[$idx++] # Remaining tokens are logon time (may contain spaces) $session.LogonTime = ($tokens[$idx..($tokens.Count-1)]) -join ' ' if ($idleRaw -eq 'none' -or $idleRaw -eq '.') { $session.IdleTime = $null } elseif ($idleRaw -match '^(\d+)$') { # Just minutes $session.IdleTime = [TimeSpan]::FromMinutes([int]$Matches[1]) } elseif ($idleRaw -match '^(\d+):(\d+)$') { # hours:minutes $session.IdleTime = [TimeSpan]::FromHours([int]$Matches[1]) + [TimeSpan]::FromMinutes([int]$Matches[2]) } elseif ($idleRaw -match '^(\d+)\+(\d+):(\d+)$') { # days+hours:minutes $session.IdleTime = [TimeSpan]::FromDays([int]$Matches[1]) + [TimeSpan]::FromHours([int]$Matches[2]) + [TimeSpan]::FromMinutes([int]$Matches[3]) } else { # Fallback - try to interpret as minutes if ([int]::TryParse($idleRaw, [ref]$null)) { $session.IdleTime = [TimeSpan]::FromMinutes([int]$idleRaw) } else { $session.IdleTime = $null Write-Verbose "Could not parse idle time: $idleRaw for $($session.UserName)" } } $Sessions += $session } } } catch { Write-Verbose "Error querying $computer : $_" } } RETURN $Sessions | Sort-Object -Property State, IdleTime, UserName } |