#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) try { Write-Host "Retrieving logon events from Security log..." -ForegroundColor Yellow # Use hashtable filter - more reliable than XPath for date filtering $FilterHash = @{ LogName = 'Security' ID = 4624 StartTime = $StartDate } $Events = Get-WinEvent -FilterHashtable $FilterHash -ErrorAction Stop Write-Host "Found $($Events.Count) total 4624 events. Filtering..." -ForegroundColor Yellow $UserLogons = @{} $ProcessedCount = 0 foreach ($Event in $Events) { $xml = [xml]$Event.ToXml() $LogonType = [int]($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'LogonType' }).'#text' # Skip if not a logon type we want if ($LogonType -notin $LogonTypes) { continue } $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' $LogonTime = $Event.TimeCreated # Filter out computer accounts and system accounts if ($Username -match '\$$') { continue } if ($Username -in @('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE', 'DWM-1', 'DWM-2', 'DWM-3', 'UMFD-0', 'UMFD-1', 'UMFD-2', 'ANONYMOUS LOGON', '-')) { continue } if ($Domain -in @('Window Manager', 'Font Driver Host', 'NT AUTHORITY')) { continue } if ([string]::IsNullOrWhiteSpace($Username)) { continue } if ([string]::IsNullOrWhiteSpace($Workstation)) { $Workstation = "Unknown" } $UserKey = "$Domain\$Username" $ProcessedCount++ # 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 { "Type $LogonType" } } } } } Write-Host "Processed $ProcessedCount matching logon events." -ForegroundColor Yellow $Results = $UserLogons.Values | Sort-Object Domain, Username if ($Results.Count -eq 0) { Write-Host "`nNo user logon events found matching criteria." -ForegroundColor Yellow Write-Host "This could mean:" Write-Host " - No interactive/RDP logons in the last $DaysBack days" Write-Host " - Audit policy may not be logging logon events" Write-Host " - Try increasing -DaysBack value" 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.Exception] { if ($_.Exception.Message -match "No events were found") { Write-Host "`nNo logon events (Event ID 4624) found in the last $DaysBack days." -ForegroundColor Yellow Write-Host "`nPossible causes:" -ForegroundColor Cyan Write-Host " 1. Audit policy not enabled - Run: auditpol /get /category:`"Logon/Logoff`"" Write-Host " 2. Security log was cleared recently" Write-Host " 3. Try a larger -DaysBack value" Write-Host "" Write-Host "To enable logon auditing:" -ForegroundColor Cyan Write-Host " auditpol /set /subcategory:`"Logon`" /success:enable" } elseif ($_.Exception.Message -match "Access is denied") { Write-Host "`nError: Access denied. Run PowerShell as Administrator." -ForegroundColor Red } else { Write-Host "`nError: $($_.Exception.Message)" -ForegroundColor Red } }