Private/Output/Format-MicrosoftCAWhatIfResponse.ps1
function Format-MicrosoftCAWhatIfResponse { <# .SYNOPSIS Formats Conditional Access WhatIf evaluation results to match Microsoft's API response format. .DESCRIPTION This function takes the internal evaluation results from the WhatIf tool and formats them to match the structure of responses from Microsoft's official Conditional Access evaluation API. This ensures consistency between our tool and Microsoft's implementation. .PARAMETER Results The raw evaluation results to format. .PARAMETER FormatType The type of format to return (Json, Object). .EXAMPLE Format-MicrosoftCAWhatIfResponse -Results $evaluationResults -FormatType Object .EXAMPLE Format-MicrosoftCAWhatIfResponse -Results $evaluationResults -FormatType Json #> [CmdletBinding()] [OutputType([System.Object], [System.String])] param ( [Parameter(Mandatory = $true)] [object[]]$Results, [Parameter(Mandatory = $false)] [ValidateSet('Json', 'Object')] [string]$FormatType = 'Object' ) # Convert our internal result format to Microsoft's API format $formattedResponse = @{ odatacontext = "https://graph.microsoft.com/beta/`$metadata#conditionalAccess/policies/evaluate" value = @() } foreach ($result in $Results) { # Convert AccessResult to Microsoft's format $accessResult = switch ($result.AccessResult) { "Blocked" { "blocked" } "Granted" { "allowed" } "ConditionallyGranted" { "conditionNotSatisfied" } default { "notApplicable" } } # Format the result reasons in Microsoft standard format $resultReasons = @() # Add reason if policy doesn't apply if (-not $result.Applies) { # Map our internal reasons to Microsoft reason codes if (-not $result.EvaluationDetails.UserInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "User not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.ResourceInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Resource not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.ClientAppInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Client app not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.DevicePlatformInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Device platform not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.DeviceStateInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Device state not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.NetworkInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Network not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.UserRiskLevelInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "User risk level not in scope" service = "ConditionalAccess" } } elseif (-not $result.EvaluationDetails.SignInRiskLevelInScope) { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Sign-in risk level not in scope" service = "ConditionalAccess" } } else { $resultReasons += @{ code = "PolicyNotApplicable" detail = "Policy conditions not met" service = "ConditionalAccess" } } } # Add reason if conditional grant controls not satisfied elseif ($result.AccessResult -eq "ConditionallyGranted") { $resultReasons += @{ code = "GrantControlNotSatisfied" detail = "Required controls: $($result.GrantControlsRequired -join ', ')" service = "ConditionalAccess" } } # Format the final policy result in Microsoft's format $policyResult = @{ id = $result.PolicyId displayName = $result.DisplayName state = $result.State result = @{ reference = "conditionalAccess" accessDecision = $accessResult appliedConditionSets = @( @{ reference = "conditionalAccess" result = if ($result.Applies) { "satisfied" } else { "notSatisfied" } reasons = $resultReasons conditions = @{ users = @{ inScope = $result.EvaluationDetails.UserInScope notInScope = ($result.EvaluationDetails.UserExcluded -eq $true) } applications = @{ inScope = $result.EvaluationDetails.ResourceInScope notInScope = ($result.EvaluationDetails.ResourceExcluded -eq $true) } clientApps = @{ inScope = $result.EvaluationDetails.ClientAppInScope } devicePlatforms = @{ inScope = $result.EvaluationDetails.DevicePlatformInScope } locations = @{ inScope = $result.EvaluationDetails.NetworkInScope } deviceState = @{ inScope = $result.EvaluationDetails.DeviceStateInScope } signInRiskLevels = @{ inScope = $result.EvaluationDetails.SignInRiskLevelInScope } userRiskLevels = @{ inScope = $result.EvaluationDetails.UserRiskLevelInScope } } } ) authenticationRequirements = if ($result.AccessResult -eq "ConditionallyGranted") { @{ mfa = if ($result.GrantControlsRequired -contains "mfa") { $true } else { $false } mfaRegistration = if ($result.GrantControlsRequired -contains "mfaRegistrationRequirement") { $true } else { $false } } } else { @{} } sessionRequirements = if ($result.SessionControlsApplied.Count -gt 0) { @{ signInFrequency = if ($result.SessionControlsApplied -contains "signInFrequency") { $true } else { $false } persistentBrowser = if ($result.SessionControlsApplied -contains "persistentBrowser") { $true } else { $false } appEnforcedRestrictions = if ($result.SessionControlsApplied -contains "applicationEnforcedRestrictions") { $true } else { $false } cloudAppSecurity = if ($result.SessionControlsApplied -contains "cloudAppSecurity") { $true } else { $false } continuousAccessEvaluation = if ($result.SessionControlsApplied -contains "continuousAccessEvaluation") { $true } else { $false } } } else { @{} } } } $formattedResponse.value += $policyResult } # Return in the requested format if ($FormatType -eq 'Json') { return $formattedResponse | ConvertTo-Json -Depth 10 } else { return $formattedResponse } } Export-ModuleMember -Function Format-MicrosoftCAWhatIfResponse |