Active Directory Password Complexity Check – #PowerShell #MVPHour

Ever need to check the complexity of a password that will be used in AD? Ever need to import a list of users or reset their passwords in AD from a predefined list that has been given to you? I have updated my code for my AD Password Complexity check. Check it out.
First off before we can talk about complex passwords, we need to all understand what the criteria of a complex password for an Active Directory account is. It’s quite well defined here – https://technet.microsoft.com/en-us/library/cc786468(v=ws.10).aspx .

As that link exists on the Internet, everyone has their own interpretation and implementation. In my implementation I’ve skipped over looking at the password history. I’m only checking to see that the password is the minimum length and that it follows the complexity rules (if set in AD). Using the link above, here is a summary of the complexity rules:

Passwords must not contain the user’s entire samAccountName (Account Name) value or entire displayName (Full Name) value. Both checks are not case sensitive:

The samAccountName is checked in its entirety only to determine whether it is part of the password. If the samAccountName is less than three characters long, this check is skipped.

The displayName is parsed for delimiters: commas, periods, dashes or hyphens, underscores, spaces, pound signs, and tabs. If any of these delimiters are found, the displayName is split and all parsed sections (tokens) are confirmed not to be included in the password. Tokens that are less than three characters in length are ignored, and substrings of the tokens are not checked. For example, the name “Erin M. Hagens” is split into three tokens: “Erin,” “M,” and “Hagens.” Because the second token is only one character long, it is ignored. Therefore, this user could not have a password that included either “erin” or “hagens” as a substring anywhere in the password.

Passwords must contain characters from three of the following five categories:

Uppercase characters of European languages (A through Z, with diacritic marks, Greek and Cyrillic characters)

Lowercase characters of European languages (a through z, sharp-s, with diacritic marks, Greek and Cyrillic characters)

Any Unicode character that is categorized as an alphabetic character but is not uppercase or lowercase. This includes Unicode characters from Asian languages.

Now that we are on the same page of what AD Complexity means, let’s look at some code I wrote.

A Look at the Code

First off, we need to get the password complexity of the AD. So let’s import the ActiveDirectory module and get the password Default Domain Policy setting.

Code Preparation

Import-Module ActiveDirectory

To make this code re-usable, I’ll create a function called Test-PasswordForDomain. As you’ve seen from the complexity rules above, I’m going to pass in some variables, but only one is manadory, the password! The other 3 parameters are optional, but will help increase the chances of your password passing the AD complexity rules. If you look above, you’ll see that part of the complexity check is to ensure that the password does not contain the SamAccountName or any part of the display name in the password. If you don’t have those, we can check the other complexity rules, but again, it can’t fully ensure that Active Directory will accept your password.

Check 2 – Is the SAM Account Name part of the Password

Check 3 – Is the Display Name part of the Password

Now this is still a simple check, but you have to read the text above that Microsoft provides. It says if ANY PART of the display name that is split by the characters below, the password should fail the complexity rules.

Check 4 – Complexity Rules for the Password

The code makes sense, but we need to make sure that we satisfy as many combinations of the complexity rules defined above.

First cmatch “[A-Z\p{Lu}\s]” – Match any UPPERCASE characters A-Z and spaces, but the funky \p{Lu} also means any UNICODE (accented characters) that are also upper case

Second cmatch “[a-z\p{Ll}\s]” – Match any lowercase characters a-z and spaces (Yes I know I check twice for spaces), but the funky \p{Ll} also means any UNICODE (accented characters) that are also lower case

[\d] – We found a numerical digit [0-9]

[^\w] – \w means [A-Za-z _]. So with a ^ in the front it’s basically saying, any other character. Example: !@#$%^&*()[];

Pretty simple right?

Looks like we fulfilled these Microsoft requirements

Uppercase characters of European languages (A through Z, with diacritic marks, Greek and Cyrillic characters)

Lowercase characters of European languages (a through z, sharp-s, with diacritic marks, Greek and Cyrillic characters)

Any Unicode character that is categorized as an alphabetic character but is not uppercase or lowercase. This includes Unicode characters from Asian languages. Honestly, I did not test this, it may work with the \p{Ll or Lu} test.

About The Author

Allan's IT career has moved him to several Canadian provinces and even to Sweden for four years. He has been nominated for the Cloud and Datacenter Management Microsoft MVP. Due to his Veeam experience in backup, restore, and DR scenarios, Veeam has accepted Allan into the Veeam Vanguard program.
Allan has always been a senior member and key player in implementing Windows infrastructure projects, virtualized platforms (Hyper-V and VMWare) and cloud projects. His love is building roadmaps and lifecycle of the Windows Server environments, DR, automation and the development of ITIL processes for OSD, configurations, and performance.
He is an expert at scripting solutions and has an uncanny ability to reduce complexity and maximize the functionality of PowerShell. Allan has recently rejoined the TriCon Elite Consulting team again as a Principal Consultant.
Allan can be found on twitter @AllanRafuse and blogs on http://www.checkyourlogs.net

on the other hand, your code test for all 4 rules, so password that match only 3 categories will fail the test while it is acceptable to AD. the easy way got to overcome this will be to + instead of “and” and check if the sum is more than 3 ($true = 1, $false = 0), so the code may look like this:

@Lukas – You are 100% correct about not requiring the if statements. I usually add the few lines of extra code as debugging RegEx statements (and others) can sometimes be tedious. Creating a full body for the If/Else statement allows me to then in production code or while debugging, write out to the console or error files. Thanks for your comment.

It seems your code is accepting the password in clear text while testing it for the pre-defined password complexity rules.

However, in reality AD stores user’s password as one-way hash. Is there a way to determine if a given AD user’s password (which is stored as one-way hash) matching a pre-defined password complexity rule.

Microsoft only accept specific ‘special characters’. [^\w] will match any, including spaces, EUR or British Pound.

This is what I’d suggest, building on the 3-out-of-4 comment from Lukas – note in addition to escaping the Regex you need to replace the ‘]’ because otherwise the ‘]’ will close the regex in the if statement.

About

Checkyourlogs is a community blogging platform that focuses on the most current Microsoft and surrounding technologies. All of our bloggers are real-world experts, Microsoft MVPs, Cisco Champions, Veeam Vanguards and more. All views expressed on this site are independent.