CharlesH
CharlesH

Reputation: 196

Differences between | and $

Can anyone explain to me the differences I'm seeing in either using a | to pipe one command to another or using $ to 'pipe' it a different way (sorry not sure if the use $ is actually considering piping).

So… this works:

Get-Mailbox -ResultSize Unlimited | 
    where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" } | 
    Get-MailboxPermission

Which is great, however because I want to place another where command after the Get-MailboxPermission which doesn't work above I then tried to use this:

$Mailbox = Get-Mailbox -ResultSize Unlimited | 
           where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" }

Get-MailboxStatistics -Identity $Mailbox |
    where { $_.IsInherited.tostring() -eq "False" }

It causes me to get this error:

Cannot process argument transformation on parameter 'Identity'. Cannot convert the "System.Collections.ArrayList" value of type "System.Collections.ArrayList" to type "Microsoft.Exchange.Configuration.Tasks.GeneralMailboxOrMailUserIdParameter".

Surely using | or $ is the same in the sense that it pipes through the results to the next command or am I completely wrong?

Upvotes: 2

Views: 566

Answers (3)

wullxz
wullxz

Reputation: 19450

I don't have an exchange shell here to test but I guess I can still explain the basics and point you in the right direction.

The pipe | is used to redirect output from one command to another command. $ in Powershell is the character which defines that the character sequence right behind it is either a variable (e.g. $Mailbox as an example for a normal variable or $_ as an example for a variable that holds data that has been piped through from a previous command) or an expression. An example for an expression one is $(4+5).
Or in a more frequently used example:

PS C:\Users\Administrator> $file = (get-childitem)[0]
PS C:\Users\Administrator> write-output "The fullname of $file is $($file.fullname)"
The fullname of .ssh is C:\Users\Administrator\.ssh

In that example it is actually necessary to use an expression, because variable detection inside a string doesn't recognize dots as separator between variable and a variable member (fullname is a member of $file).
If it's not clear to you why there is a point and what members are, you should probably look into object oriented programming a bit because Powershell is object oriented through and through.

In your 2nd example you just save everything that's returned by your Get-Mailbox command in the $Mailbox variable. The $Mailbox variable is available as long as you don't delete it or leave its scope (in this case, the powershell session). You can actually use the variable as input for multiple commands without losing its data.
When using the pipe, the data returned by your first command is only accessible for the command behind the pipe and after that it's gone.
That's probably the difference you're interested in.

As for your actual problem: Powershell tells you that it's not expecting to be handed a variable of type System.Collections.ArrayList, which is what Get-Mailbox returns. The technet help is unclear as to what Get-Mailbox specificly returns, but I strongly guess it's an ArrayList of Mailbox-Objects. You can check it like this:

$Mailbox.GetType()
$Mailbox[0].GetType() # gets the type of the first object in $Mailbox

To fix your code, you need to loop over what's been returned by Get-Mailbox. Try this:

$Mailboxes = Get-Mailbox -ResultSize Unlimited | where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" }
$Mailboxes | ForEach-Object { Get-MailboxStatistics -Identity $_ }

The ForEach-Object cmdlet loops over an array or a list and works on each item individually.
Your first example works so far because Powershell has been made smarter about piped data a few versions ago (See paragraph about 'Member Enumeration'). It's actually ForEach-ing over the passed in data.

Follow up links:
The $_ variable in powershell
Powershell is an object oriented language

Upvotes: 5

Sean
Sean

Reputation: 62472

The pipe operator | i used to flow the output of one command into the input of another command.

The dollar symbolc, $ is used to denote that the name following it is a variable, and has nothing to do with piping data between cmdlets. The where cmdlet create a $_ variable for use within its expression.

Upvotes: 2

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200273

Sorry to have to say this, but you're completely wrong. Pipelines and variables are two entirely different things.

The pipe (|) connects the output of one cmdlet to the input of another cmdlet. List output is processed one item at a time, i.e. the second cmdlet receives each list item separately.

If you collect a list of items in a variable ($mailbox) and call a cmdlet with that variable you're passing the list object instead of individual list items. That only works if the cmdlet parameter accepts array input.

Upvotes: 3

Related Questions