#Requires -Modules ActiveDirectory <# .SYNOPSIS Exports a list of users and the last PC they logged into. .DESCRIPTION Queries Domain Controller security event logs for interactive logon events (4624) to determine which computer each user last authenticated from. .PARAMETER OutputPath Path for the output CSV file. Defaults to current directory. .PARAMETER DaysBack Number of days of event logs to search. Default is 7. .PARAMETER LogonTypes Array of logon types to include. Default is 2 (Interactive) and 10 (RemoteInteractive/RDP). .EXAMPLE .\Get-UserLastLogonComputer.ps1 .EXAMPLE .\Get-UserLastLogonComputer.ps1 -OutputPath "C:\Reports" -DaysBack 30 .NOTES Must be run on a Domain Controller with appropriate permissions to read Security logs. Logon Type 2 = Interactive (console) Logon Type 10 = RemoteInteractive (RDP) Logon Type 11 = CachedInteractive #> [CmdletBinding()] param( [Parameter()] [string]$OutputPath = (Get-Location).Path, [Parameter()] [int]$DaysBack = 7, [Parameter()] [int[]]$LogonTypes = @(2, 10, 11) ) $Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $CsvFile = Join-Path $OutputPath "UserLastLogonComputer_$Timestamp.csv" Write-Host "`nQuerying security event logs for the last $DaysBack days..." -ForegroundColor Cyan Write-Host "Looking for logon types: $($LogonTypes -join ', ')" -ForegroundColor Cyan Write-Host "" $StartDate = (Get-Date).AddDays(-$DaysBack) # Build XPath filter for Event ID 4624 (Successful Logon) $LogonTypeFilter = ($LogonTypes | ForEach-Object { "Data[@Name='LogonType']=$_" }) -join " or " $XPath = @" *[System[ EventID=4624 and TimeCreated[@SystemTime >= '$($StartDate.ToUniversalTime().ToString("o"))'] ] and EventData[ ($LogonTypeFilter) ] ] "@ try { Write-Host "Retrieving logon events from Security log..." -ForegroundColor Yellow $Events = Get-WinEvent -LogName Security -FilterXPath $XPath -ErrorAction Stop | Where-Object { $xml = [xml]$_.ToXml() $targetUser = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text' $targetDomain = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text' # Filter out computer accounts and system accounts $targetUser -notmatch '\$$' -and $targetUser -notin @('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE', 'DWM-1', 'DWM-2', 'UMFD-0', 'UMFD-1') -and $targetDomain -ne 'Window Manager' -and $targetDomain -ne 'Font Driver Host' } Write-Host "Found $($Events.Count) logon events. Processing..." -ForegroundColor Yellow $UserLogons = @{} foreach ($Event in $Events) { $xml = [xml]$Event.ToXml() $Username = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text' $Domain = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text' $Workstation = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' }).'#text' $LogonType = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'LogonType' }).'#text' $LogonTime = $Event.TimeCreated if ([string]::IsNullOrWhiteSpace($Workstation)) { $Workstation = "Unknown" } $UserKey = "$Domain\$Username" # Keep only the most recent logon for each user if (-not $UserLogons.ContainsKey($UserKey) -or $LogonTime -gt $UserLogons[$UserKey].LogonTime) { $UserLogons[$UserKey] = [PSCustomObject]@{ Domain = $Domain Username = $Username Computer = $Workstation.ToUpper() LogonTime = $LogonTime LogonType = switch ($LogonType) { 2 { "Interactive" } 10 { "RDP" } 11 { "Cached" } default { $LogonType } } } } } $Results = $UserLogons.Values | Sort-Object Domain, Username if ($Results.Count -eq 0) { Write-Host "`nNo user logon events found in the specified time period." -ForegroundColor Yellow return } # Export to CSV $Results | Select-Object Domain, Username, Computer, LogonTime, LogonType | Export-Csv -Path $CsvFile -NoTypeInformation -Encoding UTF8 Write-Host "`n===== Results =====" -ForegroundColor Green Write-Host "Total users found: $($Results.Count)" Write-Host "Output saved to: $CsvFile" Write-Host "" # Display summary table $Results | Format-Table -AutoSize } catch [System.Diagnostics.Eventing.Reader.EventLogNotFoundException] { Write-Host "`nError: Security event log not accessible. Ensure you're running on a DC with appropriate permissions." -ForegroundColor Red } catch [System.UnauthorizedAccessException] { Write-Host "`nError: Access denied. Run as Administrator with permissions to read Security logs." -ForegroundColor Red } catch { Write-Host "`nError: $($_.Exception.Message)" -ForegroundColor Red }