Skip to content

How to export Conditional Access policy

You have Conditional Access policies set up for your organization. There are times when a CA policy is not applying as it should. It’s best to have an overview of every policy to see which options you have configured and which groups or users are included or excluded. In this article, you will learn how to export the Conditional Access policy.

Conditional Access policy

You can create a Conditional Access (CA) policy for users to decide how they authenticate to Microsoft 365. There are certain rules you can implement with its requirements. For example, conditional Access policies allow you to manage security controls that block access and require MFA.

Organizations with Azure AD Premium P2 licenses can include user and sign-in risk in their Conditional Access policies. These additions can help to reduce the security measures by requiring multifactor authentication or secure password change only when a user or sign-in is considered risky.

Once you create multiple Conditional Access policies, it’s better to see a structured overview. To display the CA policy rules and settings you configured, you need to use a PowerShell script to export it to an HTML file.

Download Export Conditional Access policy PowerShell script

You can export all your Conditional Access policies in an HTML file, which you can open to view in a single window browser.

Download the Export-CAPolicy.ps1 PowerShell script and save it in the C:\scripts folder.

Another method is to copy and paste the below code into Notepad. Give it the name Export-CAPolicy.ps1 and place it in the C:\scripts folder.

<#
    .SYNOPSIS
	Conditional Access Export Utility with Microsoft Graph PowerShell (MgGraph).

    .DESCRIPTION
	Exports CA Policy to HTML Format for auditing/historical purposes.
#>

# ExportLocation
$ExportLocation = "C:\scripts\CAPolicy.html"

# Test Graph Module
$GraphModule = Get-Module "Microsoft.Graph" -ListAvailable
If ($null -eq $GraphModule) {
    Write-Host "Microsoft.Graph Module not installed" -ForegroundColor Yellow
    Write-Host "Use: Install-Module -Name Microsoft.Graph" -ForegroundColor Yellow
    break
}

# Connect-MgGraph
$MgContext = Get-MgContext
If ($null -eq $MgContext) {
    Write-host "Connect-MgGraph"
    Connect-MgGraph -Scopes 'Policy.Read.All', 'Directory.Read.All', 'Application.Read.All'
}
else {
    Write-host "Disconnect-MgGraph"
    Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
    Write-host "Connect-MgGraph"
    Connect-MgGraph -Scopes 'Policy.Read.All', 'Directory.Read.All', 'Application.Read.All'
}

# Collect CA Policy
$CAPolicy = Get-MgIdentityConditionalAccessPolicy -All

if (-not $CAPolicy) {
    Write-Host "No CA policies found. Stopping script." -ForegroundColor Red
    return
}

# Tenant Informations
$TenantData = Get-MgOrganization
$TenantName = $TenantData.DisplayName
$date = Get-Date

Write-Host "Exporting: CA Policy" -ForegroundColor Cyan
$CAExport = [PSCustomObject]@()

