Private/Core/Test-NewDevice.ps1
|
# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0 # https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/ # AI/LLM use: see AI-USAGE.md for required attribution function Test-NewDevice { [CmdletBinding()] param( [hashtable[]]$LoginEvents = @(), [hashtable]$PreviousDevices = @{} ) $results = [System.Collections.Generic.List[PSCustomObject]]::new() $seenDevices = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) # Load known devices from previous scans foreach ($key in $PreviousDevices.Keys) { [void]$seenDevices.Add($key) } # Sort events chronologically $sorted = @($LoginEvents | Sort-Object { $_.Timestamp }) foreach ($event in $sorted) { # Build device fingerprint from available params $ua = $event.Params['user_agent'] if (-not $ua) { $ua = $event.Params['userAgent'] } $deviceId = $event.Params['device_id'] if (-not $deviceId) { $deviceId = $event.Params['deviceId'] } # Construct a fingerprint $fingerprint = if ($deviceId) { "device:$deviceId" } elseif ($ua) { "ua:$ua" } else { $null } if (-not $fingerprint) { continue } if (-not $seenDevices.Contains($fingerprint)) { [void]$seenDevices.Add($fingerprint) $ipClass = if ($event.IpAddress) { Get-CloudIpClassification -IpAddress $event.IpAddress } else { '' } $isCloudIp = $ipClass -and ($ipClass -eq 'known_attacker' -or $script:CloudProviderClasses.Contains($ipClass)) $results.Add([PSCustomObject]@{ Timestamp = $event.Timestamp IpAddress = $event.IpAddress IpClass = $ipClass IsCloudIp = $isCloudIp DeviceId = $deviceId UserAgent = $ua Fingerprint = $fingerprint EventName = $event.EventName }) } } return @($results) } |