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 on 2018-07-18
Modified on 2018-11-26
Created by Guy Leech
Downloads: 189

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"
}