$AdUsers = @()
$Apps = @()
# Extract Values
Write-host "Extracting: CA Policy Data" -ForegroundColor Cyan
foreach ( $Policy in $CAPolicy) {
    ### Conditions ###
    $IncludeUG = $null
    $IncludeUG = $Policy.Conditions.Users.IncludeUsers
    $IncludeUG += $Policy.Conditions.Users.IncludeGroups
    $IncludeUG += $Policy.Conditions.Users.IncludeRoles

    $ExcludeUG = $null
    $ExcludeUG = $Policy.Conditions.Users.ExcludeUsers
    $ExcludeUG += $Policy.Conditions.Users.ExcludeGroups
    $ExcludeUG += $Policy.Conditions.Users.ExcludeRoles

    $Apps += $Policy.Conditions.Applications.IncludeApplications
    $Apps += $Policy.Conditions.Applications.ExcludeApplications

    $AdUsers += $ExcludeUG
    $AdUsers += $IncludeUG

    $InclLocation = $null
    $ExclLocation = $null
    $InclLocation = $Policy.Conditions.Locations.includelocations
    $ExclLocation = $Policy.Conditions.Locations.Excludelocations

    $InclPlat = $null
    $ExclPlat = $null
    $InclPlat = $Policy.Conditions.Platforms.IncludePlatforms
    $ExclPlat = $Policy.Conditions.Platforms.ExcludePlatforms
    $InclDev = $null
    $ExclDev = $null
    $InclDev = $Policy.Conditions.Devices.IncludeDevices
    $ExclDev = $Policy.Conditions.Devices.ExcludeDevices
    $devFilters = $null
    $devFilters = $Policy.Conditions.Devices.DeviceFilter.Rule

    $CAExport += New-Object PSObject -Property @{
        ### Users ###
        Users                                               = ""
        Name                                                = $Policy.DisplayName;
        PolicyID                                            = $Policy.ID
        Status                                              = $Policy.State;
        UsersInclude                                        = ($IncludeUG -join ", `r`n");
        UsersExclude                                        = ($ExcludeUG -join ", `r`n");
        ### Cloud apps or actions ###
        'Cloud apps or actions'                             = "";
        ApplicationsIncluded                                = ($Policy.Conditions.Applications.IncludeApplications -join ", `r`n");
        ApplicationsExcluded                                = ($Policy.Conditions.Applications.ExcludeApplications -join ", `r`n");
        userActions                                         = ($Policy.Conditions.Applications.IncludeUserActions -join ", `r`n");
        AuthContext                                         = ($Policy.Conditions.Applications.IncludeAuthenticationContextClassReferences -join ", `r`n");
        ### Conditions ###
        Conditions                                          = "";
        UserRisk                                            = ($Policy.Conditions.UserRiskLevels -join ", `r`n");
        SignInRisk                                          = ($Policy.Conditions.SignInRiskLevels -join ", `r`n");
        PlatformsInclude                                    = ($InclPlat -join ", `r`n");
        PlatformsExclude                                    = ($ExclPlat -join ", `r`n");
        LocationsIncluded                                   = ($InclLocation -join ", `r`n");
        LocationsExcluded                                   = ($ExclLocation -join ", `r`n");
        ClientApps                                          = ($Policy.Conditions.ClientAppTypes -join ", `r`n");
        DevicesIncluded                                     = ($InclDev -join ", `r`n");
        DevicesExcluded                                     = ($ExclDev -join ", `r`n");
        DeviceFilters                                       = ($devFilters -join ", `r`n");

        ### Grant Controls ###
        GrantControls                                       = "";
        BuiltInControls                                     = $($Policy.GrantControls.BuiltInControls)
        TermsOfUse                                          = $($Policy.GrantControls.TermsOfUse)
        CustomControls                                      = $($Policy.GrantControls.CustomAuthenticationFactors)
        GrantOperator                                       = $Policy.GrantControls.Operator

        ### Session Controls ###
        SessionControls                                     = ""
        SessionControlsAdditionalProperties                 = $Policy.SessionControls.AdditionalProperties
        ApplicationEnforcedRestrictionsIsEnabled            = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled
        ApplicationEnforcedRestrictionsAdditionalProperties = $Policy.SessionControls.ApplicationEnforcedRestrictions.AdditionalProperties
        CloudAppSecurityType                                = $Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType
        CloudAppSecurityIsEnabled                           = $Policy.SessionControls.CloudAppSecurity.IsEnabled
        CloudAppSecurityAdditionalProperties                = $Policy.SessionControls.CloudAppSecurity.AdditionalProperties
        DisableResilienceDefaults                           = $Policy.SessionControls.DisableResilienceDefaults
        PersistentBrowserIsEnabled                          = $Policy.SessionControls.PersistentBrowser.IsEnabled
        PersistentBrowserMode                               = $Policy.SessionControls.PersistentBrowser.Mode
        PersistentBrowserAdditionalProperties               = $Policy.SessionControls.PersistentBrowser.AdditionalProperties
        SignInFrequencyAuthenticationType                   = $Policy.SessionControls.SignInFrequency.AuthenticationType
        SignInFrequencyInterval                             = $Policy.SessionControls.SignInFrequency.FrequencyInterval
        SignInFrequencyIsEnabled                            = $Policy.SessionControls.SignInFrequency.IsEnabled
        SignInFrequencyType                                 = $Policy.SessionControls.SignInFrequency.Type
        SignInFrequencyValue                                = $Policy.SessionControls.SignInFrequency.Value
        SignInFrequencyAdditionalProperties                 = $Policy.SessionControls.SignInFrequency.AdditionalProperties


    }
}

