Search code examples
powershelldirectory7zipforeach-object

PowerShell ForEach-Object and Pipelining - upstream


I have a small powershell script which zips all files and folders in one folder individually:

dir | ForEach-Object { 7z a -tzip -mmt=32 $_.BaseName $_.Name };

Let's suppose I have two folders in my directory:

test1
test2

and nothing else. Currently this code will create "test1.zip" and "test2.zip", with the respective folders inside but also contain themselves again (i.e. test1.zip). With two folders, 7z is called four times: once for each folder to create a zip and then once for each new zip-file to update the zip by including the zip in itself. Obviously this is not the desired outcome:

Content of test1.zip:

test1 
test1.zip

It seems like the pipeline fetches an update on the new files and forwards them to the ForEach-Object command, meaning "test1.zip" gets promptly added to "test1.zip".

I'm confused on why this is happening (and even more disturbing: this was not the case in all runs), since I thought the statement is done from left to right, meaning dirand it's output is done and fixed and is then (potentially parallely) processed by ForEach-Object.

Where am I wrong?

dir | ForEach-Object { Write-Host ("I see:"+$_.Name);7z a -tzip $_.Name $_.Name };

Shows that even the newly created zip files are pipelined into ForEach-Object.


Solution

  • So commonly to make dir finish first, put parentheses around it, or the pipeline will go back and forth one object at a time and possibly include new files. This happens with renaming scripts. I think in powershell 7 this is less common.

    (dir) | ForEach-Object { 7z a -tzip -mmt=32 $_.BaseName $_.Name }