Script to Quickly Document your Conditional Access Policies

Conditional Access Policies are often critical to an organizations security configuration for Microsoft 365 and any other integrated apps that leverage Azure AD. I’ve been using this script for a while to document and ‘snapshot’ Conditional Access Policies in customer environments and thought I would share via GitHub.

The script will gather each existing Conditional Access Policy and export it in JSON format complete with all configured settings. This allows for easy review of policies along with comparison of policies over time by comparing the JSON files created.

To run the script, we need an Application Registration with “Policy.Read.All” application permissions assigned and granted. I’ve detailed the process of setting up an application registration previously in a few posts (like this one). Once everything is set up, we need to Application ID, Tenant ID and an App Secret to run the export.

When we have gathered these bits of information, download the script and navigate to the path in PowerShell. To import it run:

Import-Module graph-Document-Conditional-Access-Policies.ps1

Once imported, we can run it using the below syntax:

Report-ConditionalAccess -clientId $clientid -tenantId $tenantid -clientSecret $ClientSecret

In this example $ClientID is the Application ID of our App Reg, $TenantID is the ID of the tenant and $ClientSecret is the secret we created in our app reg.

Once everything runs, we will get a selection of JSON files exported, one for each policy we have.

Opening up one of the policies shows us the complete detail of the policy, giving us an easy breakdown of our configuration.

We can then save these files as part of our documentation and use them for comparisons down the line.

This script is available on GitHub here and I’ve copied the code below:


##Author: Sean McAvinue
##Details: Exports conditional access policies to JSON 
##          USE AT YOUR OWN RISK
function GetGraphToken {

    <#
    .SYNOPSIS
    Azure AD OAuth Application Token for Graph API
    Get OAuth token for a AAD Application (returned as $token)
    
    #>

    # Application (client) ID, tenant ID and secret
    Param(
        [parameter(Mandatory = $true)]
        $clientId,
        [parameter(Mandatory = $true)]
        $tenantId,
        [parameter(Mandatory = $true)]
        $clientSecret

    )
    
    
    
    # Construct URI
    $uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
     
    # Construct Body
    $body = @{
        client_id     = $clientId
        scope         = "https://graph.microsoft.com/.default"
        client_secret = $clientSecret
        grant_type    = "client_credentials"
    }
     
    # Get OAuth 2.0 Token
    $tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
     
    # Access Token
    $token = ($tokenRequest.Content | ConvertFrom-Json).access_token
    
    #Returns token
    return $token
}
    



function RunQueryandEnumerateResults {
    <#
    .SYNOPSIS
    Runs Graph Query and if there are any additional pages, parses them and appends to a single variable
    
    .PARAMETER apiUri
    -APIURi is the apiUri to be passed
    
    .PARAMETER token
    -token is the auth token
    
    #>
    Param(
        [parameter(Mandatory = $true)]
        [String]
        $apiUri,
        [parameter(Mandatory = $true)]
        $token

    )

    #Run Graph Query
    $Results = (Invoke-RestMethod -Headers @{Authorization = "Bearer $($Token)" } -Uri $apiUri -Method Get)
    #Output Results for debug checking
    #write-host $results

    #Begin populating results
    $ResultsValue = $Results.value

    #If there is a next page, query the next page until there are no more pages and append results to existing set
    if ($results."@odata.nextLink" -ne $null) {
        write-host enumerating pages -ForegroundColor yellow
        $NextPageUri = $results."@odata.nextLink"
        ##While there is a next page, query it and loop, append results
        While ($NextPageUri -ne $null) {
            $NextPageRequest = (Invoke-RestMethod -Headers @{Authorization = "Bearer $($Token)" } -Uri $NextPageURI -Method Get)
            $NxtPageData = $NextPageRequest.Value
            $NextPageUri = $NextPageRequest."@odata.nextLink"
            $ResultsValue = $ResultsValue + $NxtPageData
        }
    }

    ##Return completed results
    return $ResultsValue

    
}

function Report-ConditionalAccess{

    <#
    .SYNOPSIS
    Returns a report of Conditional Access Policies in a tenent
    
    #>

    # Application (client) ID, tenant ID and secret
    Param(
        [parameter(Mandatory = $true)]
        $clientId,
        [parameter(Mandatory = $true)]
        $tenantId,
        [parameter(Mandatory = $true)]
        $clientSecret

    )

    $apiUri = "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies"
    $token = GetGraphToken -clientId $clientId -tenantId  $tenantId -clientSecret $clientSecret

    $Policies = RunQueryandEnumerateResults -apiuri $apiUri -token $token



    foreach($policy in $policies){

        $policy | convertto-json | out-file ("$($policy.displayName).json").replace('[','').replace(']','').replace('/','')

    }

}



6 thoughts on “Script to Quickly Document your Conditional Access Policies

  1. Pingback: 7 Tips for Working with the Graph API in PowerShell – Sean McAvinue

  2. Pingback: Updated: Conditional Access Documentation Script Now Supports Translation to Friendly Names – Sean McAvinue

  3. Tony

    Any thoughts on why the script returns 403 – forbidden?
    Pretty sure I have the App registration configured with “Policy.Read.All”.

    Like

    1. garetjax67

      if using -performtranslation you will also need to grant Directory.Read.All so you can enumerate the Azure AD objects

      Like

  4. Hi Tony,
    I just tested it with a new app reg and it didn’t give me an error. Can you confirm if you added the permissions as application permissions rather than delegated?

    You could also test if you can get a token by running the code from the GetGraphToken function and then check the output of the $token variable:

    $uri = “https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token”

    # Construct Body
    $body = @{
    client_id = $clientId
    scope = “https://graph.microsoft.com/.default”
    client_secret = $clientSecret
    grant_type = “client_credentials”
    }

    # Get OAuth 2.0 Token
    $tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType “application/x-www-form-urlencoded” -Body $body -UseBasicParsing

    # Access Token
    $token = ($tokenRequest.Content | ConvertFrom-Json).access_token

    $token

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s