M HYPE SPLASH
// news

PowerShell: How to substitute array value into regex expression within Where-Object -MATCH

By John Campbell

I am having trouble getting a string value from an array to insert into the regex expression in the -match condition of Where-Object below.

PS [path]> $ordArr=@("001","005","002","007")
PS [path]> for ($i=0;$i -le $ordArr.Length) { get-childitem -file -recurse | where-object {$_.BaseName -match "^$ordArr[$i].*$"} | ForEach-Object {echo $_}; $i=($i+2)}

If I am to enter $ordArr[$i] by itself (i.e. call it outside the presence of the Where-Object function, it returns the expected string values.

I have also tried ... -match "^${ordArr[$i]}.*$ ... ", ... -match "^${ordArr[$[tick mark]{i[tick mark]}]}.*$ ... ", and other misc. combinations using tick markets and braces. However, I cannot get the string value from the $ordArr to substituted into the command.

Depending upon the combination of braces and tick marks, it either returns nothing or everything. Also, if I am to manually enter 001 from the $ordArr into the regex expression, ... -match "^001.*$" ..., then it will return the files I expect.

So, how can I insert a value from an array into the regex condition within Where-Object ... -match ...?

Thanks!

1 Answer

Your regex pattern does not interpolate the string like you intend.

"^$ordArr[$i].*$"} results in ^001 005 002 007[0].*$

You have to use the subexpression operator $() if you want to use expressions like calculations ($int1 + $int2), member access ($something.Path), index access ($array[1]), etc. within another expression like a String.

In your case you have to put your $ordArr[$i] into a subexpression:

"^$($ordArr[$i]).*$"

See: MSFT: Subexpression operator $( )

Furthermore you should avoid using Get-ChildItem for the same location within a for or foreach loop. In your example you call Get-ChildItem recursively 4 times for the same items.

My suggestion

My suggestion is to define a combined regex pattern to have a single one instead of looping several times over an array to build a pattern. This is much faster than other approaches.

$ordArr = @('001', '005', '002', '007')
# build a combined regex pattern
# this time we don't need a subexpression operator, since we don't access any member or index from $_
$regexPattern = ($ordArr | ForEach-Object { "^$_.*$" }) -join '|'
Get-ChildItem -File -Recurse | Where-Object { $_.BaseName -match $regexPattern # as alternative and to avoid saving anything to the automatic variable $matches (-> better performance) # but not idiomatic Powershell: # [regex]::IsMatch($_.BaseName, $regexPattern)
}
3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy