I’ve been using PowerShell for around 4 years but this week for the first time I’m attending some classroom training and I came across some behaviour that we couldn’t explain completely.
The exercise was based around creating a calculated property in order for it to be accepted through the pipeline as input for the next cmdlet.
This is the example given, and it works but in my understanding it should not
I understand that the property name needs changed to match the accepted parameter on Get-Service, hence the calculated property. Also that it effectively adds “-Computername [value]” invisibly when it runs Get-Service, for each iteration. However, in the second line of code the object type that comes over the pipe is an ADComputer object and so will not be accepted by Get-Service. I verified this using Get-Member.
The first line of code, given in the course material works fine. It’s like in the first example the ADComputer object is being expanded out to the strings it contains and in the second, it is not. The only difference is the “-name *” which refers to the service name and as I understand it should have no effect.
Normally I would ignore this and find another way to write the code but this is purely an academic question because I’m looking for a deeper understanding. Have I understood this incorrectly? Is it a bug? Something to do with positional parameters? Ghosts?
Get-Service is a bit bugged in that respect. It should work like that (just piping an object into the cmdlet with the right property names) but I believe (not sure whether it’s a bug in the pipeline logic or the cmdlet itself) it also inserts the input value as the -Name parameter of Get-Service despite you specifying it as ComputerName by the property name.
I’ll have to remember to file an issue in the PS Core repo; pretty sure that issue is still around.
In the meantime, there’s something else you can do with ByPropertyName-enabled parameters:
Note that here I’m passing a script block to the parameter. This essentially forces the pipeline logic to bind the requested value in that place. Within that script block, $_ refers to the input objects as they come over the pipeline, and you can access any of their properties to pass to the parameter.
This can be done for any number of parameters, each taking a separate script block, but only if they’re declared as supporting input by property name.
However, if the bug is in the cmdlet itself… it’s possible that it’ll exhibit the same behaviour.
So, interestingly enough, PS Core actually removed the -ComputerName parameter from Get-Service; not sure why. Perhaps related… and there aren’t any other ByPropertyName parameters on that cmdlet. I would generally assume that only -Name will work correctly with pipeline input (it does seem to be what the help documentation states, with the exception of -ComputerName).
So for whatever reason, the declared attributes of that parameter don’t seem to match the established code paths.
PSCore was changed from computer name to hostname. Only the PS Team will know why (though it does not matter, it’s what we’re stuck with now), but this was also talked about in the ‘BRK3069 - What’s new in PowerShell’ breakout session at MSIgnite 2018. I know this because I was in that session. Specifically shown at this time marker:
This is a known issue with ALL powershell cmdlets. If a parameter that can be sent over the pipe “byvalue” isn’t specified by argument (like “name”), other parameters sent “bypropertyname” over the pipe get messed up.