Public/Invoke-ReconDemo.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 Invoke-ReconDemo { [CmdletBinding()] param( [string]$OutputPath, [switch]$NoOpen ) if (-not $OutputPath) { $outDir = Join-Path (Get-PSGuerrillaDataRoot) 'Reports' if (-not (Test-Path $outDir)) { New-Item -Path $outDir -ItemType Directory -Force | Out-Null } $OutputPath = Join-Path $outDir "demo_field_report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html" } Write-GuerrillaText 'Generating demo field report...' -Color Olive # --- Mock data --- $now = [datetime]::UtcNow # Helper to build a mock enriched event $mockEvent = { param([string]$User, [string]$EventName, [string]$Ip, [string]$IpClass, [string]$Country, [datetime]$Time, [string]$Source, [hashtable]$Params) [PSCustomObject]@{ Timestamp = $Time User = $User EventName = $EventName IpAddress = $Ip IpClass = $IpClass GeoCountry = $Country Source = $Source ?? 'login' Params = $Params ?? @{} } } $profiles = @() # ============================================================ # USER 1: CRITICAL — known attacker IP + impossible travel + brute force success # ============================================================ $u1Events = @( (& $mockEvent 'sarah.chen@acme.com' 'login_success' '185.220.101.42' 'known_attacker' 'DE' ($now.AddHours(-6)) 'login' @{ login_type = 'exchange' }) (& $mockEvent 'sarah.chen@acme.com' 'login_success' '3.236.48.201' 'aws' 'US' ($now.AddHours(-4)) 'login' @{ login_type = 'reauth' }) (& $mockEvent 'sarah.chen@acme.com' 'risky_sensitive_action_allowed' '3.236.48.201' 'aws' 'US' ($now.AddHours(-3.5)) 'login' @{}) ) $u1 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'sarah.chen@acme.com' ThreatLevel = 'CRITICAL' ThreatScore = 260.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @( 'KNOWN ATTACKER IP - 1 login(s) from 1 known attacker IP(s): 185.220.101.42' 'IMPOSSIBLE TRAVEL - 1 instance(s), e.g. DE to US (6,379 km in 0.5h)' 'REAUTH FROM CLOUD - 1 reauth login(s) from cloud provider IPs (matches attack pattern)' 'BRUTE FORCE SUCCESS - 7 failures followed by successful login from 2 IP(s)' 'RISKY ACTION FROM CLOUD IP - 1 risky sensitive action(s) from cloud/hosting IPs' ) KnownAttackerIpLogins = @( (& $mockEvent 'sarah.chen@acme.com' 'login_success' '185.220.101.42' 'known_attacker' 'DE' ($now.AddHours(-6)) 'login' @{ login_type = 'exchange' }) ) CloudIpLogins = @( (& $mockEvent 'sarah.chen@acme.com' 'login_success' '3.236.48.201' 'aws' 'US' ($now.AddHours(-4)) 'login' @{ login_type = 'reauth' }) ) ReauthFromCloud = @( (& $mockEvent 'sarah.chen@acme.com' 'login_success' '3.236.48.201' 'aws' 'US' ($now.AddHours(-4)) 'login' @{ login_type = 'reauth' }) ) RiskyActions = @( (& $mockEvent 'sarah.chen@acme.com' 'risky_sensitive_action_allowed' '3.236.48.201' 'aws' 'US' ($now.AddHours(-3.5)) 'login' @{}) ) SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @() ImpossibleTravel = @( [PSCustomObject]@{ FromIp = '185.220.101.42'; ToIp = '3.236.48.201' FromCountry = 'DE'; ToCountry = 'US' FromTime = $now.AddHours(-6); ToTime = $now.AddHours(-5.5) DistanceKm = 6379; TimeDiffHours = 0.5; RequiredSpeedKmh = 12758 } ) ConcurrentSessions = @() UserAgentAnomalies = @() BruteForce = [PSCustomObject]@{ Detected = $true; FailureCount = 7; SuccessAfter = $true AttackingIps = @('185.220.101.42', '45.33.32.156') FailureWindow = [PSCustomObject]@{ Start = $now.AddHours(-6.5); End = $now.AddHours(-6.1) Duration = [TimeSpan]::FromMinutes(24) } SuccessEvent = [PSCustomObject]@{ Timestamp = $now.AddHours(-6); IpAddress = '185.220.101.42' } } AfterHoursLogins = @( [PSCustomObject]@{ Timestamp = $now.AddHours(-6); LocalTime = $now.AddHours(-6) IpAddress = '185.220.101.42'; EventName = 'login_success' DayOfWeek = 'Wednesday'; LocalHour = 3; Timezone = 'UTC' Reason = 'Outside business hours (03:00 local, business hours 7:00-19:00)' } ) NewDevices = @( [PSCustomObject]@{ Timestamp = $now.AddHours(-6); IpAddress = '185.220.101.42' IpClass = 'known_attacker'; IsCloudIp = $true DeviceId = $null; UserAgent = 'python-requests/2.31.0' Fingerprint = 'ua:python-requests/2.31.0'; EventName = 'login_success' } ) IpClassifications = @{ '185.220.101.42' = @{ Class = 'known_attacker'; Country = 'DE'; Events = @('login_success') } '3.236.48.201' = @{ Class = 'aws'; Country = 'US'; Events = @('login_success', 'risky_sensitive_action_allowed') } '98.137.246.8' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success') } } TotalLoginEvents = 14 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u1 # ============================================================ # USER 2: CRITICAL — confirmed compromised, reauth from Azure, OAuth grant # ============================================================ $u2 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'james.rodriguez@acme.com' ThreatLevel = 'CRITICAL' ThreatScore = 185.0 IsKnownCompromised = $true WasRemediated = $true Indicators = @( 'CONFIRMED COMPROMISED (known victim)' 'REAUTH FROM CLOUD - 3 reauth login(s) from cloud provider IPs (matches attack pattern)' 'OAUTH FROM CLOUD IP - 2 OAuth grant(s) from cloud IPs: MailDaemon, CloudSync Pro' 'CONCURRENT SESSIONS - 2 window(s) with multiple IPs (max 3 IPs simultaneously)' 'SUSPICIOUS COUNTRY LOGIN - 1 login(s) from Russia (RU)' ) KnownAttackerIpLogins = @() CloudIpLogins = @( (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '20.42.128.97' 'azure' 'US' ($now.AddDays(-2)) 'login' @{ login_type = 'reauth' }) (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '20.42.128.97' 'azure' 'US' ($now.AddDays(-1.5)) 'login' @{ login_type = 'reauth' }) (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '35.198.42.6' 'gcp' 'NL' ($now.AddDays(-1)) 'login' @{ login_type = 'reauth' }) ) ReauthFromCloud = @( (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '20.42.128.97' 'azure' 'US' ($now.AddDays(-2)) 'login' @{ login_type = 'reauth' }) (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '20.42.128.97' 'azure' 'US' ($now.AddDays(-1.5)) 'login' @{ login_type = 'reauth' }) (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '35.198.42.6' 'gcp' 'NL' ($now.AddDays(-1)) 'login' @{ login_type = 'reauth' }) ) RiskyActions = @() SuspiciousCountryLogins = @( (& $mockEvent 'james.rodriguez@acme.com' 'login_success' '95.165.8.42' '' 'RU' ($now.AddDays(-3)) 'login' @{}) ) SuspiciousOAuthGrants = @( (& $mockEvent 'james.rodriguez@acme.com' 'authorize' '20.42.128.97' 'azure' '' ($now.AddDays(-1.8)) 'token' @{ app_name = 'MailDaemon' }) (& $mockEvent 'james.rodriguez@acme.com' 'authorize' '35.198.42.6' 'gcp' '' ($now.AddDays(-0.9)) 'token' @{ app_name = 'CloudSync Pro' }) ) ImpossibleTravel = @() ConcurrentSessions = @( [PSCustomObject]@{ WindowStart = $now.AddDays(-2); WindowEnd = $now.AddDays(-2).AddMinutes(3) DistinctIps = @('20.42.128.97', '95.165.8.42', '73.162.201.44'); IpCount = 3; EventCount = 4 } [PSCustomObject]@{ WindowStart = $now.AddDays(-1); WindowEnd = $now.AddDays(-1).AddMinutes(2) DistinctIps = @('35.198.42.6', '73.162.201.44'); IpCount = 2; EventCount = 3 } ) UserAgentAnomalies = @() BruteForce = $null AfterHoursLogins = @() NewDevices = @() IpClassifications = @{ '20.42.128.97' = @{ Class = 'azure'; Country = 'US'; Events = @('login_success', 'login_success', 'authorize') } '35.198.42.6' = @{ Class = 'gcp'; Country = 'NL'; Events = @('login_success', 'authorize') } '95.165.8.42' = @{ Class = ''; Country = 'RU'; Events = @('login_success') } '73.162.201.44' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success', 'login_success') } } TotalLoginEvents = 22 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u2 # ============================================================ # USER 3: HIGH — impossible travel + Tor + suspicious UA # ============================================================ $u3 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'mike.oconnor@acme.com' ThreatLevel = 'HIGH' ThreatScore = 85.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @( 'IMPOSSIBLE TRAVEL - 1 instance(s), e.g. US to JP (10,847 km in 2.1h)' 'USER AGENT ANOMALY - 1 suspicious client(s): Selenium automation' 'AFTER HOURS LOGIN - 3 login(s) outside business hours (1 outside hours, 2 weekend)' ) KnownAttackerIpLogins = @() CloudIpLogins = @() ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @() ImpossibleTravel = @( [PSCustomObject]@{ FromIp = '73.162.201.44'; ToIp = '126.78.215.3' FromCountry = 'US'; ToCountry = 'JP' FromTime = $now.AddDays(-1); ToTime = $now.AddDays(-1).AddHours(2.1) DistanceKm = 10847; TimeDiffHours = 2.1; RequiredSpeedKmh = 5165 } ) ConcurrentSessions = @() UserAgentAnomalies = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); IpAddress = '126.78.215.3' UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Selenium/4.8.0' MatchLabel = 'Selenium automation'; EventName = 'login_success' } ) BruteForce = $null AfterHoursLogins = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); LocalTime = $now.AddDays(-1) IpAddress = '126.78.215.3'; EventName = 'login_success' DayOfWeek = 'Wednesday'; LocalHour = 2; Timezone = 'UTC' Reason = 'Outside business hours (02:00 local, business hours 7:00-19:00)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-3); LocalTime = $now.AddDays(-3) IpAddress = '73.162.201.44'; EventName = 'login_success' DayOfWeek = 'Saturday'; LocalHour = 14; Timezone = 'UTC' Reason = 'Weekend/non-business day (Saturday)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-4); LocalTime = $now.AddDays(-4) IpAddress = '73.162.201.44'; EventName = 'login_success' DayOfWeek = 'Sunday'; LocalHour = 10; Timezone = 'UTC' Reason = 'Weekend/non-business day (Sunday)' } ) NewDevices = @() IpClassifications = @{ '73.162.201.44' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success', 'login_success') } '126.78.215.3' = @{ Class = ''; Country = 'JP'; Events = @('login_success') } } TotalLoginEvents = 8 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u3 # ============================================================ # USER 4: HIGH — VPN + brute force attempt + suspicious country # ============================================================ $u4 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'anna.petrov@acme.com' ThreatLevel = 'HIGH' ThreatScore = 75.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @( 'SUSPICIOUS COUNTRY LOGIN - 2 login(s) from China (CN), Nigeria (NG)' 'NEW DEVICE FROM CLOUD IP - 1 first-seen device(s) from cloud/hosting IPs' 'BRUTE FORCE ATTEMPT - 8 login failures in 4.2 min from 3 IP(s)' ) KnownAttackerIpLogins = @() CloudIpLogins = @( (& $mockEvent 'anna.petrov@acme.com' 'login_success' '159.89.174.12' 'digitalocean' 'NL' ($now.AddDays(-1)) 'login' @{}) ) ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @( (& $mockEvent 'anna.petrov@acme.com' 'login_success' '119.84.32.5' '' 'CN' ($now.AddDays(-2)) 'login' @{}) (& $mockEvent 'anna.petrov@acme.com' 'login_success' '154.118.42.8' '' 'NG' ($now.AddDays(-1.5)) 'login' @{}) ) SuspiciousOAuthGrants = @() ImpossibleTravel = @() ConcurrentSessions = @() UserAgentAnomalies = @() BruteForce = [PSCustomObject]@{ Detected = $true; FailureCount = 8; SuccessAfter = $false AttackingIps = @('119.84.32.5', '154.118.42.8', '103.42.18.9') FailureWindow = [PSCustomObject]@{ Start = $now.AddDays(-2).AddMinutes(-5); End = $now.AddDays(-2).AddMinutes(-0.8) Duration = [TimeSpan]::FromMinutes(4.2) } SuccessEvent = $null } AfterHoursLogins = @() NewDevices = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); IpAddress = '159.89.174.12' IpClass = 'digitalocean'; IsCloudIp = $true DeviceId = 'dev-x7829'; UserAgent = $null Fingerprint = 'device:dev-x7829'; EventName = 'login_success' } ) IpClassifications = @{ '119.84.32.5' = @{ Class = ''; Country = 'CN'; Events = @('login_failure', 'login_failure', 'login_failure', 'login_success') } '154.118.42.8' = @{ Class = ''; Country = 'NG'; Events = @('login_failure', 'login_failure', 'login_success') } '103.42.18.9' = @{ Class = 'vpn'; Country = 'SG'; Events = @('login_failure', 'login_failure', 'login_failure') } '159.89.174.12' = @{ Class = 'digitalocean'; Country = 'NL'; Events = @('login_success') } '72.134.89.201' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success') } } TotalLoginEvents = 18 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u4 # ============================================================ # USER 5: MEDIUM — cloud logins + after hours + new device # ============================================================ $u5 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'david.kim@acme.com' ThreatLevel = 'MEDIUM' ThreatScore = 40.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @( 'OAUTH FROM CLOUD IP - 1 OAuth grant(s) from cloud IPs: DataPipeline' 'AFTER HOURS LOGIN - 5 login(s) outside business hours (3 outside hours, 2 weekend)' ) KnownAttackerIpLogins = @() CloudIpLogins = @( (& $mockEvent 'david.kim@acme.com' 'login_success' '34.102.136.180' 'gcp' 'US' ($now.AddDays(-3)) 'login' @{}) ) ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @( (& $mockEvent 'david.kim@acme.com' 'authorize' '34.102.136.180' 'gcp' '' ($now.AddDays(-3)) 'token' @{ app_name = 'DataPipeline' }) ) ImpossibleTravel = @() ConcurrentSessions = @() UserAgentAnomalies = @() BruteForce = $null AfterHoursLogins = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); LocalTime = $now.AddDays(-1); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Wednesday'; LocalHour = 23; Timezone = 'UTC'; Reason = 'Outside business hours (23:00 local, business hours 7:00-19:00)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-2); LocalTime = $now.AddDays(-2); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Tuesday'; LocalHour = 4; Timezone = 'UTC'; Reason = 'Outside business hours (04:00 local, business hours 7:00-19:00)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-3); LocalTime = $now.AddDays(-3); IpAddress = '34.102.136.180'; EventName = 'login_success'; DayOfWeek = 'Monday'; LocalHour = 1; Timezone = 'UTC'; Reason = 'Outside business hours (01:00 local, business hours 7:00-19:00)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-5); LocalTime = $now.AddDays(-5); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Saturday'; LocalHour = 14; Timezone = 'UTC'; Reason = 'Weekend/non-business day (Saturday)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-6); LocalTime = $now.AddDays(-6); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Sunday'; LocalHour = 9; Timezone = 'UTC'; Reason = 'Weekend/non-business day (Sunday)' } ) NewDevices = @() IpClassifications = @{ '34.102.136.180' = @{ Class = 'gcp'; Country = 'US'; Events = @('login_success', 'authorize') } '72.134.89.201' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success', 'login_success', 'login_success', 'login_success') } } TotalLoginEvents = 11 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u5 # ============================================================ # USER 6: MEDIUM — Tor exit node + user agent anomaly # ============================================================ $u6 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'lisa.nakamura@acme.com' ThreatLevel = 'MEDIUM' ThreatScore = 45.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @( 'USER AGENT ANOMALY - 2 suspicious client(s): Python requests library, curl' 'CLOUD IP LOGINS - 3 login(s) from cloud/hosting provider IPs' ) KnownAttackerIpLogins = @() CloudIpLogins = @( (& $mockEvent 'lisa.nakamura@acme.com' 'login_success' '104.16.132.229' 'cloudflare' 'US' ($now.AddDays(-1)) 'login' @{}) (& $mockEvent 'lisa.nakamura@acme.com' 'login_success' '104.16.132.229' 'cloudflare' 'US' ($now.AddDays(-2)) 'login' @{}) (& $mockEvent 'lisa.nakamura@acme.com' 'login_success' '152.89.196.211' 'ovh' 'FR' ($now.AddDays(-3)) 'login' @{}) ) ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @() ImpossibleTravel = @() ConcurrentSessions = @() UserAgentAnomalies = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); IpAddress = '104.16.132.229'; UserAgent = 'python-requests/2.28.1'; MatchLabel = 'Python requests library'; EventName = 'login_success' } [PSCustomObject]@{ Timestamp = $now.AddDays(-3); IpAddress = '152.89.196.211'; UserAgent = 'curl/7.88.0'; MatchLabel = 'curl'; EventName = 'login_success' } ) BruteForce = $null AfterHoursLogins = @() NewDevices = @() IpClassifications = @{ '104.16.132.229' = @{ Class = 'cloudflare'; Country = 'US'; Events = @('login_success', 'login_success') } '152.89.196.211' = @{ Class = 'ovh'; Country = 'FR'; Events = @('login_success') } '192.168.1.10' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success') } } TotalLoginEvents = 7 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u6 # ============================================================ # USER 7: LOW — new device only # ============================================================ $u7 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'robert.patel@acme.com' ThreatLevel = 'LOW' ThreatScore = 10.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @('NEW DEVICE - 2 first-seen device(s)') KnownAttackerIpLogins = @() CloudIpLogins = @() ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @() ImpossibleTravel = @() ConcurrentSessions = @() UserAgentAnomalies = @() BruteForce = $null AfterHoursLogins = @() NewDevices = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); IpAddress = '72.134.89.201'; IpClass = ''; IsCloudIp = $false; DeviceId = 'pixel-8-new'; UserAgent = $null; Fingerprint = 'device:pixel-8-new'; EventName = 'login_success' } [PSCustomObject]@{ Timestamp = $now.AddDays(-2); IpAddress = '72.134.89.201'; IpClass = ''; IsCloudIp = $false; DeviceId = $null; UserAgent = 'Mozilla/5.0 (Linux; Android 14) Chrome/121.0'; Fingerprint = 'ua:Mozilla/5.0 (Linux; Android 14) Chrome/121.0'; EventName = 'login_success' } ) IpClassifications = @{ '72.134.89.201' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success', 'login_success') } } TotalLoginEvents = 5 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u7 # ============================================================ # USER 8: LOW — after-hours only # ============================================================ $u8 = [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.UserProfile' Email = 'emily.watson@acme.com' ThreatLevel = 'LOW' ThreatScore = 15.0 IsKnownCompromised = $false WasRemediated = $false Indicators = @('AFTER HOURS LOGIN - 2 login(s) outside business hours (2 outside hours)') KnownAttackerIpLogins = @() CloudIpLogins = @() ReauthFromCloud = @() RiskyActions = @() SuspiciousCountryLogins = @() SuspiciousOAuthGrants = @() ImpossibleTravel = @() ConcurrentSessions = @() UserAgentAnomalies = @() BruteForce = $null AfterHoursLogins = @( [PSCustomObject]@{ Timestamp = $now.AddDays(-1); LocalTime = $now.AddDays(-1); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Monday'; LocalHour = 22; Timezone = 'UTC'; Reason = 'Outside business hours (22:00 local, business hours 7:00-19:00)' } [PSCustomObject]@{ Timestamp = $now.AddDays(-3); LocalTime = $now.AddDays(-3); IpAddress = '72.134.89.201'; EventName = 'login_success'; DayOfWeek = 'Thursday'; LocalHour = 5; Timezone = 'UTC'; Reason = 'Outside business hours (05:00 local, business hours 7:00-19:00)' } ) NewDevices = @() IpClassifications = @{ '72.134.89.201' = @{ Class = ''; Country = 'US'; Events = @('login_success', 'login_success', 'login_success', 'login_success') } } TotalLoginEvents = 6 LoginEvents = @() TokenEvents = @() AccountEvents = @() } $profiles += $u8 # --- Generate report --- $totalUsers = 247 $cleanCount = $totalUsers - $profiles.Count $totalEvents = 12483 Write-GuerrillaText " Generating HTML report with $($profiles.Count) flagged users..." -Color Dim Export-FieldReportHtml ` -Profiles $profiles ` -AllProfilesCount $totalUsers ` -CleanCount $cleanCount ` -AllEventsCount $totalEvents ` -DaysBack 30 ` -TimestampStr (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ` -FilePath $OutputPath Write-GuerrillaText "Demo report generated: $OutputPath" -Color Sage if (-not $NoOpen) { Write-GuerrillaText 'Opening in browser...' -Color Dim Invoke-Item $OutputPath } [PSCustomObject]@{ FilePath = $OutputPath FlaggedUsers = $profiles.Count TotalUsers = $totalUsers } } |