Add Get-UserLastLogonComputer.ps1 - exports users and last PC to CSV

This commit is contained in:
2026-01-30 10:36:30 +11:00
parent 328a6d5e3f
commit 8aef95655e

View File

@@ -0,0 +1,142 @@
#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
}