Dealing with concurrent pipelines in remote PowerShell
One of the issues you are bound to run into, sooner or later, is a concurrent pipeline error when working in a remote PowerShell session. This is a common stumbling block for most administrators, since all Exchange Management Shell tasks are done through PowerShell remoting. Concurrent pipeline errors can often be counter-intuitive because the same command syntax works fine in a standard PowerShell session. In this recipe, we'll take a look at why this happens and what you can do to get around it.
How to do it...
PowerShell remoting does not support more than one pipeline running at a time. When executing multiple cmldets within a pipeline, you may need to store the output of one or more commands in an object that can be then be passed down the pipeline to other commands. For example, to pipe a collection of mailboxes to the New-InboxRule
command, use the following syntax to avoid a concurrent pipeline operation:
$mailboxes = Get-Mailbox -Database DB1 $mailboxes | %{ New-InboxRule -Name Attach ` -Mailbox $_ ` -HasAttachment $true ` -MarkImportance High }
How it works...
In this example, we first create a collection of all the mailboxes in the DB1
database by storing them in the $mailboxes
variable . We then loop through each mailbox object by piping $mailboxes
to the ForEach-Object
cmdlet (using the %
alias), and, for each item in the collection, we create an inbox rule that marks any message with an attachment as of high importance.
Some Exchange Management Shell cmdlets are designed specifically to accept input from other cmdlets. One good example of this is how the Get-Mailbox
and Set-Mailbox
cmdlets work together. You can simply pipe the Get-Mailbox
cmdlet directly to the Set-Mailbox
cmdlet, and the parameter binding is automatic. As you can see from the example, when dealing with cmdlets that are not designed to work together such as the Get-Mailbox
and New-InboxRule
cmdlets , you need to use the ForEach-Object
cmdlet or a foreach
loop statement so you can explicitly identify the object that needs to be modified.
In a typical PowerShell session, you can pipe one command to another in this way without any problems, but this is not the case when working in a remote PowerShell session. PowerShell remoting does not support multiple pipelines executing at the same time.
Had we tried to pipe the results from Get-Mailbox
directly to ForEach-Object
, we would have gotten the following error:
There's more...
In the first example, we used the ForEach-Object
cmdlet to process each mailbox in the $mailboxes
collection to avoid executing concurrent pipelines. You can also use a foreach
statement to accomplish the same thing. This code is an alternative to the previous example but will achieve the same end result:
foreach($i in Get-Mailbox –Database DB1) { New-InboxRule -Name Attach ` -Mailbox $i ` -HasAttachment $true ` -MarkImportance High }
Notice that we're still working with the same set of mailboxes, but since we are using the foreach
construct, we identify the mailbox object that the New-InboxRule
cmdlet needs to work with, using the $i
variable as opposed to the $_
pipeline variable used with the ForEach-Object
cmdlet.