PowerShell Regex and wildcards
PowerShell has two separate pattern systems and mixing them up wastes a lot of time.
Documentation: Microsoft Learn
Overview
Wildcards are simple: * matches any number of characters, ? matches exactly one. They are what -like uses, and what the -Filter and -Path parameters of file commands accept. Wildcards are all you need for most filename work.
Regular expressions are the full pattern language, used by -match, -replace and -split, and by Select-String. In a regex, . means any character, \d means a digit, + means one or more, and ^ and $ anchor to the start and end of the string. A dot in a regex is not a literal dot, which is the single most common source of confusion when moving from wildcards.
When -match succeeds it populates $Matches, a hashtable holding the whole match at key 0 and any capture groups after it. Named groups, written (?<name>...), land in $Matches.name and are far easier to read than counting parentheses.
For filtering files, prefer -Filter over piping to Where-Object. -Filter is handled by the filesystem provider before objects are created, so it is dramatically faster on large directories.
What happens
The first line uses wildcards. -Filter '*.ps1' asks the filesystem for names ending in .ps1, and the provider applies it while enumerating, so PowerShell never builds objects for the files you did not want. On a directory with 200,000 files that is the difference between seconds and minutes.
The second line uses regex. -match returns True and fills $Matches, and the escaped \.log at the end is a literal dot rather than the any-character dot. The named group (?<date>...) means the captured value is $Matches.date instead of $Matches[1], which is what the last line reads. Two patterns, two systems, on purpose.
Worth remembering
- Wildcards (* and ?) are for -like and file paths.
- Regex is for -match, -replace, -split and Select-String.
- In regex, . means any character. Escape it as \. for a literal dot.
- -match fills $Matches, including named capture groups.
$Matchesis only refreshed when-matchsucceeds — after a failed match it still holds the previous match's values. Always test the$true/$falseresult before reading$Matches.
Primary documentation
Try it
Browser simulation · fictional data; no changes to your computer.
Follow the objects
Run the command to inspect each stage.
Filters files with a wildcard, then parses a filename with a named regex group.
Show reference output
Browser dataset output · the real environment will differ
Name Length ---------- -------- app.log 12582912 errors.log 26214400 trace.log 524288