Public/Test-GuerrillaConditionalAccess.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-GuerrillaConditionalAccess { <# .SYNOPSIS Conditional Access "what-if" simulation — evaluates a simulated sign-in against the tenant's live CA policies via the Microsoft Graph evaluate API, and returns the enforced outcome. .DESCRIPTION The free, multi-theater answer to Maester's Test-MtConditionalAccessWhatIf. Builds the same request and POSTs to https://graph.microsoft.com/beta/identity/conditionalAccess/evaluate, then normalizes the applied policies into a single verdict (Block / MfaRequired / CompliantDeviceRequired / PasswordChangeRequired / Grant / NotApplied / Unknown). The evaluate API is in BETA. If the response is empty or an unrecognised shape, the verdict is 'Unknown' (callers treat that as Not Assessed — never a false PASS). .PARAMETER UserId Object ID (GUID) of the user to simulate the sign-in for. .PARAMETER AccessToken Microsoft Graph access token (needs Policy.Read.ConditionalAccess + the CA evaluate beta scope). .PARAMETER IncludeApplications App ID(s) the sign-in targets. Default 'All'. (Application-context simulation.) .PARAMETER UserAction Instead of an app, simulate a user action ('registerOrJoinDevices' / 'registerSecurityInformation'). .PARAMETER DevicePlatform / ClientAppType / SignInRiskLevel / UserRiskLevel / Country / IpAddress Optional sign-in conditions, mirroring the Graph what-if conditions. .PARAMETER AllResults Return all evaluated policies, not just the ones that apply. .EXAMPLE Test-GuerrillaConditionalAccess -UserId $uid -AccessToken $tok -ClientAppType exchangeActiveSync # Is legacy auth blocked for this user? -> .Result should be 'Block' #> [CmdletBinding(DefaultParameterSetName = 'App')] [OutputType('PSGuerrilla.CAWhatIfResult')] param( [Parameter(Mandatory)][string]$UserId, [Parameter(Mandatory)][string]$AccessToken, [Parameter(ParameterSetName = 'App')][string[]]$IncludeApplications = @('All'), [Parameter(ParameterSetName = 'UserAction')] [ValidateSet('registerOrJoinDevices', 'registerSecurityInformation')] [string[]]$UserAction, [ValidateSet('all', 'Android', 'iOS', 'windows', 'windowsPhone', 'macOS', 'linux')] [string]$DevicePlatform, [ValidateSet('browser', 'mobileAppsAndDesktopClients', 'exchangeActiveSync', 'easSupported', 'other')] [string]$ClientAppType, [ValidateSet('None', 'Low', 'Medium', 'High')][string]$SignInRiskLevel, [ValidateSet('None', 'Low', 'Medium', 'High')][string]$UserRiskLevel, [string]$Country, [string]$IpAddress, [switch]$AllResults ) $context = if ($PSCmdlet.ParameterSetName -eq 'UserAction') { @{ '@odata.type' = '#microsoft.graph.userActionContext'; userAction = ($(if ($UserAction.Count -eq 1) { $UserAction[0] } else { $UserAction })) } } else { @{ '@odata.type' = '#microsoft.graph.applicationContext'; includeApplications = @($IncludeApplications) } } $conditions = @{} if ($SignInRiskLevel) { $conditions.signInRiskLevel = $SignInRiskLevel } if ($UserRiskLevel) { $conditions.userRiskLevel = $UserRiskLevel } if ($ClientAppType) { $conditions.clientAppType = $ClientAppType } if ($DevicePlatform) { $conditions.devicePlatform = $DevicePlatform } if ($Country) { $conditions.country = $Country } if ($IpAddress) { $conditions.ipAddress = $IpAddress } $body = @{ AppliedPoliciesOnly = (-not $AllResults) signInIdentity = @{ '@odata.type' = '#microsoft.graph.userSignIn'; userId = $UserId } signInContext = $context signInConditions = $conditions } $verdict = @{ Result = 'Unknown'; AppliedPolicies = @() } $applied = @() try { $resp = Invoke-GraphApi -AccessToken $AccessToken -Uri '/identity/conditionalAccess/evaluate' ` -Method Post -Body $body -Beta $applied = @($resp.value) if (-not $AllResults) { $applied = @($applied | Where-Object { $_.policyApplies -eq $true }) } $verdict = ConvertTo-CAWhatIfVerdict -AppliedPolicies $applied } catch { Write-Warning "CA what-if evaluation failed (beta API): $_" } [PSCustomObject]@{ PSTypeName = 'PSGuerrilla.CAWhatIfResult' UserId = $UserId Context = ($context.'@odata.type' -replace '#microsoft\.graph\.', '') Conditions = $conditions Result = $verdict.Result AppliedPolicies = @($verdict.AppliedPolicies) Raw = $applied } } |