functions/Tenant/Get-HawkTenantRiskyUsers.ps1
Function Get-HawkTenantRiskyUsers { <# .SYNOPSIS Retrieves and analyzes users flagged as risky in Microsoft Entra ID. .DESCRIPTION Uses Microsoft Graph API to retrieve a list of users that have been flagged as risky in Microsoft Entra ID. The function analyzes user risk levels and states to identify potentially compromised accounts requiring immediate investigation. The function requires the following Microsoft Graph permissions: - IdentityRiskyUser.Read.All .EXAMPLE Get-HawkTenantRiskyUsers Retrieves all risky users from Entra ID, including their risk levels and risk states. High risk users are automatically flagged for investigation. .OUTPUTS File: RiskyUsers.csv/.json Path: \Tenant Description: All users currently flagged as risky in Entra ID File: _Investigate_HighRiskUsers.csv/.json Path: \Tenant Description: Users with high risk levels requiring immediate investigation .NOTES This function requires appropriate Graph API permissions to access risky user data. Ensure your authenticated account has IdentityRiskyUser.Read.All permission. #> [CmdletBinding()] param() begin { # Check if Hawk object exists and is fully initialized if (Test-HawkGlobalObject) { Initialize-HawkGlobalObject } # Test Graph connection and proper permissions Test-GraphConnection Send-AIEvent -Event "CmdRun" Out-LogFile "Initiating collection of Risky Users from Entra ID." -Action # Create tenant folder if it doesn't exist $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" if (-not (Test-Path -Path $TenantPath)) { New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null } } process { try { # Get current risky users Out-LogFile "Retrieving current risky users" -Action $riskyUsers = Get-MgRiskyUser -All if ($null -eq $riskyUsers -or $riskyUsers.Count -eq 0) { Out-LogFile "No risky users found" -Information return } Out-LogFile ("Total risky users found: " + $riskyUsers.Count) -Information # Define risk level order for consistent sorting $riskOrder = @{ 'high' = 1 'medium' = 2 'low' = 3 'none' = 4 } # Log summary of users by risk level $riskLevels = $riskyUsers | Group-Object -Property RiskLevel | Sort-Object -Property { $riskOrder[$_.Name] } foreach ($level in $riskLevels) { $capitalizedName = $level.Name.Substring(0, 1).ToUpper() + $level.Name.Substring(1).ToLower() Out-LogFile ("- $($level.Count) users at Risk Level '${capitalizedName}'") -Information } # Export all risky users $riskyUsers | Out-MultipleFileType -FilePrefix "RiskyUsers" -csv -json # Group users by risk level and compromise state for investigation $riskyUserGroups = @{ Compromised = $riskyUsers | Where-Object { $_.RiskState -eq 'confirmedCompromised' } High = $riskyUsers | Where-Object { $_.RiskLevel -eq 'high' } Medium = $riskyUsers | Where-Object { $_.RiskLevel -eq 'medium' } Low = $riskyUsers | Where-Object { $_.RiskLevel -eq 'low' } } # Process compromised users if ($riskyUserGroups.Compromised) { Out-LogFile "Found $($riskyUserGroups.Compromised.Count) confirmed compromised accounts" -Notice Out-LogFile "Details in _Investigate_Compromised_Users files" -Notice $riskyUserGroups.Compromised | Out-MultipleFileType -FilePrefix "_Investigate_Compromised_Users" -json -Notice } # Combine High, Medium, and Low risk users into a single collection $nonCompromisedRiskUsers = @() if ($riskyUserGroups.High) { Out-LogFile ("Found " + $riskyUserGroups.High.Count + " High Risk users requiring immediate investigation") -Notice foreach ($user in $riskyUserGroups.High) { Out-LogFile ("High Risk user detected: $($user.UserPrincipalName)") -Notice Out-LogFile ("Risk Level: $($user.RiskLevel), Risk State: $($user.RiskState)") -Notice } $nonCompromisedRiskUsers += $riskyUserGroups.High } if ($riskyUserGroups.Medium) { Out-LogFile ("Found " + $riskyUserGroups.Medium.Count + " Medium Risk users requiring investigation") -Notice foreach ($user in $riskyUserGroups.Medium) { Out-LogFile ("Medium Risk user detected: $($user.UserPrincipalName)") -Notice Out-LogFile ("Risk Level: $($user.RiskLevel), Risk State: $($user.RiskState)") -Notice } $nonCompromisedRiskUsers += $riskyUserGroups.Medium } if ($riskyUserGroups.Low) { Out-LogFile ("Found " + $riskyUserGroups.Low.Count + " Low Risk users for review") -Notice foreach ($user in $riskyUserGroups.Low) { Out-LogFile ("Low Risk user detected: $($user.UserPrincipalName)") -Notice Out-LogFile ("Risk Level: $($user.RiskLevel), Risk State: $($user.RiskState)") -Notice } $nonCompromisedRiskUsers += $riskyUserGroups.Low } # Combine High, Medium, and Low risk users summary if ($nonCompromisedRiskUsers.Count -gt 0) { $highRisk = ($riskyUserGroups.High).Count $mediumRisk = ($riskyUserGroups.Medium).Count $lowRisk = ($riskyUserGroups.Low).Count Out-LogFile "Found risky users: $highRisk High, $mediumRisk Medium, $lowRisk Low" -Notice $nonCompromisedRiskUsers | Out-MultipleFileType -FilePrefix "_Investigate_Risky_Users" -csv -json -Notice } } catch { Out-LogFile "Error retrieving risky users: $($_.Exception.Message)" -isError Write-Error -ErrorRecord $_ -ErrorAction Continue } } end { Out-LogFile "Completed collection of Risky Users from Entra ID." -Information } } |