Conditional Access ‘What If’ Simulation with PowerShell

Introduction

So, I decided to write my own Conditional Access evaluation engine in PowerShell, like one does on rainy November nights, right?

Its purpose is to provide capabilities similar to the built-in What If tool in the Entra ID portal, but with a clear focus on finding grant control gaps in common an uncommon use cases. Use it for troubleshooting, configuration verification, or large scale Conditional Access gap analysis.

What If

The Conditional Access What If tool is a feature within Entra ID that allows administrators to simulate the effects of their Conditional Access policies. It helps in understanding how these policies would impact users access to resources and applications without actually enforcing the policies.

Here’s what the Microsoft tool can do, and what I’m trying to reproduce:

  1. Policy Testing: Administrators can test the impact of new or modified Conditional Access policies before deploying them. This helps in ensuring that policies function as intended without causing unexpected disruptions.
  2. Risk Assessment: By simulating different scenarios, administrators can assess potential risks and vulnerabilities in their security configurations. They can identify gaps in access control and refine policies accordingly.
  3. User Experience Analysis: The tool helps in understanding how policy changes might affect the user experience. Admins can see if the policies might overly restrict or inconvenience users, allowing adjustments for a smoother workflow.
  4. Compliance Validation: It assists in ensuring compliance with regulatory requirements by evaluating if the configured policies meet necessary compliance standards.
  5. Troubleshooting: In case of access issues, the WhatIf tool can be used to diagnose and troubleshoot problems related to Conditional Access policies, allowing admins to pinpoint potential causes without affecting live configurations.

The Conditional Access What If tool serves as a sandbox environment where administrators can experiment with policy changes, assess their impact, and fine-tune settings before implementation, thereby enhancing security and user experience within their organization. So let’s see what I managed to pull off.

Invoke-DCConditionalAccessSimulation

This tool is part of DCToolbox. Install with:

Install-Module -Name DCToolbox -Force

Now you are ready to test Conditional Access evaluation. Make sure you read and understand the help content. Learn about the different parameters and options by running:

help Invoke-DCConditionalAccessSimulation

You can run the tool without parameters to use a set of default parameters:

# Run basic evaluation with default settings.
Invoke-DCConditionalAccessSimulation | Format-List

By default, matching Conditional Access policies are returned as PowerShell objects that can be used for further piping and formatting. Note that some properties are returned as JSON objects (because I like JSON):

Examples piping objects to Where-Object:

# Filter on all matching policies that requires authentication strengths.
Invoke-DCConditionalAccessSimulation | Where-Object { ($_.GrantControls | ConvertFrom-Json ).AuthenticationStrength -eq $true  }

You can test specific scenarios by changing the defaults:

# Run evaluation with custom settings.
$Parameters = @{
    UserPrincipalName = 'user@example.com'
    ApplicationDisplayName = 'Office 365'
    ClientApp = 'mobileAppsAndDesktopClients'
    TrustedIPAddress = $true
    Country = 'US'
    Platform = 'windows'
    SignInRiskLevel = 'medium'
    UserRiskLevel = 'high'
    SummarizedOutput = $true
    VerbosePolicyEvaluation = $false
    IncludeNonMatchingPolicies = $false
}

Invoke-DCConditionalAccessSimulation @Parameters

In most cases you are probably more interested in a quick answer. What would apply if… Therefor I included a switch called -SummarizedOutput you can use to add a nice readable and colorized output:

Invoke-DCConditionalAccessSimulation -SummarizedOutput

If you need to troubleshoot or understand the evaluation process there is a verbose switch for that called -VerbosePolicyEvaluation. If one or more conditions doesn’t match, then the policy is not applied (exceptions are users and groups since only one of them have to match, the same goes for countries and IP addresses). That’s how Conditional Access works 🙂

Invoke-DCConditionalAccessSimulation -VerbosePolicyEvaluation

Finally, if I’m doing a gap analysis of a Conditional Access implementation, then this is what I would run to get a nice clean output for me to read (getting rid of all output streams used by the tool except for Informational (Write-Host)):

Write-Host -ForegroundColor Yellow "TEST CASE: USER signing into 'Microsoft Admin Portals', from a BROWSER, running on WINDOWS, from SWEDEN"

$Parameters = @{
    UserPrincipalName = 'All'
    ApplicationDisplayName = 'Microsoft Admin Portals'
    ClientApp = 'browser'
    TrustedIPAddress = $false
    Country = 'SE'
    Platform = 'windows'
    SignInRiskLevel = 'none'
    UserRiskLevel = 'none'
    SummarizedOutput = $true
    VerbosePolicyEvaluation = $false
    IncludeNonMatchingPolicies = $false

}

Invoke-DCConditionalAccessSimulation @Parameters 1>$null 4>$null

You can put this in a loop and test different use cases for rapid large scale gap analysis.

Examples

TEST CASE : USER signing into ‘Office 365’, from a LEGACY AUTHENTICATION CLIENT, running on WINDOWS, from SWEDEN:

$Parameters = @{
    UserPrincipalName = 'All'
    ApplicationDisplayName = 'Office 365'
    ClientApp = 'other'
    TrustedIPAddress = $false
    Country = 'SE'
    Platform = 'windows'
    SignInRiskLevel = 'none'
    UserRiskLevel = 'none'
    SummarizedOutput = $true
    VerbosePolicyEvaluation = $false
    IncludeNonMatchingPolicies = $false

}

Invoke-DCConditionalAccessSimulation @Parameters 1>$null 4>$null

TEST CASE: USER signing into ‘Microsoft Admin Portals’, from a BROWSER, running on LINUX, from CHINA:

$Parameters = @{
    UserPrincipalName = 'All'
    ApplicationDisplayName = 'Microsoft Admin Portals'
    ClientApp = 'browser'
    TrustedIPAddress = $false
    Country = 'CH'
    Platform = 'linux'
    SignInRiskLevel = 'none'
    UserRiskLevel = 'none'
    SummarizedOutput = $true
    VerbosePolicyEvaluation = $false
    IncludeNonMatchingPolicies = $false

}

Invoke-DCConditionalAccessSimulation @Parameters 1>$null 4>$null

TEST CASE: USER signing into ‘Office 365’, from a BROWSER, running on WINDOWS, with SIGN-IN HIGH-RISK

$Parameters = @{
    UserPrincipalName = 'All'
    ApplicationDisplayName = 'Office 365'
    ClientApp = 'browser'
    TrustedIPAddress = $false
    Country = 'SE'
    Platform = 'windows'
    SignInRiskLevel = 'high'
    UserRiskLevel = 'none'
    SummarizedOutput = $true
    VerbosePolicyEvaluation = $false
    IncludeNonMatchingPolicies = $false

}

Invoke-DCConditionalAccessSimulation @Parameters 1>$null 4>$null

Limitations / In Development

As stated above, the goal of the tool is to find gaps where grant controls aren’t applied. For that reason all features of Conditional Access aren’t simulated. Here are some current limitations and stuff I plan to add:

  • Entra ID role assignments aren’t checked (under development).
  • Session controls aren’t evaluated at all (but are included in the PowerShell object output as JSON data).
  • Applications filters aren’t evaluated (under development).
  • Device filters aren’t evaluated (under development , if I can pull it of 😅)
  • User actions aren’t evaluated (in development).
  • Authentication context (I might skip this for now)

Currently the tool does what it was initially intended for, but it will evolve over time.

Summary

This tool has helped me to improve my own, and other Conditional Access implementations. I hope it can help you too!

Please follow me here, on LinkedIn, and on X!

@DanielChronlund