# Swith user/group Guid to display names
Write-host "Converting: Entra ID Guids" -ForegroundColor Cyan
# Filter out Objects
$cajson = $CAExport | ConvertTo-Json -Depth 4
$ADsearch = $AdUsers | Where-Object { $_ -ne 'All' -and $_ -ne 'GuestsOrExternalUsers' -and $_ -ne 'None' }
$AdNames = @{}
Get-MgDirectoryObjectById -ids $ADsearch | ForEach-Object {
    $obj = $_.Id
    #$disp = $_.displayName
    $disp = $_.AdditionalProperties.displayName
    $AdNames.$obj = $disp
    $cajson = $cajson -replace "$obj", "$disp"
}
$CAExport = $cajson | ConvertFrom-Json
# Switch Apps Guid with Display names
$allApps = Get-MgServicePrincipal -All
$allApps | Where-Object { $_.AppId -in $Apps } | ForEach-Object {
    $obj = $_.AppId
    $disp = $_.DisplayName
    $cajson = $cajson -replace "$obj", "$disp"
}
# Switch named location Guid for Display Names
Get-MgIdentityConditionalAccessNamedLocation | ForEach-Object {
    $obj = $_.Id
    $disp = $_.DisplayName
    $cajson = $cajson -replace "$obj", "$disp"
}
# Switch Roles Guid to Names
#Get-MgDirectoryRole | ForEach-Object{
Get-MgDirectoryRoleTemplate | ForEach-Object {
    $obj = $_.Id
    $disp = $_.DisplayName
    $cajson = $cajson -replace "$obj", "$disp"
}
$CAExport = $cajson | ConvertFrom-Json

# Export Setup
Write-host "Pivoting: CA to Export Format" -ForegroundColor Cyan
$pivot = @()
$rowItem = New-Object PSObject
$rowitem | Add-Member -type NoteProperty -Name 'CA Item' -Value "row1"
$Pcount = 1
foreach ($CA in $CAExport) {
    $rowitem | Add-Member -type NoteProperty -Name "Policy $pcount" -Value "row1"
    #$ca.Name
    $pcount += 1
}
$pivot += $rowItem

# Add Data to Report
$Rows = $CAExport | Get-Member | Where-Object { $_.MemberType -eq "NoteProperty" }
$Rows | ForEach-Object {
    $rowItem = New-Object PSObject
    $rowname = $_.Name
    $rowitem | Add-Member -type NoteProperty -Name 'CA Item' -Value $_.Name
    $Pcount = 1
    foreach ($CA in $CAExport) {
        $ca | Get-Member | Where-Object { $_.MemberType -eq "NoteProperty" } | ForEach-Object {
            $a = $_.name
            $b = $ca.$a
            if ($a -eq $rowname) {
                $rowitem | Add-Member -type NoteProperty -Name "Policy $pcount" -Value $b
            }
        }
        $pcount += 1
    }
    $pivot += $rowItem
}

