PowerShell Regex: How to Use Regular Expressions (With Examples)

PowerShell regex (regular expressions) lets you match, extract, replace and split text by pattern. The operators -match, -replace and -split all take a regex, and $Matches holds what -match found:

$text = 'Order ORD-5812 ships to Austin, TX'

$text -match 'ORD-(\d+)'
"Whole match: $($Matches[0])"
"Order number: $($Matches[1])"

Output:

True
Whole match: ORD-5812
Order number: 5812
PowerShell regex -match operator and the $Matches variable
-match returns True, and $Matches holds the whole match and the captured group (PowerShell 7)

Below I cover case sensitivity, named groups, replacing, splitting, finding every match, Select-String and switch -Regex. Every example ran in PowerShell 7.6 and 5.1, and all the data is made up.

Regex basics in PowerShell

PowerShell uses the .NET regex engine. A few tokens cover most everyday patterns:

TokenMatchesExample
\dOne digit\d{4} matches 2026
\wLetter, digit or underscore\w+ matches Austin
\sWhitespace\s+ matches spaces and tabs
.Any character except a newlinea.c matches abc
^ and $Start and end of the string^ORD matches at the start
( )Capture groupORD-(\d+) captures 5812
[ ]Any one character in the set[;,] matches ; or ,

Microsoft’s regular expression quick reference lists every token.

-match is case-insensitive, -cmatch isn’t

Like most PowerShell operators, -match ignores case. Use -cmatch when case matters:

'INVOICE inv-20431' -match 'INV-\d+'
'INVOICE inv-20431' -cmatch 'INV-\d+'

Output:

True
False

The same rule applies to -replace and -creplace, and -split and -csplit. The -match operator in depth covers matching against arrays.

Capture data with named groups

Named groups, written (?<Name>…), make a pattern easier to read and the results easier to use. Here I break a log line into parts:

$line = '2026-09-14 08:16:44 ERROR [Billing] Card declined for order ORD-5812'
$pattern = '^(?<Date>\S+) (?<Time>\S+) (?<Level>\w+)\s+\[(?<Area>\w+)\] (?<Message>.+)$'

if ($line -match $pattern) {
    "Level:   $($Matches.Level)"
    "Area:    $($Matches.Area)"
    "Message: $($Matches.Message)"
}

Output:

Level:   ERROR
Area:    Billing
Message: Card declined for order ORD-5812
PowerShell regex named capture groups parse a log line
Named groups pull the level, area and message out of one log line (Windows PowerShell 5.1)

Each group name becomes a key in $Matches. Extracting text between delimiters shows more capture patterns.

Replace text with -replace

-replace takes a pattern and a replacement, and $1, $2 refer to your groups. This reformats phone numbers written three different ways:

$phones = '512-555-0147', '214.555.0199', '713 555 0123'
$phones -replace '^(\d{3})[-. ](\d{3})[-. ](\d{4})$', '($1) $2-$3'

Output:

(512) 555-0147
(214) 555-0199
(713) 555-0123
PowerShell regex -replace with capture groups reformats phone numbers
Three phone number formats become one with a single -replace (PowerShell 7)

Put the replacement in single quotes. In double quotes, PowerShell would treat $1 as a variable before the regex sees it. Replacing text in strings covers plain-text replacements too.

Split on a pattern with -split

-split accepts a regex, so you can split on several separators at once and trim spaces at the same time:

'Austin; Dallas,Houston ;  El Paso' -split '\s*[;,]\s*'

Output:

Austin
Dallas
Houston
El Paso

The pattern \s*[;,]\s* means any spaces, then a semicolon or comma, then any spaces. Splitting strings in PowerShell covers more options.

Find every match with [regex]::Matches

-match stops at the first match. To get all of them, use the .NET Regex class:

$text = 'Contact sales@example.com or support@example.com, not help@example'
$found = [regex]::Matches($text, '\b[\w.-]+@[\w-]+\.\w+\b')

"Found $($found.Count) email addresses:"
$found.Value

Output:

Found 2 email addresses:
sales@example.com
support@example.com

help@example isn’t matched, because the pattern needs a dot and a domain ending after the @.

Search files with Select-String

Select-String runs a regex against every line of a file, like grep. Here I pull the order number from each error line in a log:

Select-String -Path C:\psfaqs\Regex\app.log -Pattern 'ERROR.*(ORD-\d+)' |
    ForEach-Object { "Line $($_.LineNumber): $($_.Matches[0].Groups[1].Value)" }

Output:

Line 2: ORD-5812
Line 4: ORD-5815

Each result has the line number and a Matches collection with your groups. Finding text patterns with Select-String goes further.

Branch on patterns with switch -Regex

switch -Regex tests a value against several patterns and runs the first block that matches:

foreach ($id in 'ORD-5812', 'INV-20431', 'RMA-77') {
    switch -Regex ($id) {
        '^ORD-\d+$' { "$id is an order"; break }
        '^INV-\d+$' { "$id is an invoice"; break }
        default     { "$id is unknown" }
    }
}

Output:

ORD-5812 is an order
INV-20431 is an invoice
RMA-77 is unknown

Without break, switch keeps testing the remaining patterns, which is useful when one value can match more than one.

Escape special characters

Characters like ( ) . \ and $ have special meanings in regex. [regex]::Escape() makes a literal string safe to use as a pattern:

$path = 'C:\Reports\Q3 (2026).xlsx'
$pattern = [regex]::Escape('Q3 (2026)')

"Escaped pattern: $pattern"
"Match found:     $($path -match $pattern)"

Output:

Escaped pattern: Q3\ \(2026\)
Match found:     True

Always escape user input or file names before putting them into a pattern. Microsoft covers this and more in about_Regular_Expressions.

Frequently Asked Questions

How do I use regex in PowerShell?

Use the -match, -replace and -split operators, or Select-String for files. They all accept .NET regular expressions.

Is PowerShell -match case-sensitive?

No. -match ignores case. Use -cmatch for a case-sensitive match.

How do I get the captured group from -match?

Read the $Matches variable after a successful -match. $Matches[1] is the first group, and named groups use their names.

How do I find all regex matches in a string?

Use [regex]::Matches($text, $pattern). -match only returns the first match.

How do I escape special characters in a PowerShell regex?

Pass the literal text to [regex]::Escape(), or put a backslash before each special character.

Keep going with text processing: