Regex and PowerShell Recap

Regular Expressions

Regular Expressions, shortened as regex, are sequences of characters that defines a search pattern. We can use these search patterns to find strings. This blog aims to capture some of what I’ve learned about Regex. I learned Regex by watching Thomas Rayner speak at some PowerShell usergroups:

These are great presentations and were recommended to me by multiple people.

Regex Applied in PowerShell

RegEx is fine on it’s own, but it’s much better when it’s applied and used.

Select-String

Select-String can be used to search for regular expressions. * is implied for this, so using simple strings works fine. This is PowerShell’s alternative for grep, kinda sorta.

There is a useful parameter, -context, which allows you to specify the lines before and after the match.

$path = (Get-PSReadLineOption).HistorySavePath
Select-String -path $path -Pattern 'password|asplaintext|token|key|secret' -context 1,1 # grab 1 line before and after

Switch -Regex ($string)

PowerShell’s Switch statement has a regex flag that you can specify. This allows you to match the variable to a bunch of different regex conditions and execute code

$PhoneNumber = '911'

Switch -Regex ($PhoneNumber) {
    '^911$' { Write-Host 'Emergency Number' }
    '\d{3}.\d{3}.\d{4}' { Write-Host 'Standard number' }
}

Emergency Number

Filter an Array with Where-Object and -Match

This example shows a simple filter using-Match. When comparing an array with -Match, it returns the values that match the pattern. If 1 item is compared with -match it only returns a true or false

Compare an array with -match

$array = @('somethingone', 'somethingtwo', 'noway')
$array -match 'something'

somethingone
somethingtwo

Compare an item with -match

This returns a boolean.

'lego' -match 'faygo'
False

Boolean -matching

The output is true because the regex patter something is found in the string on the left.

 'somethingone' -match 'something'
 True

The regex pattern pickles isn’t found anywhere in the string somethingone.

'somethingone' -match 'pickles'
False

Simple Replacements

To replace, we can make use of the -replace operator. This operator accepts 2 arguments: the regex pattern and the string to replace it with.

'Here is a simple string.' -replace 'simple string', 'string that got something replaced'
Here is a string that got something replaced.

Parameter/Variable Validation

Using regex to validate parameters is possible with [ValidatePattern('<pattern>')]. This can be put into a parameter block of a script or function, but it can also be used on variables. Once a variable is declared with the ValidatePattern attribute the value of the variable must always match the pattern specified or else it will throw an error.


[ValidatePattern('^fan$')]$Appliance = 'fan

$Appliance = 'icemaker'

An error is thrown

MetadataError: The variable cannot be validated because the value icemaker is not a valid value for the Appliance variable.

[Regex] Class

The [Regex] class has some useful methods for dealing with regex

[regex]::Match()

The match method searches an input string for a substring that matches a regular expression pattern and returns the first occurrence as a single match object.

[regex]::Match('Bond. James Bond.', 'James\sBond').Value
James Bond

[regex]::Matches()

The matches method searches an input string for all occurrences of a regular expression and returns all of the matches, unlike the match() method.

This example searches the specified input string for all occurrences of a specified regular expression. The specified regular expression is looking for \w+ which is one or more word character, followed by a $, which represents hte end of the line.

Matches(String, String)

Searches the specified input string for all occurrences of a specified regular expression.

[regex]::Matches('domain\username', '\w+$').value
username

-Match

-Match and it’s oppsite, -NotMatch are used to compare a string to a regular expression.

'Bond. James Bond.' -match  '(James)\s(Bond)'
True

The builtin variable, $matches is available with everything that matched. The output of $matches is below.

Name                           Value
----                           -----
2                              Bond
1                              James
0                              James Bond

RegEx Basics

* Character

Tells you that we want 0 or more of what comes before it. There are 0 or more s characters before omething.txt so this is True

' omething.txt' -match 's*omething.txt'
True

+ Character

The + stands for 1 or more of the preceding character. In this example there is NOT 1 or more s character(s) at the beginning of the string.

'omething.txt' -match 's+omething.txt'
False

? Character

? stands for 0 or 1 of the preceding character.

'something.txt' -match 's?omething.txt'
True

Special Symbols

The Magic Wand

Thomas affectionately refers to the \ symbol as a magic wand that bonks whatever character follows it. Look out for the \ as you use regex! It is also used as an escape character.

Character Classes

Character classes are strings (case-sensitive) that define certain things in a pattern

| character | description | example (True) | |—|—|——–| | \w | word character [a-zA-Z_0-9] | 'hi123' -match '\w' | | \W | non-word character [^a-zA-Z_0-9] | '...' -match '\W' | | \d | Digit [0-9] | '1' -match '\d' | | \D | non-digit [^0-9] | 'word' -match '\D' | | \n | new line | “n" -match "\n" | | \r | carriage return | "r” -match “\r” | |\t | tabulation | “t" -match "\t" | |\s | white space | ’ ‘ -match ‘\s’ | |\S | non-white space | ‘abc’ -match ‘\S’` | |\A | beginning of the string (multi-line match) | “bob” -match “\Ab” | |\Z | end of the string (multi-line match) | “bob” -match “b\Z” | |\b | word boundary, boundary between \w and \W | |\B | not a word boundary | |< | beginning of a word | |> | end of a word |

Values

character description example (True)
. matches any character except newline 'light' -match 'l.ght'
“string” matches a literal string 'string' -match 'st'
[abc] matches at least one of these 'b' -match '[abc]'
[^abc] matches characters except these 'd' -match '[^abc]
[a-z] match any letter in range 'v' -match '[a-z]'

Quantifiers

Specify how many of times to match on.

character description example (True)
{n} matches exactly n times 'aa' -match 'a{2}'
{n,} matches a minimum of n times  
{x,y} matches a min of x and max of y  
* matches 0 or more times ‘abc’ -match ‘*a’
+ matches 1 or more times  
? matches 1 or 0 times  
*? matches 0 or more times, but as few as possible  
+? matches 1 or more times, but as few as possible  
?? matches 0 or 1 time  

Quick Reference

character description example (True)  
\ escape character    
^ beginning of a line “bob” -match “^b”  
$ end of a line “bob” -match “b$”  
(a|b) ‘a’ or ‘b’ ‘aaa’ -match ‘(a b)’

Curly Braces { }

Curly braces act like a custom quantifier. The quantity of what comes before it is put inside the curly braces.

This output is true because \d represents a digit and there are 3 of them.

'something123' -match '\d{3}'
True

Round Brackets ( )

Round brackets are used to group.

The grouping contains the string hello123 and the 2 for the custom quantifier specifies that anything that comes before it must occur 2 times.

'hello123hello123' -match '(hello123){2}'
True

Square Brackets [ ]

Square brackets denote a set. One of the values in the square brackets should match in order to be a match.

In this example, we are looking for f,g, or h, followed by the end of line character, which is denoted by $.

'something' -match '[fgh]$'
True

Named Capturing Groups

The <> characters can be used to assign tags to groups

$pat = '(?<first>James)\s(?<last>Bond)'
$match = [regex]::Match('Bond. James Bond.',  $pat)
# Output is stored in the Groups property and has a nice tag for first and last
$match.Groups.First