Microsoft provides many methods to manage a tenant’s data and users.  PowerShell is a powerful tool to manage resources, including Conditional Access Policies using a set of cmdlets in the AzureAD module.  In this article, we review the eight PowerShell cmdlets and how to use them.

**Note that both the AzureAD and AzureADPreview PowerShell modules contain these cmdlets.

PowerShell and CA Policies

First, connect to Azure Active Directory using either the AzureAD or AzureADPreview module:
Connect-AzureAD

After connecting, we can get a list of available PowerShell cmdlets by using these two one-liners:
Get-Command *conditional*
Get-Command *named*

Combined we get a total of eight cmdlets dealing with Conditional Access Policies and Names Location Policies:
Get-AzureADMSConditionalAccessPolicy
New-AzureADMSConditionalAccessPolicy
Remove-AzureADMSConditionalAccessPolicy
Set-AzureADMSConditionalAccessPolicy

Get-AzureADMSNamedLocationPolicy
New-AzureADMSNamedLocationPolicy
Remove-AzureADMSNamedLocationPolicy
Set-AzureADMSNamedLocationPolicy

Conditional Access Policies set conditions to determine the conditions under which users receive access to apps.  These conditions can consist of locations, one or more users, applications, platforms, and more. 

Using PowerShell to Manage Conditional Access (CA) Policies
Figure 1: Properties of a new Conditional Access Policy

In the following examples, we examine these conditions to see what we can configure with PowerShell.

Creating a New Conditional Access Policy

A greenfield, or new tenant, has no Conditional Access Policies.  To utilize Conditional Access, we need to build its conditions.  If Named Locations are required, we need to create the Named Location first.  Let us walk through this process using an example scenario.

Named Locations

Conditional Access Policies can contain Named Locations that correspond to physical locations in an organization’s environment. Named Locations can be Physical locations with their corresponding IP subnet/range or a single country/a set of countries.  We can use Named Locations to provide a condition that controls where users are prompted (or not prompted) for MFA or other optional actions.   Included in the Azure AD Module, we saw that there are four PowerShell cmdlets for managing Named Locations and run the typical gamut of Get, New, Remove and Set PowerShell verbs.

In a new or Greenfield Azure AD, there are no Named Locations that can be used by Conditional Access and we need to either create these in Azure AD or with PowerShell.  To create a new Named Location policy, we need to use the New-AzureADMSNamedLocationPolicy cmdlet. 

When creating a new Named location, we need to keep a couple of things in mind:

  • Display Name is required
  • Need to choose either an IP range or a list of countries as this determines the type of Named Location we are creating.

For the first Named Location, we can use some base criteria – Chicago Office, IP Range of 10.25.0.0 with a subnet mask of 16 bits and we will mark this location as a trusted location. A second location can also be created for a New York Office, with an IP range of 10.26.0.0 and the same subnet mask of 16 bits. PowerShell is required to create the Named Location.  Notice that there is an MS Graph object for the IP subnet of the office in the example below.

Example:
IT wants a Conditional Access Policy to force multi-factor authentication (MFA) for all cloud apps unless users access apps from two locations.  The locations are both physical offices in Chicago and New York, with subnets of 10.25.0.0/16 and 10.26.0.0/16, respectively.  We will first create the two Named Locations using New-AzureADMSNamedLocationPolicy and then create a new CA Policy using New-AzureADMSConditionalAccessPolicy to reference the locations:
$CHISubnet = New-Object -TypeName Microsoft.Open.MSGraph.Model.IpRange
$CHISubnet.cidrAddress = ‘10.25.0.0/16’
New-AzureADMSNamedLocationPolicy -OdataType “#microsoft.graph.ipNamedLocation” -DisplayName ‘Chicago Office’ -IsTrusted $True -IpRanges $CHISubnet
$NYSubnet = New-Object -TypeName Microsoft.Open.MSGraph.Model.IpRange
$NYSubnet.cidrAddress = ‘10.26.0.0/16’
New-AzureADMSNamedLocationPolicy -OdataType “#microsoft.graph.ipNamedLocation” -DisplayName ‘New York Office’ -IsTrusted $True -IpRanges $NYSubnet

We can validate the properties of the locations with the Get-AzureADMSNamedLocationPolicy cmdlet, which we should do before proceeding:

Using PowerShell to Manage Conditional Access (CA) Policies
Figure 2: New Named Locations and the configured settings in the red rectangles.

