I want to iterate over folders and execute a command per folder, ignoring the already processed ones.
For this I'm trying to concatenate variables to produce a command and then execute this string.
But PowerShell (v7.2.5) is removing the variables from concatenation (or replacing them with empty strings).
I tried many different syntaxes like $($var1) $($var2)
or "$var1 $var2"
, none of them work. My current approach (it will run with Invoke-Expression -Command
instead of echo
):
$arguments = "-a -b -c"
$exe = "C:\foo\bar.exe"
$targetdir = "C:\path\"
Get-ChildItem $targetdir -Directory | ForEach-Object -Parallel {If($_.FullName.Contains("processed")){continue}; echo ("{0} -d {1} {2}" -f $($exe),$($_.FullName),$($arguments));} -ThrottleLimit 8
Expected:
C:\foo\bar.exe -d C:\path\101 -a -b -c
C:\foo\bar.exe -d C:\path\102 -a -b -c
C:\foo\bar.exe -d C:\path\103 -a -b -c
Output:
-d C:\path\101
-d C:\path\102
-d C:\path\103
Why is PowerShell removing paths or arguments from the concatenation and how do I fix this?
CodePudding user response:
As stated in the the ForEach-Object
MS Docs:
The
ForEach-Object -Parallel
parameter set runs script blocks in parallel on separate process threads. The$using:
keyword allows passing variable references from the cmdlet invocation thread to each running script block thread.
Do not use continue outside of a loop, switch, or trap:
Using
continue
inside a pipeline, such as aForEach-Object
script block, not only exits the pipeline, it potentially terminates the entire runspace.
You can use return
to emulate the behavior that continue
has on a loop:
$arguments = '-a -b -c'
$exe = 'C:\foo\bar.exe'
$targetdir = 'C:\path'
Get-ChildItem $targetdir -Directory | ForEach-Object -Parallel {
if($_.FullName.Contains('processed')) {
return
}
"{0} -d {1} {2}" -f $using:exe, $_.FullName, $using:arguments
} -ThrottleLimit 8