How to manage Entra ID’s banned password list via the Graph SDK for PowerShell

Entra ID’s password protection feature was introduced back in 2018, adding support for a banned password list, the smart lockout controls and integration with on-premises AD. Programmatic access to the feature was enabled via directory settings templates, which at the time were exposed via the Azure AD Preview PowerShell module, as we covered here. To date, the set of directory setting templates and the corresponding directory setting objects remain one of the most convoluted parts of the service, so in this article I want to show you how we can manage them via the Graph SDK for PowerShell. Well, at least when it comes to the Password Rule Settings template, which hosts the password protection settings.

I’ll try to keep this article short, so if you need a refresher on how directory settings (and templates) work, consult the official documentation articles linked above. Or check out this recent article where we explored a the process of working with Group settings. In fact, you can even use the “group” templates to manage password protection settings, as we will see later on.

Short introduction and prerequisites

First things first, this is still BETA functionality. What, you thought 7 years is enough for Microsoft to mature a feature to GA status? OK, maybe I wasn’t entirely honest here. There is in fact a v1.0 method we can use, as we will detail a bit later, but as it’s name has nothing to do with directory settings, it’s no surprise people do not know about it. It is in fact the group settings method we detailed in our previous article. Unlike that scenario however, when it comes to password protection settings, we only have a single instance to check, as after all such settings are only configurable on the tenant level.

The corresponding directory setting template is named Password Rule Settings and has a TemplateId value of 5cf42378-d67d-4f36-ba46-e8b86229381d. While the password protection feature requires Entra ID Premium licensing, in theory that is, the directory setting template object should be available for all tenants. Apart from the license requirements, you will also need permissions, namely the Directory.Read.All scope for querying the template and corresponding settings object, and Directory.ReadWrite.All to manage their values.

You can fetch the template object and its properties via the Get-MgBetaDirectorySettingTemplate cmdlet:

Get-MgBetaDirectorySettingTemplate -DirectorySettingTemplateId 5cf42378-d67d-4f36-ba46-e8b86229381d | select -ExpandProperty Values | select Name, Description, DefaultValue

Name                                Description                                                                                                DefaultValue
----                                -----------                                                                                                ------------
BannedPasswordCheckOnPremisesMode   How should we enforce password policy check in on-premises system.                                         Audit
EnableBannedPasswordCheckOnPremises Flag indicating if the banned password check is turned on or not for on-premises system.                   true
EnableBannedPasswordCheck           Flag indicating if the banned password check for tenant specific banned password list is turned on or not. true
LockoutDurationInSeconds            The duration in seconds of the initial lockout period.                                                     60
LockoutThreshold                    The number of failed login attempts before the first lockout period begins.                                10
BannedPasswordList                  A tab-delimited banned password list.

BannedPasswords

Before we proceed with configuring the feature, let’s first cover what the available settings do:

  • LockoutThreshold sets the maximum value of sign-in attempts after which a given user will be temporary locked out.
  • LockoutDurationInSeconds configures the time span for which the account will be locked, in seconds.
  • EnableBannedPasswordCheck toggles the use of the Custom banned password list.
  • BannedPasswordList contains the set of prohibited password values, in a tab-delimited list.
  • EnableBannedPasswordCheckOnPremises extends the password protection feature to on-premises AD.
  • BannedPasswordCheckOnPremisesMode defines whether to audit or enforce the password protection features in your on-premises AD.

Additional details about the settings above and their accepted values can be found in the official documentation.

Creating a new password protection configuration

If you haven’t made any customizations to the password protection feature, no corresponding directory setting object should exist, and we can go about creating a new one via the New-MgBetaDirectorySetting cmdlet. We of course need to reference the “parent” settings template object, shown in the example above, as well as provide values for the set of settings within the template. Do note that ALL the settings are required, i.e. you must provide values for them.

In this example we enable the custom banned password list and add few prohibited password values to it, while configuring the default values for the remaining settings. One thing to note is that the list of banned passwords should be tab-separated, and the maximum number of entries you can add is limited to 1000.

