Create a Azure AD Conditional Access Policy using PowerShell

  • Post author:
  • Post category:Main
  • Post last modified:August 7, 2023
  • Reading time:11 mins read

In this post we are going to look at creating conditional access policies in Azure AD using PowerShell and the Azure AD PowerShell module. 

Creating conditional access policies using the Azure Management Portal is easily done, however it is not ideal using the clunky web portal if you want this done quickly, in an automated process or through multiple tenants. 

The GA release of the AzureAD module for PowerShell brought us the following cmdlets:

  • New-AzureADMSConditionalAccessPolicy – To create a new conditional access policy.
  • Get-AzureADMSConditionalAccessPolicy – To retrieve a list of conditional access policies.
  • Set-AzureADMSConditionalAccessPolicy – To modify an existing conditional access policy.
  • Remove-AzureADMSConditionalAccessPolicy – To delete an existing conditional access policy.

Install the AzureAD PowerShell module

To successfully create your conditional access policy, you will need to ensure the AzureAD module is installed. If you do not have the AzureAD PowerShell module installed already. Run the following command:

Install-Module AzureAD

If you already have the Azure AD Module installed but want to upgrade to the latest version, use the -Force switch:

Install-Module AzureAD -Force

Create a conditional access policy in Azure Active Directory with PowerShell

Before creating our conditional access policy, there is some information we need to know and decide on, I am going to use the examples below as the basis for my script.

  • The applications you wish protect (Example: OWA)
  • The users you wish to include or exclude (Example: All, except the global admin user)
  • The conditional in which the policy will apply (Example: Windows Devices, Except for Win 11)
  • The Access Control (Example: Grant requiring authentication strength)
  • Any session controls (Example: Sign in frequency every 4 hours)

Here is the full script to create the above conditional access policy:

$conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet
$conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition
$conditions.Applications.IncludeApplications = "00000002-0000-0ff1-ce00-000000000000"
$conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition
$conditions.Users.IncludeUsers = "All"
$conditions.Users.ExcludeRoles = @("62e90394-69f5-4237-9190-012177145e10")
$conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition
$conditions.Platforms.IncludePlatforms = @('Windows')
$gcontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls
$gcontrols._Operator = "OR"
$gcontrols.BuiltInControls = "MFA"
$session = New-Object -TypeName Microsoft.Open.MSGraph.Model.conditionalAccessSessionControls
$sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency
$sessioncontrols.Type = "hours"
$sessioncontrols.Value = 4
$sessioncontrols.IsEnabled = $true
$session.SignInFrequency = $sessioncontrols

New-AzureADMSConditionalAccessPolicy -DisplayName "OWA MFA policy" -State "Disabled" -Conditions $conditions -GrantControls $gcontrols -SessionControls $session

Lets break the above down!

Defining the applications we wish to protect

$conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet
$conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition
$conditions.Applications.IncludeApplications = "00000002-0000-0ff1-ce00-000000000000"

On Line 1 we are creating a new-object of the “conditionalAccessConditionSet” type and passing this information into the variable $conditions. 

On Line 2 we are creating another new object of the “ConditionalAccessApplicationCondition” type and passing this into the Applications property, within the variable $conditions. At this point you should know that we haven’t just guessed the correct property name for this object, you can use the following command to list the ‘members’ of the $condition variable. 

$conditions | get-member

On line 3 we have specified the application ID and passed this into the IncludeApplications parameter. We gather this information from 2 areas, firstly we know to use the IncludeApplications parameter thanks to the Microsoft Graph Rest API reference page here and secondly we gathered the application ID from the Azure AD management portal under “cloud apps or actions” from within a new conditional access policy.

Exchange Online App ID
JSON Conditional access application

We can also expand on the command above, to get a list of available paramaters:

$conditions.Applications | get-member

You will see the following parameters are available to you:

  • $conditions.Applications.IncludeApplications
  • $conditions.Applications.ExcludeApplications
  • $conditions.Applications.IncludeUserActions
  • $conditions.Applications.IncludeProtectionLevels

