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.
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:
** 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:
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.”
}
}
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.
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.
Great article. Question, how can I add a member to condition policy? For example I want to add someone to included or excluded.
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
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.
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.
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
This guy copied your article https://simpleitpro.com/index.php/2021/03/30/using-powershell-to-manage-conditional-access-ca-policies/
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Thanks. It happens (a lot).
Great stuff written here. Keep it up!
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”.
The Real Person!
Author Tony Redmond acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Thanks. We’ve updated the text.
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