$params = @{
	templateId = "5cf42378-d67d-4f36-ba46-e8b86229381d"
	values = @(
		@{
			name = "EnableBannedPasswordCheck"
			value = "True" 
		}
		@{
			name = "BannedPasswordList"
			value = @("password","Password","P@ssword","P@ssw0rd") -join [char]9
		}
		@{
			name = "LockoutDurationInSeconds"
			value = "600" 
		}
		@{
			name = "LockoutThreshold"
			value = "10" 
		}
		@{
			name = "EnableBannedPasswordCheckOnPremises"
			value = "False" 
		}
		@{
			name = "BannedPasswordCheckOnPremisesMode"
			value = "Audit" 
		}
	)
}
 
New-MgBetaDirectorySetting -BodyParameter ($params | ConvertTo-Json -Depth 5)

Before I forget, few notes above the input. We need to provide the settings in a JSON-formatted payload, as with most Graph cmdlets, but due to the complexity of the payload, we should not rely on the built-in conversion. In other words, if you pass an PowerShell object, such as in the example above, make sure to pipe it to the ConvertTo-Json cmdlet. The other thing you need to do is to prepare the tab-delimited list of passwords, which in this case we do via the -join operator.

If the cmdlet completes successfully, we the output will indicate that a new directory setting object has been created. We can then examine said object via the Get-MgBetaDirectorySetting cmdlet. You can either note the Id of the settings object from the output of the cmdlet above, filter it based on the template Id, or just get all the directory settings object in the tenant:

#List all directory setting objects
Get-MgBetaDirectorySetting

#Get the Password Rule Settings object we created above
Get-MgBetaDirectorySetting -DirectorySettingId 5b8723c1-164f-4839-afc0-8da16d740423

#Filter based on the TemplateId value
Get-MgBetaDirectorySetting | ? {$_.TemplateId -eq "5cf42378-d67d-4f36-ba46-e8b86229381d"}

#List the setting values
[17:02:58][O365]# Get-MgBetaDirectorySetting | ? {$_.TemplateId -eq "5cf42378-d67d-4f36-ba46-e8b86229381d"} | select -ExpandProperty Values

Name                                Value
----                                -----
BannedPasswordCheckOnPremisesMode   Audit
EnableBannedPasswordCheckOnPremises False
EnableBannedPasswordCheck           True
LockoutDurationInSeconds            600
LockoutThreshold                    10
BannedPasswordList                  password    P@ssword        P@ssw0rd

bannedPasswords1

A keen-eyed observer might notice that the output of the settings object shown above does not match our input values, as we did indeed add four different password strings to the custom blocked passwords list. This is because the service normalizes the passwords first, as detailed for example in this article. Thus, the first two entries in the list, “password” and “Password”, are treated as one. And while we’re on the topic of case-sensitivity, make sure that all payload properties are entered in lower case, i.e. “value”, “name” and so on.

Updating and removing password protection settings

OK, at this point we know how to create and query directory setting objects responsible for the password protection feature. Another thing we need to examine is how to update them, as it is very likely that you will want to add additional entries to the banned passwords list over time. We can go about this in two ways: edit an existing settings object’s values, or remove it and provision a new one. The important thing to remember is that only one such settings object can exist in the tenant, thus the latter scenario mandates that we remove any existing objects first.

To modify an existing directory settings object, we can use the Update-MgBetaDirectorySetting cmdlet. In this example, we fetch the object first, modify its setting values and write it back. In particular we remove one entry from the banner password list and add two new ones. Here’s how:

#Get the existing Password Rule Settings object
$obj = Get-MgBetaDirectorySetting | ? {$_.TemplateId -eq "5cf42378-d67d-4f36-ba46-e8b86229381d"}

#Extract the current list of banned passwords
$passwords = $obj.Values.ToJsonString() | ConvertFrom-Json | ? {$_.Name -eq "BannedPasswordList"} | select -ExpandProperty Value

