Regular expression, commonly referred to as regex, is a powerful tool if you know how to use it. In terms of PowerShell regular expressions, you can find and alter text strings, identify text strings that match, and much more. For example, regex can help you read and analyze a log file — a process that’s horrifying to think about doing manually.
Let’s dive into how regex can help you be l̶a̶z̶i̶e̶r̶ more efficient in your role.
What is regular expression (regex)?
Regular expression is a series of characters that define a search pattern. You can use regex to identify matching text strings. It’s like a really fancy find-and-replace feature that helps you sift through large amounts of data (or text strings) at once. Regular expressions can consist of a single character or a complex combination of characters designed to return broad or very concise results. In other words, it’s built for you to fine tune to meet your needs.
Regular expression works with many text editors and scripting languages, including Notepad++, Visual Studio Code, SQL, Python, Perl, Java, PowerShell, and many more. While some systems include their own flavor of regex, others use standard regex libraries. PowerShell uses .NET regular expressions.
The information in this article focuses solely on the .NET regex engine. While there are many similarities between regex implementations, there can also be several differences between syntax, features, and behavior.
PowerShell regular expression reference sheet
If you’re new to regex and come across a complex regex statement, then you know what true confusion feels like.
Regex is a somewhat standardized shorthand language model that uses special characters, sometimes called metacharacters, to define pattern parameters. I say “somewhat” because different applications and languages use different regex models, which can vary slightly.
To the untrained eye, a regex statement may appear as though a cat walked across a keyboard. However, even those familiar with regex may struggle to read patterns, especially if they don’t work with regex consistently. That’s why it’s nice to keep a cheat sheet handy.
Regex character | Matches |
. | Matches any single character except newline. |
^ | Matches the beginning of a line. |
$ | Matches the end of a line. |
\ | Escapes a trailing special character. |
* | Matches zero or more times, matching as many times as possible. |
+ | Matches 1 or more times, matching as many times as possible. |
? | Repeat 0 or 1 time, as many times as possible. |
?? | Repeat 0 or 1 time, 0 if possible. |
*? | Repeat 0 or more times, as few as possible. |
+? | Repeat 1 or more times, as few as possible. |
\w | Matches alphanumeric character [a–z] [A–Z] [0–9] and underscore. |
\W | Matches a non-alphanumeric character. |
\d | Matches a number character [0–9]. |
\D | Matches any non-number character. |
\s | Matches a whitespace character. |
\S | Matches any non-whitespace character. |
\n | Matches a newline. |
\t | Matches a tab. |
\r | Matches a carriage return. |
\b | Matches a word boundary between word and nonword characters. |
\B | Matches a location that is not a word boundary. |
\A | Matches must occur at the beginning of a string. |
\Z | Matches must occur at the end of a string or before a newline. |
\z | Matches must occur at the end of a string. |
\G | Matches must occur at the point the previous match ended. |
[abc123…] | Matches any character in brackets. |
[^abc123…] | Matches any character not in brackets. |
[a-z] | Matches any character in the range of characters. |
{n} | Matches exactly n times. |
{n,} | Matches at least n times. |
{n,m} | Matches at least n times, up to m times. |
a|b | Matches either a or b. |
(…) | Specifies the pattern as a group. |
Using regex in PowerShell
If you’ve spent any significant amount of time with PowerShell, there's a good chance you’ve already used regex. If you’ve matched or replaced a string, you’ve definitely used regex.
Here are some of the PowerShell commands that use regex:
-match operator
-replace operator
-split operator
Select-String
switch statements with the -regex option
Let’s look at a few basic examples of regex usage in PowerShell. Remember, if you’re wondering what a regex special character does, refer to the table above or any of the other resources linked below.
Matching patterns in PowerShell with regex
The -match
operator identifies input that matches the provided regex pattern. It returns a Boolean value of true if a match is found and false if no match is found. Here is an example of how the -match
operator works.
'Elden Ring is an amazing game!' -match 'amazing'
This command returns true because the pattern ‘amazing’
is found in the string ‘Elden Ring is an
amazing
game!’
Be careful not to confuse -match
with -like
. While -match
uses regex, -like
uses simplified wildcard pattern matching. If we replace -match
with -like
in the previous example, the command returns false
.
The -like
operator attempts to match the pattern ‘amazing’
exactly. It fails because the sentence contains much more than just ‘amazing
.’
If we wanted the above command to work with the -like
operator, we would need to add an asterisk before and after ‘amazing’
for the command to return true.
Here’s a slightly more complex example of utilizing the -match
operator.
'Elden Ring won game of the year in 2022.' -match '\d{4}\.$'
The pattern ‘\d{4}\.$’
indicates that we’re looking for four digits or number characters followed immediately by a period. The $
indicates that the match needs to come at the end of the line. If it doesn’t come at the end of the line, the command returns false.
Replacing strings in PowerShell with regex
The -replace
operator in PowerShell works much like the -match
operator, except when a matching pattern is found, it calls for that pattern to be replaced with a substitute. Here’s the basic format of a -replace
command:
<input> -replace <regex pattern>, <replacement>
Here’s a simple example of a -replace
command that uses variables to store the input.
$halo = 'Halo infinite was great.'
$halo -replace 'was great', 'could have been better'
It’s important to note that the -replace
operator doesn’t overwrite the value stored in the variable. You would need to recast the value of the variable to replace it.
Splitting strings in PowerShell with regex
The -split
operator in PowerShell can split strings into substrings. By default, whitespace is used as the delimiter. However, the delimiter can be set to specific characters, strings, or patterns.
Here are some examples of the -split
operator in use.
-split 'Red Dead Redemption'
'Red,Dead,Redemption' -split ','
'RedzDeadzRedemption' -split 'z'
'Red1Dead2Redemption' -split '\d'
The first example is formatted a bit differently but uses the default whitespace as the delimiter. The second and third examples use ‘,’
and ‘z’
characters as the designated delimiters. The last example uses the ‘\d’
regex special character, meaning any number character is treated as a delimiter.
Using Select-String in PowerShell
The Select-String
cmdlet uses regex to match input from strings and files. If you have data that needs to be cleaned up and formatted, the Select-String
cmdlet is the right tool for the job.
Here’s an example of using the Select-String
cmdlet to identify the names of games in a block of text.
$text = "Mass Effect is a great trilogy. Mass Effect 2 was my favorite, followed by Mass Effect 3. Mass Effect 1 was good, but the gameplay was a bit clunky. mass effect 4 was the game we never got (Andromeda doesn't count!)."
$games = $text | Select-String -Pattern 'Mass\sEffect\s\d' -CaseSensitive -AllMatches
$games.Matches.Value
In this example, we piped the contents of the $text
variable to the Select-String
cmdlet. Using the -Pattern
parameter, we set the regex pattern as ‘Mass\sEffect\s\d’
and set the pattern to be case sensitive with the -CaseSensitive
parameter. We also included the -AllMatches
parameter because only the first match in each line returns by default. The -AllMatches
parameter returns all matches found. We’ve assigned the results of the command to the $games
variable, then called the variable with the .Matches.Value
property to return just the matched values. Notice that ‘mass effect 4’ was not returned because it did not match the case sensitivity requirement.
Here's another example of the Select-String
cmdlet in use. In this example, we have a text file containing random employee data, including the name, username, and employee ID of several employees. We want to extract the usernames contained in the file, but the file is not in a very functional format. We can use the Select-String
command to retrieve only the data we’re looking for and export it to a CSV file.
Here is what our original source file looks like.
Here is the script we’ll use to extract the usernames from the text file.
$file = Get-ChildItem 'C:\Temp\SFEmployeeInfo.txt'
$username = Select-String -Path $file -Pattern 'username:\s(.*)$' | ForEach-Object {$_.Matches.Groups[1].Value}
$userNames = $username.ToLower() | Select-Object @{Name='Name';Expression={$_}}
$userNames | Export-Csv -Path 'C:\Temp\Usernames.csv' -NoTypeInformation
In this script, we’ve assigned our text file to the $file
variable. Then we use the Select-String
parameter with the pattern ‘username:\s(.*)$’
to match the usernames from the file. Next, we pipe the results to the For-EachObject
to return just the matched values (in this case, just the names). Then we convert all the usernames to lowercase format before converting the returned string object to a new object with a Name
parameter. By default, a string object only has a length property, which is what is written to the CSV file if we don’t convert it. Finally, we export data to a CSV file.
Here is the resulting CSV file.
Using switch statements with the -Regex parameter
The switch
statement in PowerShell uses exact matching by default, but we can employ the -Regex
option to force it to use regex instead. Switch
statements are great for evaluating multiple conditions.
Here’s what the syntax of a simple switch
statement that uses the -Regex
parameter looks like.
switch -Regex (<test-expression>){
<condition1> {<action>}
<condition2> {<action>}
}
Here’s an example of a switch
statement that moves user accounts into their corresponding OU depending on the department information contained in a CSV file. This is the CSV file used in this example:
And here is the script:
$users = Import-CSV -Path 'C:\Temp\User Info.csv'
foreach ($user in $users){
switch -Regex ($user.Department){
'facilities|fac' {
Get-ADUser -Identity $user.Name | Move-ADObject -TargetPath "OU=Facilities,DC=nintendo,DC=com"
Write-Host $user.Name 'has been moved to the Facilities OU'
}
'management|mgt'{
Get-ADUser -Identity $user.Name | Move-ADObject -TargetPath "OU=Management,DC=nintendo,DC=com"
Write-Host $user.Name 'has been moved to the Management OU'
}
'research' {
Get-ADUser -Identity $user.Name | Move-ADObject -TargetPath "OU=Research,DC=nintendo,DC=com"
Write-Host $user.Name 'has been moved to the Research OU'
}
'sales'{
Get-ADUser -Identity $user.Name | Move-ADObject -TargetPath "OU=Sales,DC=nintendo,DC=com"
Write-Host $user.Name 'has been moved to the Sales OU'
}
'administration|adm'{
Get-ADUser -Identity $user.Name | Move-ADObject -TargetPath "OU=Administration,DC=nintendo,DC=com"
Write-Host $user.Name 'has been moved to the Administration OU'
}
Default {
Write-Host $user.Name 'does not have a matching department'
}
}
}
To summarize, this script looks at the department value for each CSV entry and compares it to the regex statements. When a match is made, the user account moves to the matching OU, and a corresponding message displays. If a department does not match any regex statement, a message indicates that the user does not have a matching department.
While this example is certainly effective, it doesn’t rely on complex regex patterns because it doesn’t have to. Your regex patterns need to meet only your requirements. In this example, the requirements were simple, and the patterns could match the information contained in the CSV file almost exactly.
Here’s another example where you would want to ensure the evaluated data is formatted correctly. In this example, we ask users to input a valid email address or phone number.
$userInput = Read-Host -Prompt 'Input your email address ([email protected]) or phone number (123-456-7890)'
switch -regex ($userInput){
'^\w+\.??\w*@\w+\.\w+$'{
Write-Host "You've entered an email address"
}
'\d{3}-\d{3}-\d{4}' {
Write-Host "You've entered a valid phone number"
}
Default {
Write-Host "The information you provided was not a valid email address or phone number"
}
}
If a user inputs a valid email address, it’s matched against the regex pattern '^\w+\.??\w*@\w+\.\w+$
.'
If they enter a valid phone number, it’s validated against the regex pattern '\d{3}-\d{3}-\d{4}
.'
If the input is not valid, the Default
value is returned. In this case, a message informs the user the input was not valid.
Other regex resources
Regex is not for the faint of heart, but there are tons of great resources available when you need help. Here are some terrific resources that can help both regex beginners and pros.
Regex Hero reference sheet: The Regex Hero reference sheet is a great resource for quickly identifying regex characters, their uses, and their meanings.
Regex Hero .NET tester: This is another great resource from Regex Hero. The .NET tester is a simple application that lets you quickly test out your regex statements.
Microsoft’s Regex quick reference sheet: If you prefer to go straight to the source, Microsoft’s regex reference sheet is what you’re looking for. Personally, I prefer the formatting of Regex Hero’s reference sheet, but Microsoft’s is very thorough.
regex101: Regex101 is a dedicated web portal you can use to test your expressions quickly. Regex101 also provides helpful explanations, matching information, and reference data.
Regex subreddit: The regex subreddit is a great place to get answers to all your regex questions.
PowerShell subreddit: With more than 200,000 members, the PowerShell subreddit is brimming with some of the smartest people out there. If you need help with PowerShell and regex, this forum gets you the answers you need quickly.
Regex is powerful but complex
There is so much you can do with regex. You can parse files, scrape websites, validate input, and so much more. However, it’s complex. If you don’t regularly use it, you’ll soon forget much of what you learned. That’s why there’s no shame in frequently using the resources above.
If you’re looking for powerful tools that aren’t complex, check out PDQ Deploy & Inventory. This powerful combination can help you manage your endpoints and automate deployments with minimal effort. Try PDQ Deploy & Inventory for free for 14 days.