# Column Sorting Order
$sort = "Name", "PolicyID", "Status", "Users", "UsersInclude", "UsersExclude", "Cloud apps or actions", "ApplicationsIncluded", "ApplicationsExcluded", `
    "userActions", "AuthContext", "Conditions", "UserRisk", "SignInRisk", "PlatformsInclude", "PlatformsExclude", "LocationsIncluded", `
    "LocationsExcluded", "ClientApps", "Devices", "DevicesIncluded", "DevicesExcluded", "DeviceFilters", `
    "GrantControls", "BuiltInControls", "TermsOfUse", "CustomControls", "GrantOperator", `
    "SessionControls", "SessionControlsAdditionalProperties", "ApplicationEnforcedRestrictionsIsEnabled", "ApplicationEnforcedRestrictionsAdditionalProperties", `
    "CloudAppSecurityType", "CloudAppSecurityIsEnabled", "CloudAppSecurityAdditionalProperties", "DisableResilienceDefaults", "PersistentBrowserIsEnabled", `
    "PersistentBrowserMode", "PersistentBrowserAdditionalProperties", "SignInFrequencyAuthenticationType", "SignInFrequencyInterval", "SignInFrequencyIsEnabled", `
    "SignInFrequencyType", "SignInFrequencyValue", "SignInFrequencyAdditionalProperties"

# Debug
#$pivot | Sort-Object $sort | Out-GridView

# HTML Export
Write-host "Saving to File: HTML in $ExportLocation" -ForegroundColor Cyan
$jquery = '<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	<script>
	$(document).ready(function(){
		$("tr").click(function(){
		if(!$(this).hasClass("selected")){
			$(this).addClass("selected");
		} else {
			$(this).removeClass("selected");
		}

		});
		$("th").click(function(){
		if(!$(this).hasClass("colselected")){
			$(this).addClass("colselected");
		} else {
			$(this).removeClass("colselected");
		}

		});
	});
	</script>'
$html = "<html><head><base href='https://docs.microsoft.com/' target='_blank'>
	$jquery<style>
	.title{
		display: block;
		font-size: 2em;
		margin-block-start: 0.67em;
		margin-block-end: 0.67em;
		margin-inline-start: 0px;
		margin-inline-end: 0px;
		font-weight: bold;
		font-family: Segoe UI;
	}
	table{
		border-collapse: collapse;
		margin: 25px 0;
		font-size: 0.9em;
		font-family: Segoe UI;
		min-width: 400px;
		box-shadow: 0 0 20px rgba(0, 0, 0, 0.15) ;
		text-align: center;
	}
	thead tr {
		background-color: #009879;
		color: #ffffff;
		text-align: left;
	}
	th, td {
		min-width: 250px;
		padding: 12px 15px;
		border: 1px solid lightgray;
		vertical-align: top;
	}
	td {
		vertical-align: top;
	}
	tbody tr {
		border-bottom: 1px solid #dddddd;
	}
	tbody tr:nth-of-type(even) {
		background-color: #f3f3f3;
	}
	tbody tr:nth-of-type(5), tbody tr:nth-of-type(8), body tr:nth-of-type(13), tbody tr:nth-of-type(24), tbody tr:nth-of-type(29){
		background-color: #36c;
		text-aling:left !important
	}
	tbody tr:last-of-type {
		border-bottom: 2px solid #009879;
	}
	tr:hover{
	background-color: #ffea76!important;
	}
	.selected:not(th){
		background-color:#ffea76!important;
	}
	th{
		background-color:white !important;
	}
	.colselected {
	background-color: rgb(93, 236, 213)!important;
	}
	table tr th:first-child,table tr td:first-child {
		position: sticky;
		inset-inline-start: 0;
		background-color: #36c!important;
		Color: #fff;
		font-weight: bolder;
		text-align: center;
	}
	</style></head><body> <div class='Title'>CA Export: $Tenantname - $Date </div>"

Write-host "Launching: Web Browser" -ForegroundColor Cyan
$Launch = $ExportLocation
$HTML += $pivot  | Where-Object { $_."CA Item" -ne 'row1' } | Sort-object { $sort.IndexOf($_."CA Item") } | convertto-html -Fragment
$HTML | Out-File $Launch
start-process $Launch

Connect to Microsoft Graph PowerShell

Before you run the Export-CAPolicy.ps1 PowerShell script, you need to install the Microsoft Graph PowerShell module.

Run the below PowerShell command to install MS Graph.

Install-Module Microsoft.Graph -Force

Export Conditional Access policy report

Run PowerShell as administrator and run the Export-CAPolicy.ps1 PowerShell script.

C:\scripts\.\Export-CAPolicy.ps1

It will connect to MS Graph, where you must sign into your admin account.

  • Enter password
  • Click Sign in
Sign in to your account to connect to MgGraph

Permission is requested to verify the consent.

  • Enable Consent on behalf of your organization
  • Click Accept
Permission Microsoft Graph accept consent

You will see this output on your PowerShell console.

Exporting: CA Policy
Extracting: CA Policy Data
Converting: Entra ID Guids
Pivoting: CA to Export Format
Saving to File: HTML in C:\scripts\CAPolicy.html
Launching: Web Browser

It will open a browser window with your Conditional Access policies report.

The below screenshot is an example of the Conditional Access Policy export report. Here, you can easily compare the different policies by going through all the different options.

Remember that your CA policy file is saved in the scripts folder in your (C:) drive.

  • Go to the folder C:\scripts
  • Double-click the CAPolicy.html file to open it in your browser
Export Conditional Access policy html file and ps1

You successfully managed to export all CA policies to a report.

Read more: Export Microsoft 365 mailbox size report »

Conclusion

You learned how to export the Conditional Access policy with PowerShell. Use the PowerShell script that will connect to MgGraph and save the CA policy HTML file in your scripts folder. Once you export the CA policies, it’s easier to get a structured overview of the settings.

Did you enjoy this article? You may also like Export Microsoft user licenses. Don’t forget to follow us and share this article.

o365info Team

o365info Team

This article was written by our team of experienced IT architects, consultants, and engineers.

This Post Has 4 Comments

  1. If you are not getting names, I suggest you remove all your graph modules and reinstall. To test before doing so, just try and run Get-MgDirectoryObjectById and see if you get the infamous “Assembly with same name is already loaded” error. There are a bunch of ways to troubleshoot this and figure out which graph module is causing the grief, but the most effective way is to shutdown powershell, and delete all the graph modules (most likely in my documents\powershell\modules) and then install microsoft graph again.

  2. The tenant has 2 CA policies and the report acknowledges that. Where the error occurs is when the script attempts to convert User GUIDs to a Display Name. The resulting report has 2 columns for the 2 CA policies with Users Included: ALL and Users Excluded: a list of GUIDs. Fine for me, but my client isn’t too happy about it. 🙂 Otherwise, it’s a beautiful report.

    Your help appreciated.

    jbw

Leave a Reply

Your email address will not be published. Required fields are marked *