** To be fair, the same output is also generated when creating a Named Location, but the above illustrates what can be seen with the Get-* portion of the Named Location cmdlets.

With the Named Locations created, we can now use these into a CA Policy (keep in mind there are a lot of settings to a CA Policy).  First, we need an object to hold the Condition for the CA Policy (Applications, Users, and Locations). Breakdown of the available conditions available in ConditionalAccessConditionSet is defined here.
$CAConditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet
$CAConditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition
$CAConditions.Applications.IncludeApplications = ‘All’

In this section, we define the users to apply the Conditional Access Policy to (Users.ExcludeUsers) as well as any users we wish to exclude (Users.ExcludeUsers).  In this case, the excluded user is a Break Glass account that is excluded from any policies we define and is shown below as the Object GUID for the user in Azure AD.  The GUIDs for the locations are in the ID field as seen in Figure 2.
$CAConditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition
$CAConditions.Users.IncludeUsers = ‘All’
$CAConditions.Users.ExcludeUsers = ‘22561a78-a72e-4d39-898d-cd7c57c84ca6’
$CAConditions.Locations = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition
$CAConditions.Locations.IncludeLocations = ‘0743ff81-cea0-40d2-b0f0-4028cdc1c61a’,’0f0c7a7f-4863-480e-9b71-d8f9eddb37e4′

** Be careful with the ‘All’ Applications AND ‘All’ user settings as this does affect the Azure AD Portal as well, which means you could get locked out of the portal and not able to change your CA Policies.  Make sure to have a Break Glass Account created and excluded as shown here [Users.ExcludeUsers].  For more information on Break Glass Accounts, refer to this blog post.

Next, we need to configure Grant Controls for the MFA requirement.  Like the Conditions above we also need a Graph object and provide an operator (‘Or’ / ‘And’) as well as the control, in our case MFA:
$CAControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls
$CAControls._Operator = “OR”
$CAControls.BuiltInControls = “Mfa”

** A list of available BuiltInControls can be found here.

Summary of Policy Settings:

  • Applies to all Cloud Apps
  • Applied to all users in Azure AD
  • Excluded from applying to one account
  • Enforces MFA for these users and these apps
  • Two Names Locations included, where MFA will not be enforced

We now have our $CAConditions object and $CAControls object populated with the required settings and can use this to create a CA Policy per our initial requirements:
New-AzureADMSConditionalAccessPolicy -DisplayName “CloudApps-MFA-CorpWide” -State “Enabled” -Conditions $CAConditions -GrantControls $CAControls

Id              : cb14d13f-6ecb-4113-b684-cb6ace507edd
DisplayName     : CloudApps-MFA-CorpWide
State           : enabled
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:
                    Locations: class ConditionalAccessLocationCondition {
                    IncludeLocations: System.Collections.Generic.List`1[System.String]
                    ExcludeLocations: System.Collections.Generic.List`1[System.String]
                  }

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

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 :
Figure: Output from New-AzureADMSConditionalAccessPolicy cmdlet.

Unfortunately, all the settings put in place for this CA Policy are obfuscated by ‘System.Collections’ as the properties contain complex data sets. To validate settings for the CA Policy we must pick apart each condition to see what is present. Applications, Users and Locations are all sub-properties of the Conditions property on a CA Policy; thus we can break each of these sections down like so:
((Get-AzureADMSConditionalAccessPolicy).Conditions).Applications

IncludeApplications ExcludeApplications IncludeUserActions IncludeProtectionLevels
------------------- ------------------- ------------------ -----------------------
{All}               {}                  {}

((Get-AzureADMSConditionalAccessPolicy).Conditions).Users

IncludeUsers  : {All}
 ExcludeUsers  : {22561a78-a72e-4d39-898d-cd7c57c84ca6}
 IncludeGroups : {}
 ExcludeGroups : {}
 IncludeRoles  : {}
 ExcludeRoles  : {}

((Get-AzureADMSConditionalAccessPolicy).Conditions).Locations

IncludeLocations                                                             ExcludeLocations
----------------                                                             ----------------
{0743ff81-cea0-40d2-b0f0-4028cdc1c61a, 0f0c7a7f-4863-480e-9b71-d8f9eddb37e4} {}