And here is a list of common application ID’s:

  • Dynamics 365 Business Central: 996def3d-b36c-4153-8607-a6fd3c01b89f
  • Microsoft Azure Management:797f4846-ba00-4fd7-ba43-dac1f8f63013
  • Microsoft Cloud App Security: 05a65629-4c1b-48c1-a78b-804c4abdd4af
  • Microsoft Graph PowerShell: 14d82eec-204b-4c2f-b7e8-296a70dab67e
  • Microsoft Information Protection Sync Service: 870c4f2e-85b6-4d43-bdda-6ed9a579b725
  • Microsoft Intune: 0000000a-0000-0000-c000-000000000000
  • Microsoft Search in Bing: 9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7
  • My Apps: 2793995e-0a7d-40d7-bd35-6968ba142197
  • O365 LinkedIn Connection: f569b9c7-be15-4e87-86f7-87d30d02090b
  • Office 365 Exchange Online: 00000002-0000-0ff1-ce00-000000000000
  • Office 365 SharePoint Online: 00000003-0000-0ff1-ce00-000000000000
  • Skype for Business Online: 00000004-0000-0ff1-ce00-000000000000
  • Universal Store Service APIs and Web Application: 45a330b1-b1ec-4cc1-9161-9f03992aa49f

Specifying which users our conditional access policy applies to

In the next 3 lines, we are defining who our policy applies to. In our case we have applied our policy to all members of our tenant, with the exception of the global administrator role.

$conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition
$conditions.Users.IncludeUsers = "All"
$conditions.Users.ExcludeRoles = @("62e90394-69f5-4237-9190-012177145e10")

We can see this in the above as we have passed “All” into the IncludeUsers parameter and in ExcludeRoles we have defined the Template ID of the global administrators role. We found the Template ID by going to the Azure Active Directory admin center > Roles and administrators > Global administrator > Description.

Global admin template ID

You can also user PowerShell to get the ObjectID for your desired directory role or user with either of the following commands:

# List all directory roles and their objectID
Get-AzureADDirectoryRole

# List all directory users and their objectID
Get-AzureADUser

Other parameters you can include are:

  • $conditions.Users.IncludeUsers
  • $conditions.Users.ExcludeUsers
  • $conditions.Users.IncludeRoles
  • $conditions.Users.ExcludeRoles
  • $conditions.Users.IncludeGroups
  • $conditions.Users.ExcludeGroups

Specifying the platform our policy applies to

In the below lines of code, we are specifying that our policy is only going to apply on the condition that the device being used is a Windows device.

$conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition
$conditions.Platforms.IncludePlatforms = @('Windows')

On line 1, again we are creating a new object time of “ConditionalAccessPlatformCondition”, then on line 2 we are passing the string ‘Windows’ into the IncludePlatforms parameter. There are 5 different platforms you can choose from, these include:

  • Andriod
  • iOS
  • Windows Phones
  • Windows
  • macOS
  • Linux

Using the command “$conditions.Platforms | get-member” we know that we can use the following parameters here:

  • $conditions.Platforms.IncludePlatforms
  • $conditions.Platforms.ExcludePlatforms

Specifying the controls that grant permission to the protected resource

Now we are going to specify on what premises we are going to allow our user to access the resource. I our example, we are going to grant access on the premisis that Multi-Factor authentication is enabled.

$gcontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls
$gcontrols._Operator = "OR"
$gcontrols.BuiltInControls = "MFA"

On line 2 we have select the ‘OR’ logical operator, which means one or the other of the selected controls need to be fulfilled. For example that could be a compliant device OR multi-factor authentication enabled.

On line 3 we have the select the ‘BuiltInControl’ of MFA (or Multi-Factor Authentication). Other possible values for this parameter includes:

  • MFA
  • Block
  • CompliantDevice
  • domainJoinedDevice
  • approvedApplications
  • compliantApplication
  • passwordChange
  • unknownFutureValue

Creating our sign-in frequency session control

The last parameter we are going to define is the session setting for our policy. In our case, we are specifying the sign-in frequency to require a new sign-in every 4 hours. 