#Convert to array, filter out passwords we want to remove, add new passwords
$passwords = $passwords -split [char]9 | ? {$_ -ne "password"}
$passwords += "P@ssw0rd123"
$passwords += "P@ssw0rd1234"
$passwords = $passwords -join [char]9


#Write back the updated banned password list to the PowerShell object
($obj.Values | ? {$_.Name -eq "BannedPasswordList"}).Value = $passwords

#Finally, update the Entra ID settings object with the new value
Update-MgBetaDirectorySetting -DirectorySettingId $obj.Id -Values $obj.Values

If everything went as expected the new banned password list should be in effect, which we can confirm by rerunning the Get-MgBetaDirectorySetting cmdlet. Using the same method, we can of course update the other setting values if needed. But as the process of updating directory settings is a bit more involved than it should be, due to factors such as the format used for the settings object itself, or the inability of the Graph SDK for PowerShell to cast it to a proper PowerShell object, you might as well consider removing the existing object and creating a new one, as detailed in the previous section.

Should you decide to go this route, or in general want to revert the password protection settings to their default state, use the Remove-MgBetaDirectorySetting cmdlet to delete any existing directory setting objects. Before doing that, be aware that the process is irreversible, and that the Graph SDK for PowerShell will not ask you for confirmation. Anyway, here’s an example:

#Remove a directory setting object by its Id
Remove-MgBetaDirectorySetting -DirectorySettingId 5b8723c1-164f-4839-afc0-8da16d740423

#Remove the Password Rule Settings object by first fetching it via the corresponding template</pre>
Get-MgBetaDirectorySetting | ? {$_.TemplateId -eq "5cf42378-d67d-4f36-ba46-e8b86229381d"} | % { Remove-MgBetaDirectorySetting -DirectorySettingId $_.Id}

Some additional notes and summary

Before closing out the article, some additional notes are due. First, let’s address the elephant in the room, that is the lack of support for the “v1.0” flavor of the Graph SDK for PowerShell. To put it another way, if you try any of the cmdlets above and do not include the “beta” prefix, you will run into an error. So if you want to use “officially supported” cmdlets, you are out of luck. Maybe.

As we discussed in our previous article, there is an officially supported “v1.0” implementation of the Graph API methods to work with directory settings templates and their corresponding setting objects. However, in the official documentation it is referred to as “group settings”, and understandingly, people assume it only applies to the group-related directory settings. In reality, you can use any of the corresponding methods, and Graph SDK for PowerShell cmdlets, to work with any of the other directory settings templates/directory settings objects.

Add to that the inherent issues of the autogenerated names in the Graph SDK for PowerShell, and you are in for a treat! But the point is, you can indeed use cmdlets from the “v1.0” module to achieve the tasks we examined above. For example, we can use the breathtakingly named Get-MgGroupSettingTemplateGroupSettingTemplate cmdlet to fetch the set of directory setting template objects, instead of the beta Get-MgBetaDirectorySettingTemplate one. For working with the settings object themselves, we can use the set of *-MgGroupSetting cmdlets, instead of *-MgBetaDirectorySetting:

#Fetch the Password Rule Settings directory settings template
Get-MgGroupSettingTemplateGroupSettingTemplate -GroupSettingTemplateId 5cf42378-d67d-4f36-ba46-e8b86229381d | select -ExpandProperty Values | select Name, Description, DefaultValue

#Fetch any non-default password protection configuration
Get-MgGroupSetting | ? {$_.TemplateId -eq "5cf42378-d67d-4f36-ba46-e8b86229381d"} | select -ExpandProperty Values

#Update the password protection configuration
Update-MgGroupSetting -GroupSettingId $obj.Id -Values $obj.Values

And with that, you now know the “officially supported” methods as well. Of course, as password protection settings are one of the rare instances where Microsoft has provided us with an actual UI to configure the directory settings object, you should hopefully never deal with with the methods outlined above. If you do need to manage said settings programmatically though, hopefully this article will be of help. Let me know!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.