In all cases, Applications, Users and Locations are listed in the Conditional Access Policies as ObjectIds.  If a report were generated for management, additional PowerShell queries would be needed to convert these values to names.  Converting the ObjectIds to names would also help with verification or documenting/auditing CA Policies.

Altering an Existing Conditional Access Policy

Now that we have a CA Policy in place, we can use PowerShell to update Applications, Users, Locations and Controls as well as other unconfigured items like Platforms and Sign-In Risk.

Changing the Enforcement of a CA Policy
One change that could be implemented is changing the state of the CA Policy.  CA Policies have three states: EnabledForReportingButNotEnforced, Enabled and Disabled.  For example, if a new CA Policy is in place and users are prompted for MFA when inside a corporate location, then the policy could potentially be disabled or set to report only until troubleshooting is performed:
Set-AzureADMSConditionalAccessPolicy -PolicyId 21bdd8c1-bb5c-40d1-a4de-926888c69163 -State Disabled
Set-AzureADMSConditionalAccessPolicy -PolicyId 21bdd8c1-bb5c-40d1-a4de-926888c69163 -State EnabledForReportingButNotEnforced

With the policy effectively disabled, IT can now make changes to the policy, validate them, and then re-enable the policy:
Set-AzureADMSConditionalAccessPolicy -PolicyId 21bdd8c1-bb5c-40d1-a4de-926888c69163 -State Enabled

Changing CA Policy Controls
In the previous example, there is a requirement for an MFA prompt when using a cloud app and connecting from outside the two Named Locations.   These controls can also be adjusted if additional security requirements are needed or possible alternatives (Azure AD Joined / Compliance).  Controls on CA Policies can also be combined (AND) versus the one control (OR) that was in the previous example.

For example, if we want to add that when a user accesses a cloud app, while external, they need to do so from a Compliant Device AND they must be prompted for MFA, we can do so by creating a new Control object and then apply this to the existing CA Policy.  A Compliant Device is a device that meets a specified list of criteria that is predefined like OS version level, not jailbroken, etc. First the Controls:
$CAControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls
$CAControls._Operator = “AND”
$CAControls.BuiltInControls = “Mfa”,”CompliantDevice”

Notice that we have an AND operator, which declares that both Controls need to be true.  Also, of note, is that the configured Controls are MFA and a Compliant Device.  These controls are then applied to an existing CA Policy, overwriting any existing settings:
Set-AzureADMSConditionalAccessPolicy -PolicyId 21bdd8c1-bb5c-40d1-a4de-926888c69163s -GrantControls $CAControls

Before:

_Operator BuiltInControls CustomAuthenticationFactors TermsOfUse
 
 OR        {Mfa}           {}                          {}

After:

_Operator BuiltInControls CustomAuthenticationFactors TermsOfUse 

AND        {Mfa, CompliantDevice} {}                   {}

We can now place this in a one-liner like so:
Remove-AzureADMSConditionalAccessPolicy -PolicyId 7ac2fcee-d5bd-4003-ad10-5dfa838417da

No prompt is given, so be careful with the removal of CA Policies.

Named Locations

As mentioned previously, Conditional Access Policies use the concept of Named Locations to correspond to physical locations in an organization’s environment. We can use the Get-AzureADMSNamedLocationPolicy to compare what is shown in PowerShell and what is displayed in the Azure AD portal for Named locations. This is useful for validating a configuration as well as understanding any differences between the two displays:

Using PowerShell to Manage Conditional Access (CA) Policies
Figure 3: Breakdown of a Named location in PowerShell and in the Conditional Access section of AzureAD.

Modify Existing Named Location

Organizations change over time which might mean that changes are needed for named locations. For example, you might need to rename locations, add subnets, remove subnets, mark them as trusted, or remove the trust. All these changes can be performed with the Set-AzureADMSNamedLocationPolicy cmdlet. Let us see what it takes to make each of these changes:

Change Named Location ‘Name’
Set-AzureADMSNamedLocationPolicy -PolicyId 0743ff81-cea0-40d2-b0f0-4028cdc1c61a -DisplayName ‘Chicago Loop Office’
Change IP Range
$ipRanges = New-Object -TypeName Microsoft.Open.MSGraph.Model.IpRange
$ipRanges.cidrAddress = ‘10.25.0.0/16’
Set-AzureADMSNamedLocationPolicy -PolicyId 0743ff81-cea0-40d2-b0f0-4028cdc1c61a -IpRanges $ipRanges -OdataType “#microsoft.graph.ipNamedLocation”
Trusted
Set-AzureADMSNamedLocationPolicy -PolicyId 0743ff81-cea0-40d2-b0f0-4028cdc1c61a -IsTrusted $False
Set-AzureADMSNamedLocationPolicy -PolicyId 0743ff81-cea0-40d2-b0f0-4028cdc1c61a -IsTrusted $True

