Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Archives
March 17, 2026

Regular Expression Actions

In this issue:

  • Anchors
  • Split
  • Replace
  • ConvertTo-ComplexString
  • Summary

If you've been following along the last few issues, and practicing, using regular expressions in PowerShell should not be quite as intimidating. There are a few more basic concepts to cover that should get you through most basic PowerShell usage scenarios. Let's continue learning.

Anchors

One of the more devious, or unpredictable facets of using regular expressions is the idea of a floating match.

PS C:\> "PowerShell is useful." -match "shell" ? $matches : $null

Name                           Value
----                           -----
0                              Shell

PS C:\> "Shell is useful." -match "shell" ? $matches : $null

Name                           Value
----                           -----
0                              Shell

PS C:\> "Is useful: PowerShell." -match "shell" ? $matches : $null

Name                           Value
----                           -----
0                              Shell

As you can see, the regular expression will match anywhere in the string. This isn't necessarily a bad thing, just something you need to be aware of. In some ways, this makes it easy to use regular expressions in PowerShell.

PS C:\> Get-Service | where {$_.DisplayName -match "host"}

Status  Name            DisplayName
------  ----            -----------
Stopped fdPHost         Function Discovery Provider Host
Stopped HgClientService Host Guardian Client Service
Running HNS             Host Network Service
Running HvHost          HV Host Service
Running jhi_service     Intel(R) Dynamic Application Loader Host Interface Service
Stopped PerfHost        Performance Counter DLL Host
Stopped upnphost        UPnP Device Host
Running vmcompute       Hyper-V Host Compute Service
Stopped WdiServiceHost  Diagnostic Service Host
Running WdiSystemHost   Diagnostic System Host
Stopped WEPHOSTSVC      Windows Encryption Provider Host Service

The expression matched anywhere that host was found. But suppose I wanted to only find services where the name ended in host. For that, I can supply an anchor. You can use ^ to anchor the patter match to the beginning of the string. use $ to anchor to the end.

PS C:\> Get-Service | where {$_.DisplayName -match 'host$'}

Status  Name           DisplayName
------  ----           -----------
Stopped fdPHost        Function Discovery Provider Host
Stopped PerfHost       Performance Counter DLL Host
Stopped upnphost       UPnP Device Host
Stopped WdiServiceHost Diagnostic Service Host
Running WdiSystemHost  Diagnostic System Host

Whenever I use the $ anchor, I use single quotes to avoid PowerShell treating it as part of a variable.

> My example is for demonstration purposes. This is not how I would perform this task normally. I could run Get-Service -displayName *host and get the same results, even faster.

And you can combine the anchors. Take a look at these sample files.

PS C:\> dir c:\temp\*sys*

    Directory: C:\temp

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           3/16/2026  3:03 PM          62782 data-sys.txt
-a---            2/2/2026  1:25 PM          73428 spectre-system-status.png
-a---           2/21/2023  3:31 PM        1073152 sysinfo.db
-a---            6/4/2025  4:29 PM           4407 SysInfo.html
-a---            6/4/2025  4:29 PM           4407 SysInfo.txt
-a---           3/16/2026  3:10 PM           6406 SysInfo2.html
-a---           3/16/2026  3:10 PM           2326 SysInfo3.html
-a---           3/16/2026  3:05 PM          85658 SysProcess.html
-a---            7/2/2025  4:25 PM          34553 SysReport.html
-a---           3/16/2026  3:05 PM          86146 SysService-1.html

I want to get a directly listing by only see files that begin with Sys, end in .html and match either Info or Report in the middle.

PS C:\> dir c:\temp\ -file  | Where {$_.name -match '^Sys((Info)|(Report)).*\.html$'}

    Directory: C:\temp

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---            6/4/2025  4:29 PM           4407 SysInfo.html
-a---           3/16/2026  3:10 PM           6406 SysInfo2.html
-a---           3/16/2026  3:10 PM           2326 SysInfo3.html
-a---            7/2/2025  4:25 PM          34553 SysReport.html

In actuality, the better approach would be to split the difference.

PS C:\> dir c:\temp\sys*.html | Where {$_.name -match "(Info)|(Report)"}

    Directory: C:\temp

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---            6/4/2025  4:29 PM           4407 SysInfo.html
-a---           3/16/2026  3:10 PM           6406 SysInfo2.html
-a---           3/16/2026  3:10 PM           2326 SysInfo3.html
-a---            7/2/2025  4:25 PM          34553 SysReport.html

The first part of the expression uses early filtering to cut down on the number of files. The Where-Object expression fine-tunes the selection.

However, you need to understand how anchors work because you might be analyzing a text file or some other source that doesn't provide any type of filtering.

PS C:\> Get-Content c:\temp\filelist.txt  | Where {$_ -match '^Sys((Info)|(Report)).*\.html$'}
SysInfo.html
SysInfo2.html
SysInfo3.html
SysReport.html

Since I'm parsing a text file, I could also use the pattern with Select-String.

PS C:\> Get-Content C:\temp\filelist.txt | Select-String '^Sys((Info)|(Report)).*\.html$'

SysInfo.html
SysInfo2.html
SysInfo3.html
SysReport.html
Want to read the full issue?
GitHub
Bluesky
LinkedIn
Mastodon
jdhitsolutions.github.io
Powered by Buttondown, the easiest way to start and grow your newsletter.