4

I'm trying to understand Powershell, but find somethings not so intuitive. What I understand of it is that in the pipeline objects are passed, instead of traditionally text. And $_ refers to the current object in the pipeline. Then, why is the following not working:

get-date|Write-Host "$_"

The errormessage is:

Write-Host : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not matc h any of the parameters that take pipeline input. At line:1 char:10 + get-date|Write-Host $_ + ~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (10-9-2014 15:17:00:PSObject) [Write-Host], ParameterBindingException + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.WriteHostCommand

Edwin
  • 527
  • 7
  • 15

2 Answers2

11

$_ is the current single item in the pipeline. To write each item in the pipeline you would write

get-data | foreach { Write-Host $_ }

Or in the short form

get-data |% { Write-Host $_ }

Conceptually, Foreach is a cmdlet that receives a function parameter, a pipeline input and applies the function on each item of the pipeline. You can't just write code with $_ - you need to have a function explicitly states that it agrees to receive pipeline input

Barak Itkin
  • 4,872
  • 1
  • 22
  • 29
  • See http://technet.microsoft.com/en-us/library/hh847902.aspx and http://technet.microsoft.com/en-us/library/hh847743.aspx for more information on defining pipeline inputs – Barak Itkin Sep 10 '14 at 13:25
  • OK, I kind of get this, but not entirely. According to "get-help Write-Host -parameter *", positional parameter -Object accepts pipeline input and indeed "get-date|Write-Host" works. So then, what's the difference with using $_ as a substitute for the pipeline input and the command using the pipeline input directly. Is it just because $_ is an array (hence the foreach is needed) and in that case would you be able to get the first item like $_[0]? – Edwin Sep 12 '14 at 14:03
  • 1
    While Write-Host is willing to get it's input from the pipeline (i.e. the Object parameter is automatically bound to the pipeline if not specified), what you did with `Write-Host $_` was to specify the object, so it was bound to `$_` and not the pipeline. But `$_` is not really the pipeline data - it's a variable which is only defined by the foreach function for the function you give it – Barak Itkin Sep 13 '14 at 09:14
0

And $_ refers to the current object in the pipeline

Indeed, the automatic $_ variable refers to the current pipeline object, but only in script blocks { ... }, notably those passed to the ForEach-Object and Where-Object cmdlets.

Outside of script blocks it has no meaningful value.

Therefore, the immediate fix to your command is the following:

Get-Date | ForEach-Object { Write-Host $_ }

However, note that:

  • Write-Host is is typically the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file.
  • To output a value, use it by itself; e.g, $value, instead of Write-Host $value (or use Write-Output $value); see this answer. To explicitly print only to the display but with rich formatting, use Out-Host.

Therefore, if merely outputting each pipeline input object is the goal, Get-Date | ForEach-Object { $_ } would do, where the ForEach-Object call is redundant if each input object is to simply be passed through (without transformation); that is, in the latter case just Get-Date would do.


As for what you tried:

get-date|Write-Host "$_"

As noted, the use of $_ in this context is pointless, but the reason for the error message you saw is unrelated to that problem:

Instead, the reason for the error is that you're mistakenly trying to provide input to Write-Host both via the pipeline Get-Date | Write-Host ... and by way of an argument (... | Write-Host "...")

  • Given that the argument ("$_") (positionally) binds to the -Object parameter, the pipeline input then has no parameter left to bind to, which causes the error at hand.
mklement0
  • 382,024
  • 64
  • 607
  • 775