Author Posts

April 25, 2014 at 1:46 pm

Coming from a Python background, how does one accomplish something along the lines of looping through each object returned from a Get-MailBox and Get-MailUser?

foreach ($user in (Get-MailUser -ResultSize unlimited))
{..}

I know how I can stuff both cmdlets in the single collection in the above foreach loop but its so ugly.
Its a script so I wont use pipes (personal preference, I dont think a pipe belongs anywhere but a shell).

PowerShell lacks the syntactic sugar that Python has for doing things like this idiomatically. Without pipes, how does one iterate over multiple collections without invoking the retrieval early? Its bad enough this consumes the set before iterating.

Thanks!

April 25, 2014 at 2:03 pm

I'm not sure I understand the question. Are you trying to combine the results of two commands into a single collection?

April 25, 2014 at 5:35 pm

Hi Dave,
That is exactly right. Does powershell support such syntax or must it be nested? If so, without pipes how can you process each object returned without consuming the entire result set before iterating?

Thanks.

April 25, 2014 at 5:56 pm

The pipeline is PowerShell's primary means of streaming objects instead of holding an entire result set in memory. If that's your goal, you'll need to stop avoiding the pipeline completely.

That said, you can put multiple commands into a script block and invoke it like a single command, piping the results to another command (ForEach-Object, or whatever.) This accomplishes what you were trying to do:

$scriptBlock = {
    Get-MailUser
    Get-MailBox 
}

& $scriptBlock |
ForEach-Object {
    # Do something
}

April 25, 2014 at 6:02 pm

That's in a nut shell how I got them in one one foreach loop.

So, is it not common belief that a pipe should be avoided in a script?
I am of the thought that they are not typically programmatic approaches but cmdline or shell like operators.

Is ForEach-Object the only way to process items returned from a cmdlet without consuming the entire result set first?
If one choose not to use pipes, could you still iterate over the return from say Get-MailBox, one mailbox at a time as they are returned?

Thanks for the insight Dave!

April 25, 2014 at 6:37 pm

I'm not sure where that "avoid the pipeline" sound byte came from originally, but it's been taken way out of context. It's important to know when to use the pipeline (essentially, anytime streaming of objects is required.) That said, if you already have a whole collection in memory to begin with, the foreach statement gives much better performance.

The pipeline is the only way to process items output by a cmdlet one at a time, but it doesn't necessarily mean you're using ForEach-Object. Any command that accepts pipeline input can be used, including your own functions or filters.