- Create a certificate-signed RDP shortcut via Group Policy - Fri, Aug 9 2019
- Monitor web server uptime with a PowerShell script - Tue, Aug 6 2019
- How to build a PowerShell inventory script for Windows Servers - Fri, Aug 2 2019
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
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?
Hey, thanks for the post. one fast question.
How i can take the object from the first comands of the pipeline? for example imagine i do thisç
Get-mailboxdatabase | get-mailbox | get-mailboxstatistics | select object “objectfrom get-mailbox” “objectfrom get-mailboxstatistics” “object from mailboxdatabase”
Dont know if i explain well. and sorry for my english, not native speaker here.
I am interested in the answer to this too.
When we pipeline two or more commands together we end up with only the properties of the last command in the chain.
Example:
command1 | command2 | fl
results in;
Command2 property 1 :
Command2 property 2 :
Command2 property 3 :
etc.
Very often we need properties from the preceding commands to build the desired output.
The way I usually do this is to assign the output of each command to a variable then tie the two together at the end.
$variable1 = command1
$variable2 = command1 | command2
To be able to use this we need a common field between the two commands to link them together or more usually a foreach loop. This is massively inefficient.
So to reiterate Carlos' question I think what we are looking for is something along the lines of
command1 | command2 | ft
output:
command1.property1
command1.property2
command2.property1
command2.property2
@Simon
You can do this with the -OutVariable parameter (when it has been implemented).
This command line displays the result of the third cmdlet.
However, $FirstResult stores the result of the first cmdlet and $SecondResult stores the result of the second cmdlet.
Please note that when you use the -OutVariable parameter you must omit the $ sign.
This does not work
In recent powershell versions, there's also specific parameter called -PipelineVariable (alias pv). See:
True. PipelineVariable introduced in PowerShell 4.0 helps further optimize the code for parameter management.