This write up should give you a basic understanding how pipeline objects are processed. The piping technique allows a kind of connection between commands. Piping is a key technologie in PowerShell. In this blog post I am going to have a look at the parameter binding on the “right side” of the pipe. In order to do this I will use the cmdlet Trace-Command to explore what’s going on when an object is passing the pipe from the left side to the right side. Let’s jump in.
Introduction
First of all, I give you a quick overview what is happening when you use piping. I’ve prepard a picture that shows the mechanism of the pipe in PowerShell.
The question now is to which parameter of Stop-Process is the object of the pipe bound? Let’s examine which parameters support pipeline input. We can figure it out easily with Get-Help.
Get-Help Stop-Process -Parameter * | Where-Object pipelineinput -Like 'true*'
Understanding PowerShell Pipeline Binding
Let’s first explore the most obvious way how PowerShell binds pipeline objects. PowerShell takes objects that come from on the left side of the pipe and then binds this objects to a parameter that accepts process objects.
For example, InputObject expects and accepts only process objects.
Get-Help Stop-Process -Parameter InputObject
This means that process objects are expected and that we need to provide this object on the left side of the pipe. PowerShell will then bind the process object to the parameter InputObject by value. The screen below shows the action.
Proof that this is really happening is provided by the Trace-Command cmdlet.
Trace-Command -Name ParameterBinding -Expression {Get-Process notepad | Stop-Process} -PSHost
Nice. The object on the left side of the pipe was bound to the InputObject parameter.
Next, let’s have a look at what is happening when the object that passes the pipe is not a process object …
The error message says …
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 match any of the parameters that take pipepline input.
Hey, that’s wrong! We actually have 3 parameters that accepts pipeline input … What’s going on here?
Remember, we have three parameters. None of them will be able to process the pipeline object ‘notepad’ and we will now see why. For clarifying let me show you the object type of ‘notepad’:
Notepad is a String.
Among other things, PowerShell tries to bind the argument to the Name parameter. However, the Name Parameter accepts only strings of Name objects. ‘notepad’ is not a Name Object. The picture below shows that it is as I prophesied it would be. Powershell will not try to bind the string to the Name parameter nor to the id parameter.
Trace-Command -Name ParameterBinding -Expression {'notepad' | Stop-Process} -PSHost
How can we now make PowerShell accept the string (PSCostumObject) notepad? The answer is that we need to make Notepad a Name object.
$a=Get-Process -Name notepad | Select-Object -Property Name
Note the difference between the current notepad object and the previous notepad object.
Fine. Notepad’s property name now matches the parameter name “Name”.
Now we can pipe the object to Stop-Process.
$a | Stop-Process
With Trace-Command we can check again what PowerShell has done. PowerShell has bound the pipeline object to the Name parameter because the pipeline object property name matches the “Name” parameter name.
I hope I could give a good insight into the topic and see you next time!
Links
Categories: PowerShell
Hey Patrick. I don’t know if you can help me understand this or not but this post led me to investigate parameter binding in one of the commands I was trying to do which was failing. I can see where it’s failing (arg is null) and know how to make it work but I don’t understand why it doesn’t work as it is.
The command is: $files | get-filehash -literalpath $_
Where $files is a string array of file paths. The trace-command says that the $_ var is null. It also fails with get-filehash -literalpath ($_)
However, it works with $files | get-filehash -literalpath {$_} which is including a script block. What is going on here?
Thank you!! (Duplicate for email alerts)
LikeLike
Hi,
Place $_ in curly braces, I would recommend.
Besst,
P
LikeLike
Hey Patrick. I don’t know if you can help me understand this or not but this post led me to investigate parameter binding in one of the commands I was trying to do which was failing. I can see where it’s failing (arg is null) and know how to make it work but I don’t understand why it doesn’t work as it is.
The command is: $files | get-filehash -literalpath $_
Where $files is a string array of file paths. The trace-command says that the $_ var is null. It also fails with get-filehash -literalpath ($_)
However, it works with $files | get-filehash -literalpath {$_} which is including a script block. What is going on here?
Thank you!!
LikeLike
Nice one.. gave me a better insight into PS parameter binding and especially an into into the useful cmd Trace-Command.
LikeLike
Thank you!
LikeLike