6

Possible Duplicate:
What does $_ mean in powershell?

I have already seen someone else's question and answer on the same subject but for me it does not answer the question.

I know how to use Select-Object, Where-Object, ForEach-Object etc and pass a script block in, for example:

dir | ForEach-Object { $_.Name }

which returns an array of all file names in the current directory.

This is similar to C#'s Select extension method:

Dir.Select(x => x.Name)

However, the above C# is easily understandable because we are passing a function to the Select method which then executes it for each element in the list.

However, the equivalent in PowerShell:

dir | ForEach-Object { param($x) $x.Name }

does not return anything. However

& { param($x) $x.Name } (dir)[0]

works as expected.

Can someone please explain the magic of $_ to someone familiar to C# but not the world of scripting? It is a special keyword? Can it be only be used in script blocks which are passed into cmdlets? How do you invoke one without piping one to ForEach-Object (or any other cmdlet)? i.e:

& { $_.Name } (dir)[0]

?

Community
  • 1
  • 1
Tahir Hassan
  • 5,715
  • 6
  • 45
  • 65
  • 2
    This is not an exact duplicate of another question (which I said in the first line of this question). The *other* question more or less asks how to *use* it, not what is *means*. You can tell that is is not a duplicate because the accepted answers are different. zdan's answer shows that it is possible to pipe something to a filter directly whereas JaredPar's answer shows something being piped to ForEach-Object. The difference between the two is calling a filter directly or passing a filter to another filter which then executes it. – Tahir Hassan Oct 26 '12 at 20:37

2 Answers2

9

The $_ is only created in the context of a pipeline, that is the passing of output objects from one command into the "input" of another. For pipeline filters (which are like functions), powershell automatically populates the $_ variable with the current object of the pipeline. Now I say current because it is important to note that when multiple objects are passed down the pipeline, the process scriptblock of your filter is executed once per object.

Now, you could rename the the pipeline objects to one of you input parameters, but you have to tell powershell that you are doing so. For e.g.:

# C:\> filter get-name-filt {Param([parameter(ValueFromPipeline=$true)]$x) $x.name}
# C:\> (dir)[0] | get-name-filt

which is not terribly convenient on the command line, hence the $_ automatic variable.

zdan
  • 28,667
  • 7
  • 60
  • 71
4

The $_ is the current pipe-line item.

For example:

 dir | ForEach-Object { $_.Name }

Means:

  1. Run the dir command
  2. Pass the output to the next pipeline command
  3. ForEach-Object uses the output from dir as a variable called $_

Since the output of dir has the property .name then the pipelined $_ will also have the same property. It's simply a way to pass data down the pipe

Nick
  • 4,302
  • 2
  • 24
  • 38