Show recently disconnected sessions

Version: 1.6.19
Creator Name: Guy Leech
Date Created: 2018-07-18
Date Modified: 2018-11-21
Scripting language: PS
Download Count: 65

Use quser.exe to find disconnected sessions on the chosen computer and order on the most recently disconnected, showing the user's logon time too. Arguments: Hours Back to Check - how far back to look for disconnected sessions so those disconnected before this time will not be included (default is 24 hours)
Tags: RDS,Sessions,Disconnected sessions,Citrix,XenApp

The Script

<#
    Show disconnected sessions sorted on how recently disconnected by parsing quser.exe output

    Guy Leech, 2018

    Modification History

    20/11/18   GRL Added logon time
#>

[datetime]$timeNow = Get-Date
[int]$totalSessions = 0
[int]$hoursBack = 0
[int]$totalDisconnected = 0
[int]$outputWidth = 400

if( $args.Count -and ! [string]::IsNullOrEmpty( $args[0] ) )
{
    $hoursBack = $args[0]
}

# Altering the size of the PS Buffer
$PSWindow = (Get-Host).UI.RawUI
$WideDimensions = $PSWindow.BufferSize
$WideDimensions.Width = $outputWidth
$PSWindow.BufferSize = $WideDimensions

[array]$disconnectedUsers = @( (quser.exe | select -Skip 1).Trim() | ForEach-Object `
{
    $totalSessions++
    [string[]]$fields = $_ -split '\s+'

    ## Headings are:  USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME

    ## if logon time has AM/PM indicator as opposed to 24 hour then there will be one more field
    [int]$disconnectedFieldCount = if( $_ -match '\s[AP]M$' ) { 7 } else { 6 }

    if( $fields -and $fields.Count -eq $disconnectedFieldCount ) ## for disconnected session there is no SESSIONNAME so field count is reduced by one (so is 7 for active sessions). Do not check for 'Disc' as may be different in non-English
    {
        $totalDisconnected++

        [int]$disconnectedDurationMinutes = `
            if( $fields[3] -match '^(\d+)\+(\d+):(\d+)$' ) ## 33+22:16
            {
                ( [int]$Matches[1] * 24 + [int]$Matches[ 2 ] ) * 60 + [int]$Matches[ 3 ]
            }
            elseif( $fields[3] -match '^(\d+):(\d+)$' ) ## 19:35
            {
                [int]$Matches[1] * 60 + [int]$Matches[ 2 ]
            }
            else
            {
                [int]$fields[3]
            }

        if( ! $hoursBack -or $disconnectedDurationMinutes -le $hoursBack * 60 )
        {
            [pscustomobject]@{ 
                'Username' = $fields[0]
                'Logon Time' = if( $disconnectedFieldCount -eq 7 ) { ( '{0} {1} {2}' -f $fields[-3] , $fields[-2] , $fields[-1] ) } else { ( '{0} {1}' -f $fields[-2] , $fields[-1] ) }
                'Disconnection Time' = Get-Date ( $timeNow.AddMinutes( -$disconnectedDurationMinutes ) ) -Format G
                'Disconnected Hours' = [math]::Round( $disconnectedDurationMinutes / 60 , 1 ) 
                'Disconnected Minutes' = $disconnectedDurationMinutes }
        }
    }
} )

[string]$output = if( $hoursBack )
{
    " in last $hoursBack hours ($totalDisconnected disconnected in total)"
}

if( $disconnectedUsers -and $disconnectedUsers.Count )
{
    Write-Output ( "$($disconnectedUsers.Count) out of $totalSessions sessions ($([math]::Round( ( $disconnectedUsers.Count / $totalSessions ) * 100 ))%) are disconnected" + $output )

    $disconnectedUsers | Sort 'Disconnected Minutes' | Format-Table -AutoSize
}
elseif( $totalSessions )
{
    Write-Output ( "No disconnected sessions found out of $totalSessions sessions" + $output )
}
else
{
    Write-Output "No sessions found at all"
}