Removing a Named Location

When offices close or are no longer needed for a Conditional Access Policy, the Named Locations can be removed if there is a desire to do so. Leaving the Named Locations behind does not create a security risk. We first need to determine if there are any existing Conditional Access Policies that contain the location. We can pick these out from the Conditions property of the CA Policy and look at the Locations sub-property, which stores the location as a System.Collections.Generic.List:

Locations: class ConditionalAccessLocationCondition {
IncludeLocations: System.Collections.Generic.List`1[System.String] 
ExcludeLocations: System.Collections.Generic.List`1[System.String]

We can reveal the GUID:
((Get-AzureADMSConditionalAccessPolicy).Conditions).Locations

IncludeLocations ExcludeLocations
---------------- ----------------
{088f361c-4103-43e1-a11d-0394018ab62b} {}

Let us assume we need to remove our Chicago Office, which is a Named Location:

OdataType : #microsoft.graph.ipNamedLocation
Id : 088f361c-4103-43e1-a11d-0394018ab62b
DisplayName : Chicago Office
IpRanges : {class IpRange {
CidrAddress: 10.25.0.0/16
}
}
IsTrusted : True
CountriesAndRegions :
IncludeUnknownCountriesAndRegions :

The ‘Id’ value is what we can use to match to the Locations.IncludeLocations value in the CA. To find any CA Policy with this Named Location, we need to match the value like so:
$OldNamedLocationId = (Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -eq ‘Chicago office’}).Id
$CAPolicies = Get-AzureADMSConditionalAccessPolicy
Foreach ($CAPolicy in $CAPolicies) {
If ($OldNamedLocationId -eq((($CAPolicy).Conditions).Locations).IncludeLocations) {
Write-Host “CA Policy $($CAPolicy.Id) contains the Named Location.”
}
}

We may have only one location, or we may have multiple locations, but all matching entries will be displayed:
CA Policy 4e7dac6d-d471-483f-9677-46407acaa3f5 contains the Named Location.
We can decide to either remove the policy or just remove the Named Location. If the Named Location is the only one, then we would need to replace it to keep the CA Policy. For this example, we will replace the location with another Named Location. First, find any non-Chicago Office Named Locations:
Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -ne ‘Chicago office’} | ft DisplayName,Id

DisplayName Id
----------- --
New York Office 0fae649d-a695-4761-9a83-cd20a96d0739

We then use the ID from this location to replace the one we need to remove:
$OldNamedLocationId = (Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -eq ‘Chicago office’}).Id
$NewNamedLocationId = (Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -eq ‘LA Office Office’}).Id
$conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet
$conditions.Locations = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition
$conditions.Locations.IncludeLocations = “$NewNamedLocationId”
Foreach ($CAPolicy in $CAPolicies) {
If ($OldNamedLocationId-eq ((($CAPolicy).Conditions).Locations).IncludeLocations) {
Set-AzureADMSConditionalAccessPolicy -PolicyId $($CAPolicy.ID) -Conditions $Conditions
}
}

Now we re-run the same code block we ran to find the CA Policies with the Named Location:
$NamedLocationId = (Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -eq ‘Chicago office’}).Id
$CAPolicies = Get-AzureADMSConditionalAccessPolicy
Foreach ($CAPolicy in $CAPolicies) {
If ($NamedLocationId -eq((($CAPolicy).Conditions).Locations).IncludeLocations) {
Write-Host “CA Policy $($CAPolicy.ID) contains the Named Location.”
}
}

Now no results are returned, and we are safe to remove the Named Location:
Remove-AzureADMSNamedLocationPolicy -PolicyId $OldNamedLocationId

**Tip: Make sure to remove a Named Location from a Conditional Access Policy
If we try to remove a Named Location that is defined in a Conditional Access Policy, an error is generated. This is because the Named Location is attached to the Conditional Access policy and needs to be removed first.

Using PowerShell to Manage Conditional Access (CA) Policies
Figure 4: Attempting to remove a Named Location before removing it from a Conditional Access policy.

