Most of this script comes from AdamTheAutomator’s website, but I did make some improvements for my own needs that included a custom class and some adjustments to the PowerShell object. I have plans to modify this further so I can use it for larger automation activities.
class eventLogObject{ [string]$AccountName [string]$DomainName [string]$LogonID [string]$SessionName [string]$ClientName [string]$ClientAddress [string]$EventID [string]$EventDescription [string]$TimeStamp } function Get-ActivityLog { <# .SYNOPSIS This script finds all PowerShell last logon, logoff and total active session times of all users on all computers specified. For this script to function as expected, the advanced AD policies; Audit Logon, Audit Logoff and Audit Other Logon/Logoff Events must be enabled and targeted to the appropriate computers via GPO or local policy. .EXAMPLE .PARAMETER ComputerName An array of computer names to search for events on. If this is not provided, the script will search the local computer. .INPUTS None. You cannot pipe objects to Get-ActiveDirectoryUserActivity.ps1. .OUTPUTS None. If successful, this script does not output anything. #> [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string[]]$ComputerName = $Env:COMPUTERNAME ) try { #region Defie all of the events to indicate session start or top $sessionEvents = @( @{ 'Label' = 'Logon'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4624 } ## Advanced Audit Policy --> Audit Logon @{ 'Label' = 'Logoff'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4647 } ## Advanced Audit Policy --> Audit Logoff @{ 'Label' = 'Startup'; 'EventType' = 'SessionStop'; 'LogName' = 'System'; 'ID' = 6005 } @{ 'Label' = 'RdpSessionReconnect'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4778 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events @{ 'Label' = 'RdpSessionDisconnect'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4779 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events @{ 'Label' = 'Locked'; 'EventType' = 'SessionStop'; 'LogName' = 'Security'; 'ID' = 4800 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events @{ 'Label' = 'Unlocked'; 'EventType' = 'SessionStart'; 'LogName' = 'Security'; 'ID' = 4801 } ## Advanced Audit Policy --> Audit Other Logon/Logoff Events ) ## All of the IDs that designate when user activity starts $sessionStartIds = ($sessionEvents | where { $_.EventType -eq 'SessionStart' }).ID ## All of the IDs that designate when user activity stops $sessionStopIds = ($sessionEvents | where { $_.EventType -eq 'SessionStop' }).ID #endregion ## Define all of the log names we'll be querying $logNames = ($sessionEvents.LogName | select -Unique) ## Grab all of the interesting IDs we'll be looking for $ids = $sessionEvents.Id ## Build the insane XPath query for the security event log in order to query PowerShell last logon events and others as fast as possible $logonXPath = "Event[System[EventID=4624]] and Event[EventData[Data[@Name='TargetDomainName'] != 'Window Manager']] and Event[EventData[Data[@Name='TargetDomainName'] != 'NT AUTHORITY']] and (Event[EventData[Data[@Name='LogonType'] = '2']] or Event[EventData[Data[@Name='LogonType'] = '10']])" $otherXpath = 'Event[System[({0})]]' -f "EventID=$(($ids.where({ $_ -ne '4624' })) -join ' or EventID=')" $xPath = '({0}) or ({1})' -f $logonXPath, $otherXpath foreach ($computer in $ComputerName) { ## Query each computer's event logs using the Xpath filter $events = Get-WinEvent -ComputerName $computer -LogName $logNames -FilterXPath $xPath Write-Verbose -Message "Found [$($events.Count)] events to look through" ## Set up the output object $output = [ordered]@{ 'ComputerName' = $computer 'Username' = $null 'StartTime' = $null 'StartAction' = $null 'StopTime' = $null 'StopAction' = $null 'Session Active (Days)' = $null 'Session Active (Min)' = $null } ## Need current users because if no stop time, they're still probably logged in $getGimInstanceParams = @{ ClassName = 'Win32_ComputerSystem' } if ($computer -ne $Env:COMPUTERNAME) { $getGimInstanceParams.ComputerName = $computer } $loggedInUsers = Get-CimInstance @getGimInstanceParams | Select-Object -ExpandProperty UserName | foreach { $_.split('\')[1] } $eventLogObject = New-Object System.Collections.ArrayList($null) Foreach ($event in $events) { $xmlEvent = [xml]$event.ToXml() #$xmlevent.event.eventdata.data If (($event.ID -eq '4778') -or ($event.ID -eq '4779')) { $eventObject = New-Object eventLogObject $eventObject.AccountName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "AccountName"}).'#text' $eventObject.DomainName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "AccountDomain"}).'#text' $eventObject.LogonID = ($xmlevent.event.eventdata.data | where { $_.Name -eq "LogonID"}).'#text' $eventObject.SessionName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "SessionName"}).'#text' $eventObject.ClientName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "ClientName"}).'#text' $eventObject.ClientAddress = ($xmlevent.event.eventdata.data | where { $_.Name -eq "ClientAddress"}).'#text' $eventObject.EventID = $event.ID $eventObject.EventDescription = $sessionEvents.Where({ $_.ID -eq $event.ID}).Label $eventObject.TimeStamp = $event.TimeCreated $eventLogObject.Add($eventObject) } else { $eventObject = New-Object eventLogObject $eventObject.AccountName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "TargetUserName"}).'#text' $eventObject.DomainName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "TargetDomainName"}).'#text' $eventObject.LogonID = ($xmlevent.event.eventdata.data | where { $_.Name -eq "TargetLogonId"}).'#text' $eventObject.SessionName = ($xmlevent.event.eventdata.data | where { $_.Name -eq "SessionId"}).'#text' $eventObject.ClientName = 'na' $eventObject.ClientAddress = 'na' $eventObject.EventID = $event.ID $eventObject.EventDescription = $sessionEvents.Where({ $_.ID -eq $event.ID}).Label $eventLogObject.Add($eventObject) $eventObject.TimeStamp = $event.TimeCreated } } #return $eventLogObject } } catch { $PSCmdlet.ThrowTerminatingError($_) } } Get-ActivityLog | Format-Table