Since the summer of 2020, the AzureAD PowerShell module provides cmdlets that can help you manage Conditional access policies. This can give you some nice options to backup, document and restore Conditional access policies. In my opinion, the PowerShell cmdlets aren’t all that intuitive, which is the reason I want to show in this post how to backup and restore Conditional Access Policies with PowerShell.
AzureAD module or the Graph API?
The cmdlets we are going to use today are part of the AzureAD module. I assume they are a wrapper around the Graph API, which also makes it possible to manage Conditional Access Policies. You do have the option to call the API directly from PowerShell. (To learn more about how, see my previous post.)
So which should you choose? Practically, there are some advantages on using the Graph API. The biggest one being that it works natively in PowerShell 7+, where the AzureAD module doesn’t. And automation running in for example Azure Functions is more clean thanks to working with a service principal.
If you would like to use PowerShell 7 and a Service Principal without learning the API, you could consider the DCToolbox module.
In my opinion, using the AzureAD module is the best way to go if you want to call these scripts interactively. Authentication through Connect-AzureAD is a breeze compared to the service principal approach you need for the Graph API. So if that is your use case, the AzureAD module is the way to go.
Prerequisites and limitations
The cmdlets we are going to use are part of the AzureAD PowerShell module. You can install the module from the PowerShell gallery by using
Install-Module AzureAD
After you have installed the module, you can import it and connect to your tenant
Import-Module AzureAD
Connect-AzureAD
An Authentication windows will pop up and you can authenticate as usual.
There are some limitations to keep in mind though:
PowerShell 5.1
AzureAD is officially not supported in PowerShell 7+. You are able to install the module, but you are not able to authenticate. So you have to use Windows PowerShell. There is more information on that here.
You should be able to use the module in PowerShell 7+ by using Windows PowerShell compatibility, but you do need Windows PowerShell on the device.
Import-Module AzureAD -UseWindowsPowerShell
The AzureAD module works natively in Cloud Shell, but the current version does not have the Conditional Access cmdlets available at the time of writing.
Preview policies
When you run the scripts to backup and restore Conditional Access Policies, all policies that are in Preview will not be touched. You do not get warned on this, you will just get an incomplete list.
To work around this, you can use the AzureADPreview module, as this module does collect the policies that are in preview. Read more about it here.
Backup up Conditional Access policies
Enough talking, let’s start working with the policies.
Our first goal is to create a backup for all the policies.
I did some experimenting with this and found the cleanest way to store the policies is by using JSON files. I did try to get a clean overview in a CSV, as that might be helpful as documentation. But there is too much layering in the objects to get a nice view. The JSONs are pretty readable with the right editor (like Visual Studio Code).
With the following code, you can create the backup files. All files will be saved as the Conditional Access ID.
Restore Conditional Access policies
While creating the backup was pretty straightforward, it is a bit more work to use those files to create new Conditional Access policies. The reason is that the policy object in PowerShell is divided into pretty specific types. If you use the following code, it will create new policies based on all the policies you just stored in JSON. By using the Prefix parameter, you can rename the policies, for example by adding restore in front of the name.
Remove existing policies
If you run above script, it will create all policies again, even if they already exist. So If you want to overwrite the existing policies, it might be a good idea to first remove the policies that you had backed up. You can do that by using the following code:
Note: There is no check on the Remove-AzureADMSConditionalAccessPolicy cmdlet. Be careful that you do not remove items you wanted to keep
Conclusion
So this is how you can Backup and restore Conditional access policies with PowerShell. I think it is great there is finally automation around the policies available, so you are able to make this part of your infra as code, to ease migrations or to set up a business standard.
Pingback:HOWTO: Get rid of the Conditional Access Baseline Policies in your Azure AD tenant - The things that are better left unspoken
Pingback:Bug in Get-AzureMSConditionalAccessPolicy cmdlet? | F12
Great post! works like a charm
This worked like a charm for so long up until Friday (2021-04-16) where I’m running into errors that the User and Applicaton cannot be found within the object:
Anyone know what might’ve changed recently? Thanks!
Cannot convert value “@{Applications=; Users=; Platforms=; Locations=; SignInRiskLevels=System.Object[];
ClientAppTypes=System.Object[]}” to type “Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet”. Error: “Cannot
convert value “@{IncludeApplications=System.Object[]; ExcludeApplications=System.Object[];
IncludeUserActions=System.Object[]; IncludeProtectionLevels=}” to type
“Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition”. Error: “Cannot convert the
“@{IncludeApplications=System.Object[]; ExcludeApplications=System.Object[]; IncludeUserActions=System.Object[];
IncludeProtectionLevels=}” value of type “System.Management.Automation.PSCustomObject” to type
“Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition”.””
At C:\Restore-ConditionalAccessPoliciesScript.ps1:41 char:5
+ [Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet]$Cond …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastConstructorException
The property ‘Users’ cannot be found on this object. Verify that the property exists and can be set.
At C:\Restore-ConditionalAccessPoliciesScript.ps1:55 char:5
+ $Conditions.Users = $Users
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
The property ‘Applications’ cannot be found on this object. Verify that the property exists and can be set.
At C:\Restore-ConditionalAccessPoliciesScript.ps1:66 char:5
+ $Conditions.Applications = $Applications
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
Ah, found a fix. Looks like new backups or exports will contain CreatedDateTime, ModifiedDateTime and a new Devices property. Restoring using the new backup .json files seems to do the trick!
So you mean that you can’t restore an old json anymore? That is good to know!
Thank you for your comment, I will look into the script to check when I find time!
I am trying to put this in AzureAutomation runbook. RunAsAccount/ServicePrinciple is having Conditional Access administrator and API permissions to read/write conditional policies – But still getting this error:
>>>>>
Get-AzureADMSConditionalAccessPolicy : Error occurred while executing GetAzureADMSConditionalAccessPolicies
Code: AccessDenied
Message: You cannot perform the requested operation, required scopes are missing in the token.
InnerError:
RequestId:
DateTimeStamp:
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed
At line:21 char:16
+ $AllPolicies = Get-AzureADMSConditionalAccessPolicy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-AzureADMSConditionalAccessPolicy], ApiException
+ FullyQualifiedErrorId :
Microsoft.Open.MSGraphV10.Client.ApiException,Microsoft.Open.MSGraphV10.PowerShell.GetAzureADMSConditionalAccessPolicy
Hi Mavi,
How did you handle the authentication?
In the example I showed, the authentication is done interactively. You can’t do it like that in a runbook.
In this forum is some guidance on how to handle it in a runbook: https://social.msdn.microsoft.com/Forums/azure/en-US/5a596b5c-c7f6-4e22-9568-24b12d7d9588/connectazuread-in-azure-automation-runbook?forum=azureautomation
I am currently having an issue where the cmdlet only retrieves three of my policies and I have eight. Is there a limitation with the cmlet Get-AzureADMSConditionalAccessPolicy?
Hi John,
Could it be that the policies you do not see are in preview?
This is a known limitation with using the regular AzureAD module. As a workaround you can try the AzureADPreview module. Read more about it here.
Hi,
Great scripts!
But it seems to only half work when importing my CAP’s – Some fail with the error:
Message: 1061: ‘devices’ condition must specify the device states to include. Did you intend to include ‘all’?
It seems to only effect policies where there is “no” device state configured within the Conditional Access Policy.
A policy that has device state configured, do not import. Only the policies without the device state configured are imported again.
The ones that do import OK, import fine into the same tenant in which they were exported from.
Which brings me to another question; When importing CAP’s into another tenant, they all fail, the idea (at least for me) is to simplify the creation on CAP’s when creating new MS365 tenants for different clients.
Do you know of anyway to achieve this?
Cheers,
F
Pingback:get azureadmsconditionalaccesspolicy - loginfinance.com
Do you happen to know the graph version of this one?
Thanks everyone for the interest in Conditional Access PowerShell and raising the issue. Due to the planned deprecation of PowerShell modules (MSOL & AAD) after December 2022, no further updates are planned for these modules to support new Conditional Access features. See recent announcements for more information: https://aka.ms/AzureADPowerShellDeprecation. As a result of this, newer Conditional Access features may not be available or may not be functional within these PowerShell modules as a result of this announcement. Please consider migrating to Microsoft Graph PowerShell (https://aka.ms/MigrateMicrosoftGraphPowerShell). Additional guidance and examples will be released soon and will replace the current Azure AD PowerShell examples.
Hi,
MS broke the export since they included Linux in the “Device Platforms” option in a CA rule.
If you have selected “any device” it will include linux and the script you kindly provided throws this error:
Get-AzureADMSConditionalAccessPolicy : Error converting value “linux” to type
‘Microsoft.Open.MSGraph.Model.ConditionalAccessDevicePlatforms’. Path ‘value[2].conditions.platforms.excludePlatforms[3]’, line 1, position
2870.
At line:13 char:16
+ $AllPolicies = Get-AzureADMSConditionalAccessPolicy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-AzureADMSConditionalAccessPolicy], ApiException
+ FullyQualifiedErrorId : Microsoft.Open.MSGraphV10.Client.ApiException,Microsoft.Open.MSGraphV10.PowerShell.GetAzureADMSConditionalAcces
sPolicy
Can you assist in the fix of this error
I’m having this issue too. Does anyone know the resolution?
I’m going to see if I can find time for this. If anyone else has some answers, let us know!
Any CA policy that includes Linux Device types causes this error with Get-AzureADMSConditionalAccessPolicy.
As a workaround were using PowerShell Graph to create a csv of the existing policies then read from the csv the Policy Name and GUID and back them up one by one instead.
Something like: $PolicyJSON = Get-AzureADMSConditionalAccessPolicy -PolicyID $_.PolicyID
Switching to PowerShell Graph for backup would probably be the better long term solution
Excellent writeup and works like a charm!