Final Thoughts

From the article, we can see that Microsoft provides a set of PowerShell cmdlets that provide a convenient access point to Conditional Access Policies. These CA Policies can be created, modified, and even removed as with these cmdlets. We also have cmdlets to create Named Locations, which can, in turn, be used by the Conditional Access Policies. Potential uses for these cmdlets span from creation and management of CA Policies to documentation and auditing of Policies for security personnel/consultants needing to verify the security stance of an organization. Make sure to read the documentation links provided in this article as well as the Get-Help for the cmdlets for guidance on values to be used for the various moving parts of a policy – Locations, Platforms, Grant Controls, Session controls, and more.

About the Author

Damian Scoles

Damian Scoles is an eight-time Microsoft MVP, specializing in Exchange, Office 365 and PowerShell. He is currently based out of the Chicago area and started out managing Exchange 5.5 and Windows NT. He has worked with Office 365 since BPOS and has experience with Azure AD, Security and Compliance Admin Centers, and Exchange Online. Contributions to the community include helping on TechNet forums, creating PowerShell scripts that are located in the TechNet Gallery, writing detailed PowerShell / Office365 / Exchange blog articles (https://www.powershellgeek.com), tweets (https://twitter.com/PPowerShell) and creating PowerShell videos on YouTube (https://www.youtube.com/channel/UClxHtLF0c_VAkjw5rzsV1Vg). He has written five PowerShell books and is actively working on the Microsoft 365 Security for IT Pros book as well.

Comments

  1. Olu Omolola

    Many thanks for your help in putting things together. Please how can I use this to extract Ipranges and output to a txt or csv file? Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -ne ‘Chicago office’} | ft DisplayName,Id

    Get-AzureADMSNamedLocationPolicy | Where {$_.DisplayName -ne ‘London office’} | ft DisplayName,Id,IpRanges but not getting the desired list of the IPs complete. Please can you help? Many thanks

  2. daye

    How to convert the conditional access user/exclude user’s objectID to displayname or userprincipalname?

    If I use $policyobjecitID.condition.user.excludeuser, I got all the exclude users objetID, how to convert them to azureAD displayname or Principalusername?

    Thank you.

  3. daye

    Thanks for the great article. Question,

    If I want to list users/exclude users, I can run this:
    $condtionalaccesspolicyID.condition.users
    $condtionalaccesspolicyID.condition.users.excludeUsers,

    I just got the ObjectID, not the displayname or UserPrincipalname, How I can convert it into displayname or userprincipal name ? Thanks.

  4. Sourav

    Hi,

    Great article!

    Quick question –
    In the summary of the policy settings you have mentioned – “Two Names Locations included, where MFA will not be enforced”.

    Shouldn’t it be “….. where MFA will be enforced” instead of “will NOT be”, since you are including those 2 locations in your policy?

    Thanks,
    Sourav

  5. Silviu

    Great stuff written here. Keep it up!

  6. Matthew Prentice

    Looks like a typo early in the article.

    **Note that both the AzureAG and AzureADPreview PowerShell modules contain these cmdlets.

    I assume that should be “AzureAD” not “AzureAG”.

  7. Ravi Mohindroo

    Thanks for such a great Article, I need some help with the CountryAndRegion.

    I just hope there is a simple way to add the country to the existing policy using powershell.
    can’t use @{add=”alias”} this doesnt work here, may be the API doesnt support it.

    PS C:\> Set-AzureADMSNamedLocationPolicy -PolicyId 17axxxa3-81d6-4c96-xxxx-ae37f65xxxx -OdataType “#microsoft.graph.countryNamedLocation” -IncludeUnknownCountriesAndRegions $false -CountriesAndRegions @{Add =”IN”} Set-AzureADMSNamedLocationPolicy : Cannot bind parameter ‘CountriesAndRegions’. Cannot create object of type “Microsoft.Open.MSGraph.Model.CountriesAndRegion”. The Add property was not found for the
    Microsoft.Open.MSGraph.Model.CountriesAndRegion object. The available property is: [value__ ]
    At line:1 char:196
    + … deUnknownCountriesAndRegions $false -CountriesAndRegions @{Add =”IN”}
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [Set-AzureADMSNamedLocationPolicy], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Open.MSGraphBeta.PowerShell.SetAzureADMSNamedLocationPolicy

Leave a Reply