<< Back to Script Library

Show recent logoffs

Show user name, logon and logoff times of all users who have logged off, or been logged off, the selected computer(s) in the last x hours where x is an argument defaulting to 48. Useful to be able to spot if many users were logged off at a specific time.
Arguments:
Hours back to search - default is 48
User - optional user name to search for otherwise all users will be displayed
Version: 1.5.7
Created: 2018-07-18
Modified: 2018-11-26
Creator: Guy Leech
Downloads: 180
Tags: citrix logoff parallels ras
The Script Copy Script Copied to clipboard
<#
    Show logoffs from machine, sorted on most recent, from User Profile Service operational event log entries

    @guyrleech 2018
#>


[datetime]$endDate = Get-Date
[int]$totalSessions = 0
[int]$hoursBack = 0
[string]$logName = 'Microsoft-Windows-User Profile Service/Operational'
[string]$user = $null
[int]$daysBefore = 7
[int]$outputWidth = 400

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

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

[datetime]$startDate = if( ! $hoursBack )
{
    $endDate.AddYears( -20 ) ## should be long enough!
}
else
{
    $endDate.AddHours( -$hoursBack )
}

## we look further back so we stand a better chance of finding the corresponding logon
[array]$events = @( Get-WinEvent -FilterHashtable @{ LogName = $logName ; id = 1,4 ; StartTime=(Get-Date $startDate).AddDays( -$daysBefore ) ; EndTime=$endDate } -ErrorAction SilentlyContinue -Oldest ) 

[array]$results = @( For( [int]$index = 0 ; $events -and $index -lt $events.Count ; $index++ )
{
    if( $events[ $index ].Id -eq 4 -and $events[ $index ].TimeCreated -ge $startDate ) ## logoff
    {
        $logoffEvent = $events[ $index ]
        [string]$userName = 
            try
            {
                ([Security.Principal.SecurityIdentifier]($logoffEvent.UserId)).Translate([Security.Principal.NTAccount]).Value
            }
            catch
            {
                ## Write-Error "Failed to get user name for SID $($logonEvent.UserId)"
                $logoffEvent.UserId
            }
        if( [string]::IsNullOrEmpty( $user ) -or $userName -match $user )
        {                
            [int]$sessionId = -1
            if( $logoffEvent.Message -match '(\d+)\.$' ) ## Finished processing user logoff notification on session 2. 
            {
                $sessionId = $Matches[ 1 ]
            }
            if( $sessionId -le 0 )
            {
                Write-Error "Failed to get valid session id from text `"$($logoffEvent.Message)`""
            }

            $logonEvent = $null
            if( $sessionId -gt 0 )
            {
                For( [int]$search = $index + 1 ; $search -ge 0 ; $search-- )
                {
                    if( $events[ $search ].Id -eq 1 -and $events[ $search ].UserId -eq $logoffEvent.UserId )
                    {
                        if( $events[ $search ].Message -match '(\d+)\.$' ) ## Recieved user logon notification on session 2.
                        {
                            [int]$loggedOnSessionId = $Matches[ 1 ]
                            if( $loggedOnSessionId -eq $sessionId )
                            {
                                $logonEvent = $events[ $search ]
                                break
                            }
                        }
                    }
                }
            }
            [pscustomobject][ordered]@{ 'UserName' = $userName ; 'Session Id' = $sessionId ; 'Logon Time' = if( $logonEvent ) { $logonEvent.TimeCreated } ; 'Logoff Time' = $logoffEvent.TimeCreated }
        }
    }
} )

[string]$output = if( $hoursBack )
{
    " in last $hoursBack hours (since $(Get-Date $startDate -Format G))"
}

if( ! [string]::IsNullOrEmpty( $user ) )
{
    $output += " for user $user"
}

if( $results -and $results.Count )
{
    Write-Output ( "$($results.Count) session logoffs found" + $output )

    $results | Sort 'Logoff Time' -Descending | Format-Table -AutoSize
}
else
{
    Write-Output "No logoffs found at all"
}