PowerShell has a unique variable called the pipeline variable ($_ or $PSItem). Due to PowerShell's ability to pipe entire objects from one command to another, it needed a way to represent that object that was traversing the pipeline.

When one PowerShell command pipes something to another command, that command can send an object. An object can be of any type. That object then has a set of methods and properties attached to it. We can reference those methods and properties on a standalone object by creating the object, assigning it to a variable, and then referencing its properties and methods that way.

For example, the Get-Item cmdlet returns a System.IO.DirectoryInfo object when querying a directory.

Get-Item -Path 'C:\Windows' | Get-Member
Using Get Item to query a directory

Using Get Item to query a directory

This object then has lots of different methods and properties we can reference. I could call methods on this object or reference its properties.

PS C:\> $windowsDir.GetFiles()

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a-h--        6/14/2017   8:24 AM          12292 .DS_Store
-a-h--        6/14/2017   8:22 AM           4096 ._.DS_Store
-a----        7/22/2017   6:00 PM          64512 bfsvc.exe
-a--s-         4/8/2018   3:16 AM          67584 bootstat.dat
-a----        10/8/2016   1:15 PM         232960 DfsrAdmin.exe
-a----         8/9/2017  10:28 AM           1315 DfsrAdmin.exe.config
<SNIP>

PS C:\> $windowsDir.LastWriteTime

Sunday, April 8, 2018 6:00:19 AM

Simple enough, right? But, what if I'm using a cmdlet like Get-ChildItem, which enumerates lots of directories at once? It'd be crazy to assign variables like $dir1, $dir2, and $dir3 to all of them. We need a more dynamic way to represent them. We need a single variable that represents each directory object upon processing it. We need the pipeline variable!

Using the Get-ChildItem example, let's say I want to find all directories in the C:\Windows folder using Get-ChildItem -Path C:\Windows\ -Directory. This command returns a few dozen directories. If we'd assign this output to a variable, it'd be an array of objects, not just a single object. Instead, I can pipe all of those objects, one at a time, from Get-ChildItem to ForEach-Object and reference the pipeline variable.

The pipeline variable ($_ or $PSItem) represents each object upon processing it. You can see below that I can reference the Name property for every directory processed using $_.Name.

PS C:\> Get-ChildItem -Path C:\Windows\ -Directory | ForEach-Object { $_.Name  }
addins
ADFS
appcompat
AppPatch
AppReadiness
assembly
<SNIP>

With the pipeline variable, we can reference any method and property. The variable will always be of the same type as the object coming from the previous command. You can see below that if you pipe the pipeline variable itself to Get-Member, it returns the same System.IO.DirectoryInfo object type as Get-Item.

PS C:\> Get-ChildItem -Path C:\Windows\ -Directory | ForEach-Object { $PSItem | Get-member  } | Select-Object -First 1


   TypeName: System.IO.DirectoryInfo
   <SNIP>

You'll see the pipeline variable most often used in commands that need to reference or perform some specific action on each object processed. Another example is using the Select-Object cmdlet's calculated properties. This allows the scripter to manipulate the output returned by referencing objects from the pipeline.

For example, instead of using ForEach-Object to return only the directory names, I could use a calculated property to create a DirectoryName property on the fly and assign the directory names to that.

Subscribe to 4sysops newsletter!

PS C:\> Get-ChildItem -Path C:\Windows\ -Directory | Select-Object -Property @{ Name = 'DirectoryName'; Expression = { $_.Name } }

DirectoryName
-------------
addins
ADFS
appcompat
AppPatch
AppReadiness
assembly
<SNIP>

Thus, we can use the pipeline variable in many different scenarios. In what scenarios do you use the pipeline variable?