$session = New-Object -TypeName Microsoft.Open.MSGraph.Model.conditionalAccessSessionControls
$sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency
$sessioncontrols.Type = "hours"
$sessioncontrols.Value = 4
$sessioncontrols.IsEnabled = $true
$session.SignInFrequency = $sessioncontrols

On line 1 and line 2 we are creating 2 new objects and storing them in the $session variable and $sessioncontrols variable. 

On line 3 to line 5 we are specifying the settings for the sign-in frequency object. On line 3 we have the option to set either “days” or “hours”, then on line 4, we are specifying an integer value and then we are specifying the ‘IsEnabled’ parameter as ‘True’ on line 5.

Lastly on line 3 we are defining the ‘SignInFrequency’ parameter with the settings we just inputted into the ‘sessioncontrols’ variable.

Creating the conditional access policy

In the final line of code in our script we are creating the conditional access policy with a specified name and state, explicitly. We are also using the variables defined prior in our script to implement the desired conditions and controls into our policy.

New-AzureADMSConditionalAccessPolicy -DisplayName "OWA MFA policy" -State "Disabled" -Conditions $conditions -GrantControls $gcontrols -SessionControls $session

Once we run the full script we will get an output like the following:

Id : 87dec72e-4651-460c-8a9d-9a8d07405208
DisplayName : OWA MFA policy
State : disabled
Conditions : class ConditionalAccessConditionSet {
Applications: class ConditionalAccessApplicationCondition {
IncludeApplications: System.Collections.Generic.List`1[System.String]
ExcludeApplications: System.Collections.Generic.List`1[System.String]
IncludeUserActions: System.Collections.Generic.List`1[System.String]
IncludeProtectionLevels:
}

Users: class ConditionalAccessUserCondition {
IncludeUsers: System.Collections.Generic.List`1[System.String]
ExcludeUsers: System.Collections.Generic.List`1[System.String]
IncludeGroups: System.Collections.Generic.List`1[System.String]
ExcludeGroups: System.Collections.Generic.List`1[System.String]
IncludeRoles: System.Collections.Generic.List`1[System.String]
ExcludeRoles: System.Collections.Generic.List`1[System.String]
}

Platforms: class ConditionalAccessPlatformCondition {
IncludePlatforms: System.Collections.Generic.List`1[Microsoft.Open.MSGraph.Model.ConditionalAccessDevicePlatforms]
ExcludePlatforms: System.Collections.Generic.List`1[Microsoft.Open.MSGraph.Model.ConditionalAccessDevicePlatforms]
}

Locations:
SignInRiskLevels: System.Collections.Generic.List`1[Microsoft.Open.MSGraph.Model.ConditionalAccessRiskLevel]
ClientAppTypes: System.Collections.Generic.List`1[Microsoft.Open.MSGraph.Model.ConditionalAccessClientApp]
}

GrantControls : class ConditionalAccessGrantControls {
_Operator: OR
BuiltInControls: System.Collections.Generic.List`1[Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControl]
CustomAuthenticationFactors: System.Collections.Generic.List`1[System.String]
TermsOfUse: System.Collections.Generic.List`1[System.String]
}

SessionControls : class ConditionalAccessSessionControls {
ApplicationEnforcedRestrictions:
CloudAppSecurity:
SignInFrequency: class ConditionalAccessSignInFrequency {
Value: 4
Type: Hours
IsEnabled: True
}

PersistentBrowser:
}

You will also now see your new policy within the Azure Active Directory Management Portal.

conditional access policy result

Daniel Bradley

My name is Daniel Bradley and I work with Microsoft 365 and Azure as an Engineer and Consultant. I enjoy writing technical content for you and engaging with the community. All opinions are my own.

This Post Has 2 Comments

  1. Jan

    Super fine Article.
    I have tryed to modifi it so the exclution could be at group, but it will only accept the ID, not the name of the group. Could that be possible to do.

    1. Daniel

      Thank you Jan! Unfortunately it only accepts the group ID I believe, but you can grab it with the get-mggroup command is some sort of dynamic fashion. 🙂

Leave a Reply