1

Why can't I pipe the result from a foreach-object operation to another foreach-object operation? I can't get the last ForEach-Object loop to run. It outputs nothing.

$mailboxstatistics |
Select-Object -First 20 |
Where { $_.FolderPath.Contains("/Inkorg") -eq $True } |
ForEach-Object -Begin{
        Write-Host "Begin"
    } -Process{
        #Write-Host "Process"
        Write-Host $($_.FolderPath)
    } -End{
        Write-Host "End"
    } |
ForEach-Object{
    Write-Host "test"
}
5
  • 1
    Write-Host is not Write-Output. You're generally off using neither (explicitly), just return the value in the pipeline itself (which has the same effect as a Write-Output call). Commented Oct 6, 2017 at 12:48
  • 1
    Don't be afraid to break your statement. Do Set a variable to the content of your First 20 where, then pipe this variable to the first foreach then pipe it to the next foreach. In your case though, I don't see why you wouldn't perform all the needed operation in the first foreach. Commented Oct 6, 2017 at 13:05
  • Seems like my use of Write-Host on the object, the ($_.FolderPath) is the culprit blocking the loop from passing the object on. Thanks, didn't know that. Is there a proper command that works like debug.writeline() if I'd like to print an object property value (without blocking it) when it passes down the pipeline? Commented Oct 6, 2017 at 13:50
  • 1
    Write-Host isn't blocking anything -- it just isn't part of the pipeline at all. Your second ForEach doesn't do anything because no objects are passed to it. If you want to print the value and pass it in the pipeline, use Write-Host in addition to producing pipeline output (but the final result will end up at the console anyway, so this may result in confusing output). Commented Oct 6, 2017 at 14:01
  • 1
    There's also Tee-Object to copy to a variable or file in addition to the pipeline (it can't copy directly to the host output, though). Commented Oct 6, 2017 at 14:07

1 Answer 1

2

Editing my original answer: You are asking "WHY does the pipeline not let you pipe from one ForEach to another ForEach," as opposed to a practical solution. This requires a basic definition of what the pipeline does. From

  • PowerShell: Automating Administrative Tasks by Michael Shepard; Chendrayan Venkatesan; Sherif Talaat; Brenton J.W. Blawat "The pipeline in PowerShell is a mechanism to get data from one command to another. Simply put, the data that is output from the first command is treated as input to the next command in the pipeline. "

The pipeline in PowerShell passes .NET framework objects as opposed to other types of shells which may pass text. So, based off the definition above, what are you expecting the For-EachObject to output to be the input from pipeline for the next sequence? When you're doing a Where-Object or Select-Object, you're refining the collection. You've already stated that the objects are sent to Write-Host. There would not be anything in the pipeline as an output after the ForEach finishes.

I'm not sure the advantage to the daisy chain of pipelining. I could be wrong about this, I generally break sequences with variables. The ForEach will consume and operate on every single item of the collection piped in, and then produce or pipe out what exactly, to the next in the piping chain? I understand ForEach can accept pipeline input as a collection of objects, such as an array. So I see advantages to its use of only iterating through the number of items, as opposed to the classic

for($i = 0; $i-lt $collectionOfOjbects.Length; $i++)
{
     Verb-Noun $collectionOfObjects[$i]
}

Is it possible to try the selecting/sorting refining first, then pipe that to the ForEach iterations?

$myFirst20MailboxStatsInkorg = $mailboxstatistics | Select-Object -First 20 | Where { $_.FolderPath.Contains("/Inkorg") -eq $True } 
#first round of iteration:
$myFirst20MailboxStatsInkorg | ForEach-Object -Begin{
        Write-Host "Begin"
    } -Process{
        #Write-Host "Process"
        Write-Host $($_.FolderPath)
    } -End{
        Write-Host "End"
    }
#second round of iteration
$myFirst20MailboxStatsInkorg | ForEach-Object{
    Write-Host "test"
}
Sign up to request clarification or add additional context in comments.

1 Comment

Sure is, but this question was generally more about why the first foreach-object loop didn't pass the objects down the pipe. Why is Write-Host diverting the entire object to the host and not just the value of the object property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.