Private/Core/Test-UserAgentAnomaly.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-UserAgentAnomaly {
    [CmdletBinding()]
    param(
        [hashtable[]]$LoginEvents = @()
    )

    $results = [System.Collections.Generic.List[PSCustomObject]]::new()

    # Known suspicious user agent patterns
    $suspiciousPatterns = @(
        @{ Pattern = 'HeadlessChrome';    Label = 'Headless Chrome' }
        @{ Pattern = 'PhantomJS';         Label = 'PhantomJS (headless)' }
        @{ Pattern = 'python-requests';   Label = 'Python requests library' }
        @{ Pattern = 'python-urllib';     Label = 'Python urllib' }
        @{ Pattern = 'curl/';            Label = 'curl' }
        @{ Pattern = 'wget/';            Label = 'wget' }
        @{ Pattern = 'Go-http-client';   Label = 'Go HTTP client' }
        @{ Pattern = 'node-fetch';       Label = 'Node.js fetch' }
        @{ Pattern = 'axios/';           Label = 'Axios HTTP client' }
        @{ Pattern = 'Selenium';         Label = 'Selenium automation' }
        @{ Pattern = 'Puppeteer';        Label = 'Puppeteer automation' }
        @{ Pattern = 'Playwright';       Label = 'Playwright automation' }
        @{ Pattern = 'scrapy';           Label = 'Scrapy crawler' }
        @{ Pattern = 'httpclient';       Label = 'Generic HTTP client' }
        @{ Pattern = 'java/';            Label = 'Java HTTP client' }
        @{ Pattern = 'Apache-HttpClient'; Label = 'Apache HttpClient' }
        @{ Pattern = 'okhttp';           Label = 'OkHttp client' }
        @{ Pattern = 'libwww-perl';      Label = 'Perl LWP' }
        @{ Pattern = 'mechanize';        Label = 'Mechanize automation' }
    )

    foreach ($event in $LoginEvents) {
        $ua = $event.Params['user_agent']
        if (-not $ua) {
            $ua = $event.Params['userAgent']
        }
        if (-not $ua) { continue }

        foreach ($sp in $suspiciousPatterns) {
            if ($ua -match [regex]::Escape($sp.Pattern)) {
                $results.Add([PSCustomObject]@{
                    Timestamp  = $event.Timestamp
                    IpAddress  = $event.IpAddress
                    UserAgent  = $ua
                    MatchLabel = $sp.Label
                    EventName  = $event.EventName
                })
                break
            }
        }
    }

    return @($results)
}