Include Type 3 network logons, resolve IP to hostname

This commit is contained in:
2026-01-30 11:24:56 +11:00
parent 5a76c44bda
commit 38168181ca

View File

@@ -4,8 +4,9 @@
Exports a list of users and the last PC they logged into. Exports a list of users and the last PC they logged into.
.DESCRIPTION .DESCRIPTION
Queries Domain Controller security event logs for interactive logon events (4624) Queries Domain Controller security event logs for logon events (4624)
to determine which computer each user last authenticated from. to determine which computer each user last authenticated from.
Resolves IP addresses to computer names for network logons.
.PARAMETER OutputPath .PARAMETER OutputPath
Path for the output CSV file. Defaults to current directory. Path for the output CSV file. Defaults to current directory.
@@ -13,8 +14,11 @@
.PARAMETER DaysBack .PARAMETER DaysBack
Number of days of event logs to search. Default is 7. Number of days of event logs to search. Default is 7.
.PARAMETER LogonTypes .PARAMETER IncludeNetworkLogons
Array of logon types to include. Default is 2 (Interactive) and 10 (RemoteInteractive/RDP). Include Type 3 (Network) logons. Default is true.
.PARAMETER ResolveIPs
Attempt to resolve IP addresses to hostnames. Default is true.
.EXAMPLE .EXAMPLE
.\Get-UserLastLogonComputer.ps1 .\Get-UserLastLogonComputer.ps1
@@ -25,6 +29,7 @@
.NOTES .NOTES
Must be run on a Domain Controller with appropriate permissions to read Security logs. Must be run on a Domain Controller with appropriate permissions to read Security logs.
Logon Type 2 = Interactive (console) Logon Type 2 = Interactive (console)
Logon Type 3 = Network (file shares, etc.)
Logon Type 10 = RemoteInteractive (RDP) Logon Type 10 = RemoteInteractive (RDP)
Logon Type 11 = CachedInteractive Logon Type 11 = CachedInteractive
#> #>
@@ -38,9 +43,18 @@ param(
[int]$DaysBack = 7, [int]$DaysBack = 7,
[Parameter()] [Parameter()]
[int[]]$LogonTypes = @(2, 10, 11) [switch]$ExcludeNetworkLogons,
[Parameter()]
[switch]$SkipIPResolve
) )
# Build logon types list
$LogonTypes = @(2, 10, 11) # Interactive, RDP, Cached
if (-not $ExcludeNetworkLogons) {
$LogonTypes += 3 # Network
}
$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$CsvFile = Join-Path $OutputPath "UserLastLogonComputer_$Timestamp.csv" $CsvFile = Join-Path $OutputPath "UserLastLogonComputer_$Timestamp.csv"
@@ -50,10 +64,46 @@ Write-Host ""
$StartDate = (Get-Date).AddDays(-$DaysBack) $StartDate = (Get-Date).AddDays(-$DaysBack)
# Cache for IP to hostname resolution
$IPCache = @{}
function Resolve-IPToHostname {
param([string]$IP)
if ([string]::IsNullOrWhiteSpace($IP) -or $IP -eq '-' -or $IP -eq '::1' -or $IP -eq '127.0.0.1') {
return $null
}
# Check cache first
if ($IPCache.ContainsKey($IP)) {
return $IPCache[$IP]
}
try {
# Try DNS reverse lookup
$hostname = [System.Net.Dns]::GetHostEntry($IP).HostName
# Extract just the computer name (before the domain)
$computerName = ($hostname -split '\.')[0].ToUpper()
$IPCache[$IP] = $computerName
return $computerName
} catch {
# Try querying AD for the IP
try {
$computer = Get-ADComputer -Filter "IPv4Address -eq '$IP'" -Properties Name -ErrorAction SilentlyContinue
if ($computer) {
$IPCache[$IP] = $computer.Name
return $computer.Name
}
} catch {}
$IPCache[$IP] = $null
return $null
}
}
try { try {
Write-Host "Retrieving logon events from Security log..." -ForegroundColor Yellow Write-Host "Retrieving logon events from Security log..." -ForegroundColor Yellow
# Use hashtable filter - more reliable than XPath for date filtering
$FilterHash = @{ $FilterHash = @{
LogName = 'Security' LogName = 'Security'
ID = 4624 ID = 4624
@@ -66,8 +116,14 @@ try {
$UserLogons = @{} $UserLogons = @{}
$ProcessedCount = 0 $ProcessedCount = 0
$i = 0
foreach ($Event in $Events) { foreach ($Event in $Events) {
$i++
if ($i % 5000 -eq 0) {
Write-Host " Processing event $i of $($Events.Count)..." -ForegroundColor Gray
}
$xml = [xml]$Event.ToXml() $xml = [xml]$Event.ToXml()
$LogonType = [int]($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'LogonType' }).'#text' $LogonType = [int]($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'LogonType' }).'#text'
@@ -78,16 +134,30 @@ try {
$Username = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text' $Username = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
$Domain = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text' $Domain = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TargetDomainName' }).'#text'
$Workstation = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' }).'#text' $Workstation = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' }).'#text'
$IPAddress = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'IpAddress' }).'#text'
$LogonTime = $Event.TimeCreated $LogonTime = $Event.TimeCreated
# Filter out computer accounts and system accounts # Filter out computer accounts and system accounts
if ($Username -match '\$$') { continue } 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 ($Username -in @('SYSTEM', 'LOCAL SERVICE', 'NETWORK SERVICE', 'DWM-1', 'DWM-2', 'DWM-3', 'DWM-4', 'UMFD-0', 'UMFD-1', 'UMFD-2', 'UMFD-3', 'ANONYMOUS LOGON', '-')) { continue }
if ($Domain -in @('Window Manager', 'Font Driver Host', 'NT AUTHORITY')) { continue } if ($Domain -in @('Window Manager', 'Font Driver Host', 'NT AUTHORITY')) { continue }
if ([string]::IsNullOrWhiteSpace($Username)) { continue } if ([string]::IsNullOrWhiteSpace($Username)) { continue }
if ([string]::IsNullOrWhiteSpace($Workstation)) { # Determine computer name - try WorkstationName first, then resolve IP
$Workstation = "Unknown" $Computer = $null
if (-not [string]::IsNullOrWhiteSpace($Workstation) -and $Workstation -ne '-') {
$Computer = $Workstation.ToUpper()
} elseif (-not $SkipIPResolve -and -not [string]::IsNullOrWhiteSpace($IPAddress)) {
$Computer = Resolve-IPToHostname -IP $IPAddress
}
if ([string]::IsNullOrWhiteSpace($Computer)) {
# Store IP if we couldn't resolve
if (-not [string]::IsNullOrWhiteSpace($IPAddress) -and $IPAddress -ne '-') {
$Computer = "[$IPAddress]"
} else {
$Computer = "Unknown"
}
} }
$UserKey = "$Domain\$Username" $UserKey = "$Domain\$Username"
@@ -98,10 +168,12 @@ try {
$UserLogons[$UserKey] = [PSCustomObject]@{ $UserLogons[$UserKey] = [PSCustomObject]@{
Domain = $Domain Domain = $Domain
Username = $Username Username = $Username
Computer = $Workstation.ToUpper() Computer = $Computer
IPAddress = if ($IPAddress -and $IPAddress -ne '-') { $IPAddress } else { '' }
LogonTime = $LogonTime LogonTime = $LogonTime
LogonType = switch ($LogonType) { LogonType = switch ($LogonType) {
2 { "Interactive" } 2 { "Interactive" }
3 { "Network" }
10 { "RDP" } 10 { "RDP" }
11 { "Cached" } 11 { "Cached" }
default { "Type $LogonType" } default { "Type $LogonType" }
@@ -116,15 +188,11 @@ try {
if ($Results.Count -eq 0) { if ($Results.Count -eq 0) {
Write-Host "`nNo user logon events found matching criteria." -ForegroundColor Yellow 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 return
} }
# Export to CSV # Export to CSV
$Results | Select-Object Domain, Username, Computer, LogonTime, LogonType | $Results | Select-Object Domain, Username, Computer, IPAddress, LogonTime, LogonType |
Export-Csv -Path $CsvFile -NoTypeInformation -Encoding UTF8 Export-Csv -Path $CsvFile -NoTypeInformation -Encoding UTF8
Write-Host "`n===== Results =====" -ForegroundColor Green Write-Host "`n===== Results =====" -ForegroundColor Green
@@ -133,18 +201,11 @@ try {
Write-Host "" Write-Host ""
# Display summary table # Display summary table
$Results | Format-Table -AutoSize $Results | Format-Table Domain, Username, Computer, LogonTime, LogonType -AutoSize
} catch [System.Exception] { } catch [System.Exception] {
if ($_.Exception.Message -match "No events were found") { 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 "`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") { } elseif ($_.Exception.Message -match "Access is denied") {
Write-Host "`nError: Access denied. Run PowerShell as Administrator." -ForegroundColor Red Write-Host "`nError: Access denied. Run PowerShell as Administrator." -ForegroundColor Red
} else { } else {