Home > Net >  Escape special characters for regex pattern in Powershell
Escape special characters for regex pattern in Powershell

Time:08-02

I'm writing a Powershell script to check for a list of passwords that meet a specific password policy. In this case at least 7 characters, at least 1 upper case letter, at least 1 lower case letter, and a special character to include white space. This is the regex I currently have:

(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*_\- =`|\\\(\)\{\}\[\]:;"'<>,.?\/\s\/])[A-Za-z\d[~!@#$%^&*_\- =`|\\\(\)\{\}\[\/\]:;"'<>,.?\s]{7,}$

I've tested the pattern on regex101 with some password strings that match the above stated policy and it works. Where I'm getting lost is when I plug the pattern into Powershell, Powershell is seeing the quotes/apostrophes as such, instead of characters to search for in the regex pattern. How do I go about escaping these characters so Powershell knows to include them in the regex pattern?

CodePudding user response:

PowerShell has no special syntax for representing regex literals - they are simply represented as string literals.

The simplest solution, which doesn't require escaping (of quote characters, ` or $) in your regex, is to use a verbatim here-string:

# The middle line is your original regex, as-is.
$regex = @'
(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*_\- =`|\\\(\)\{\}\[\]:;"'<>,.?\/\s\/])[A-Za-z\d[~!@#$%^&*_\- =`|\\\(\)\{\}\[\/\]:;"'<>,.?\s]{7,}$
'@

Note that no characters (other than whitespace) may follow the opening delimiter, @', and that the closing delimiter, '@, must be on its own line, at the very start of that line (not even whitespace may precede it).

The alternative is to use a regular (single-line) verbatim (single-quoted) string ('...'), in which case the only character you need to escape is ' itself, namely as '':

# Note how both embedded instances of ' are escaped as ''
$regex = '(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*_\- =`|\\\(\)\{\}\[\]:;"''<>,.?\/\s\/])[A-Za-z\d[~!@#$%^&*_\- =`|\\\(\)\{\}\[\/\]:;"''<>,.?\s]{7,}$'

CodePudding user response:

Doing this with a single regex makes for a complex and hard to read regex. Make several smaller tests, and they are easier to read - and you can provide a good error message because you can tell which one failed:

at least 7 characters

$pass.Length -ge 7

at least 1 upper case letter

$pass -cmatch '[A-Z]' (cmatch is case sensitive)

at least 1 lower case letter

$pass -cmatch '[a-z]'

and a special character to include white space.

$pass -match '\W' (\W is not word characters; not a letter or digit)


There is also [regex]::Escape($Text) which will escape characters in a string that could be interpreted by the regex engine as patterns. You would still need to handle quotes and backticks when writing the $Text variable so that the PowerShell string processor does not get confused; use a single quoted string and you only need to escape single quotes inside it.


Do note that NIST password guidelines recommend against this kind of password complexity testing, and instead recommend only:

  • at least 12 characters.
  • checked a list of passwords found in breaches, rejected if it's one of those.
  • Related