PowerShell: How to substitute array value into regex expression within Where-Object -MATCH
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