Autumn Baril
Autumn Baril

Reputation: 101

How to read logon events and lookup user information, using Powershell?

How does one read logon and logoff events from the Windows event log, and retrieve the corresponding information for each user from Active Directory, using Powershell?

Upvotes: 3

Views: 9796

Answers (2)

Kevin
Kevin

Reputation: 2929

With Windows 10 professional, a member of Active Directory domain, this script will generate a list of logon / logoff times for the selected user, includes events from screensaver lockscreen. Powershell script to log active work hours, no application needed.

# original source: https://community.spiceworks.com/topic/764481-get-logon-off-workstation-lock-unlock-times 
# cleaned up, filtered by username, and included lock by screensaver timeout by kevin, Dec 2018
# must enable auditing via secpol.msc
# Security Settings -> Advanced Audit Policy -> System Audit -> Logon/Logoff -> Audit Other Logon/Off Events -> On Success

$days = 30
$username = "kevin"

Write-Host "Retrieving last $days days of user: $username, logon/logoff activity... please wait

$events = @()
$events += Get-WinEvent -FilterHashtable @{
    LogName='Security'
    Id=@(4624,4800,4634)
    StartTime=(Get-Date).AddDays(-$days)
}

$type_lu = @{
    4624 = 'Logon'
    4800 = 'Logoff' # screensaver lock
    4634 = 'Logoff' # explicit
}

$ns = @{'ns'='http://schemas.microsoft.com/win/2004/08/events/event'}
$target_xpath = "//ns:Data[@Name='TargetUserName']"
$usersid_xpath = "//ns:Data[@Name='UserSid']"

If($events) {
    $results = ForEach($event in $events) {
        $xml = $event.ToXml()
        Switch -Regex ($event.Id) {
            '4...' {
                $user = (
                    Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath
                ).Node.'#text'
                Break
            }
            '7...' {
                $sid = (
                    Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath
                ).Node.'#text'
                $user = (
                    New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList $sid
                ).Translate([System.Security.Principal.NTAccount]).Value
                Break
            }
        }
        if($username -eq $user) {
            New-Object -TypeName PSObject -Property @{
                Time = $event.TimeCreated
                Id = $event.Id
                Type = $type_lu[$event.Id]
                User = $user
            }
        }
    }

    If($results) {
        $results
    }
}

Example output:

C:\WINDOWS\system32>powershell -file C:\desk\path\timetracker.ps1
Retrieving last 10 days of user: kevin, logon/logoff activity

Time                   User    Id Type
----                   ----    -- ----
12/4/2018 1:39:22 PM   kevin 4634 Logoff
12/4/2018 1:39:19 PM   kevin 4800 Logoff
12/4/2018 1:10:28 PM   kevin 4634 Logoff
12/4/2018 1:10:28 PM   kevin 4624 Logon
12/4/2018 12:57:32 PM  kevin 4634 Logoff
12/4/2018 12:57:32 PM  kevin 4624 Logon
12/4/2018 12:29:43 PM  kevin 4624 Logon
12/4/2018 11:48:11 AM  kevin 4634 Logoff

To debug this script, I opened Event Viewer eventvwr.msc, and used this custom filter (XML).

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[(EventID=4624)] and EventData[Data[@Name='TargetUserName']='kevin']]</Select>
  </Query>
</QueryList>

Powershell also has Get-EventLog cmdlet, but I found it lacking in options.

Upvotes: 0

Autumn Baril
Autumn Baril

Reputation: 101

The following script will read Winlogon events from the System log, retrieve information from AD based on each user's SID, and display the results in a generated HTML page. The results of each AD lookup are cached to prevent unnecessary round-trips to the AD server.

# event id 7001 is Logon, event id 7002 is Logoff
function WinlogonEventIdToString($EventID) {switch($EventID){7001{"Logon";break}7002{"Logoff";break}}}

# look up SID in Active Directory and cache the results in a hashtable
$AdUsers = @{}
function SidToAdUser($sid) {
  $AdUser = $AdUsers[$sid]
  if ($AdUser -eq $null) {
    $AdUser = $AdUsers[$sid] = [adsi]("LDAP://<SID=" + $sid + ">")
  }
  return $AdUser
}

$outputFilename = [System.IO.Path]::GetTempPath() + "DisplayLatestLogonEvents.html"

# the first Select extracts the SID from the event log entry and converts the event id to a descriptive string
# the second Select is responsible for looking up the User object in Active Directory, using the SID
# the final Select picks the various attribute data from the User object, ready for display in the table
# to retrieve only recent log entries, one can use something like this in Get-EventLog: -After (Get-Date).AddDays(-14)
Get-Eventlog -Logname "System" -Source "Microsoft-Windows-Winlogon" -InstanceId 7001,7002 `
  | Select TimeGenerated, @{n='Operation';e={WinlogonEventIdToString $_.EventID}}, @{n='SID';e={$_.ReplacementStrings[1]}} `
  | Select TimeGenerated, Operation, @{n='AdUser';e={(SidToAdUser $_.SID)}} `
  | Select TimeGenerated, Operation, `
           @{n='Username';e={$_.AdUser.sAMAccountName}}, `
           @{n='Full name';e={$_.AdUser.firstname + " " + $_.AdUser.lastname}}, `
           @{n='Title';e={$_.AdUser.title}}, `
           @{n='Department';e={$_.AdUser.department}}, `
           @{n='Company';e={$_.AdUser.company}} `
  | ConvertTo-HTML -Head "<style>td, th { border:1px solid grey }</style>" | Out-File $outputFilename

# this will open the default web browser
Invoke-Expression $outputFilename

Upvotes: 6

Related Questions