Microsoft Exchange 2010 PowerShell Cookbook
上QQ阅读APP看书,第一时间看更新

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.

See also

  • Understanding the pipeline in Chapter 1, PowerShell Key Concepts
  • Looping through items in Chapter 1, PowerShell Key Concepts
  • Adding, modifying, and removing sever-side inbox rules in Chapter 3, Managing Recipients