Pipeline Deeper

Hey Guys,

I’ve read chapter nine, done lab, started to play with the shell and I have one question :slight_smile:

First, please look at the code. The CSV file contains only two lines, one filled with ‘Name’ another filled with ‘DESKTOP-001’.

Code Example

Both Get-Service and Get-Process have a parameter called -ComputerName which accept input ByPropertyName. The code above works fine with Get-Process and Get-Hotfix but somehow it failed when I piped into Get-Service. Instead of linking ByPropertyName with my custom property, the shell is trying to link it with Get-Service’s Name.

Here is an error code: Cannot find any service with service name ‘@{ComputerName=DESKTOP-001}’.

The only difference I found is in parameter Name, in Get-Service it accepts both ByPropertyName and ByValue, in comparison to the Get-Process where it only accepts ByPropertyName. It doesn’t make sense for me, why the shell is trying to link PSCustomObject, which is returned by Select, with Get-Service’s Name (String).

I know there is another way to do it- the last line in the code, but I’m curious why this one has failed.

Any help will be appreciated.

Have a nice day,
Tom

Please don’t re-post multiple times; you triggered the spam filters.

Yeah, CSV gets goofy sometimes. There’s a lot of fiddling happening under the hood and sometimes it doesn’t all fit up. That’s actually changed a bit between versions; sometimes, you’ll find that it works fine. But yeah, you’re seeing it trying to bind a hash table, run through a string converter, to -Name. Not the intended behavior but it’s what it’s doing.

Sorry for multiple posts, I’ve had a problem with MS Edge. Thanks for the reply.

Tom

I would wager that it simply doesn’t have a valid parameter set for the pipeline input you’re trying to give it. That, or there’s something a little flawed in its logic of how its choosing to bind parameters.

In this case, you can do things a little differently to work around this:

Import-Csv C:\PowerShellOutput\desktop.csv | Get-Process -ComputerName {$_.Name} 

Thanks for interesting in this topic.

I tried to run what you type yesterday before I thought about leaving a question here, but this isn’t working either - or to be precise, this works only with Get-Hotfix, with Get-Process and Get-Service we have the same situation, the shell is trying to pipe it to a process name or a service name. Your example should work because PSCustomObject has a String NoteProperty and -ComputerName also want a string object.

I think Don is right, maybe something under the hood is going incorrectly or I have broken the shell somehow :slight_smile:

I will paste you the output below, both commands and errors.

PS C:\Windows\system32> Import-Csv C:\PowerShellOutput\desktop.csv | Get-Process -ComputerName {$PSItem.Name}
Get-Process : Cannot find a process with the name "DESKTOP-001". Verify the process name and call the cmdlet again.
At line:1 char:46
+ ... werShellOutput\desktop.csv | Get-Process -ComputerName {$PSItem.Name}
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (DESKTOP-001:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
 

PS C:\Windows\system32> Import-Csv C:\PowerShellOutput\desktop.csv | Get-Service -ComputerName {$PSItem.Name}
Get-Service : Cannot find any service with service name 'DESKTOP-001'.
At line:1 char:46
+ ... werShellOutput\desktop.csv | Get-Service -ComputerName {$PSItem.Name}
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (DESKTOP-001:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

Have a nice Sunday,
Tom

Hmm, you’re right, it looks like it won’t accept only the computername as parameter, and keeps trying to bind whatever it’s given to Name.

Perhaps the ValueFromPipeline supersedes the ValueFromPipelineByPropertyName when only one value is present for it to take. Weird. You should be able to just add in -Name “*” to force it to retrieve all services on the specified machine, though. :slight_smile:

Yes, you are right, with -Name * it works fine.

Import-Csv C:\PowerShellOutput\desktop.csv | Get-Service -Name * -ComputerName {$PSItem.Name}
Import-Csv C:\PowerShellOutput\desktop.csv | Get-Process -Name * -ComputerName {$PSItem.Name}

Yep, providing the name works:

[pscustomobject]@{computername='desktop-001'} | get-service -name *

You can try trace-command, but it’s hard to read ([UPDATED] Figuring Out Pipeline Input Binding Using Trace-Command | ITPro Today: IT News, How-Tos, Trends, Case Studies, Career Tips, More). There sure is a lot going on under the hood, lol.

EDIT:
I guess since -name can accept pipe byvalue, which is a string, it tries to use ‘@{computername=desktop-001}’ as a string, which seems like an obscure bug. Even powershell 6 does it.

Trace-Command -Name ParameterBinding -PSHost -Expression { [pscustomobject]@{computername='desktop-001'} | 
  get-service }

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Service]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Service]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-Service]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Get-Service]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [Name] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [@{computername=desktop-001}] to parameter [Name]
DEBUG: ParameterBinding Information: 0 :         Binding collection parameter Name: argument type [PSObject], parameter
 type [System.String[]], collection type Array, element type [System.String], no coerceElementType
DEBUG: ParameterBinding Information: 0 :         Creating array with element type [System.String] and 1 elements
DEBUG: ParameterBinding Information: 0 :         Argument type PSObject is not IList, treating this as scalar
DEBUG: ParameterBinding Information: 0 :         BIND arg [@{computername=desktop-001}] to param [Name] SKIPPED
DEBUG: ParameterBinding Information: 0 :     Parameter [ComputerName] PIPELINE INPUT ValueFromPipelineByPropertyName NO
 COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [desktop-001] to parameter [ComputerName]
DEBUG: ParameterBinding Information: 0 :         Binding collection parameter ComputerName: argument type [String],
parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
DEBUG: ParameterBinding Information: 0 :         Creating array with element type [System.String] and 1 elements
DEBUG: ParameterBinding Information: 0 :         Argument type String is not IList, treating this as scalar
DEBUG: ParameterBinding Information: 0 :         Adding scalar element of type String to array position 0
DEBUG: ParameterBinding Information: 0 :         Executing VALIDATION metadata:
[System.Management.Automation.ValidateNotNullOrEmptyAttribute]
DEBUG: ParameterBinding Information: 0 :         BIND arg [System.String[]] to param [ComputerName] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 :     Parameter [Name] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
DEBUG: ParameterBinding Information: 0 :     Parameter [Name] PIPELINE INPUT ValueFromPipeline WITH COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [@{computername=desktop-001}] to parameter [Name]
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.String[]]
DEBUG: ParameterBinding Information: 0 :             Trying to convert argument value from
System.Management.Automation.PSObject to System.String[]
DEBUG: ParameterBinding Information: 0 :             ENCODING arg into collection
DEBUG: ParameterBinding Information: 0 :             Binding collection parameter Name: argument type [PSObject],
parameter type [System.String[]], collection type Array, element type [System.String], coerceElementType
DEBUG: ParameterBinding Information: 0 :             Creating array with element type [System.String] and 1 elements
DEBUG: ParameterBinding Information: 0 :             Argument type PSObject is not IList, treating this as scalar
DEBUG: ParameterBinding Information: 0 :             COERCE arg to [System.String]
DEBUG: ParameterBinding Information: 0 :                 Trying to convert argument value from
System.Management.Automation.PSObject to System.String
DEBUG: ParameterBinding Information: 0 :                 CONVERT arg type to param type using
LanguagePrimitives.ConvertTo
DEBUG: ParameterBinding Information: 0 :                 CONVERT SUCCESSFUL using LanguagePrimitives.ConvertTo:
[@{computername=desktop-001}]
DEBUG: ParameterBinding Information: 0 :             Adding scalar element of type String to array position 0
DEBUG: ParameterBinding Information: 0 :         BIND arg [System.String[]] to param [Name] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Get-Service]
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Out-Default]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.ErrorRecord]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to parameter [InputObject]
DEBUG: ParameterBinding Information: 0 :         BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to param [InputObject] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Out-Default]
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Out-LineOutput]
DEBUG: ParameterBinding Information: 0 :     BIND arg [Microsoft.PowerShell.Commands.Internal.Format.ConsoleLineOutput]
 to parameter [LineOutput]
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Object]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         BIND arg
[Microsoft.PowerShell.Commands.Internal.Format.ConsoleLineOutput] to param [LineOutput] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Out-LineOutput]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Out-LineOutput]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Out-LineOutput]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.ErrorRecord]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to parameter [InputObject]
DEBUG: ParameterBinding Information: 0 :         BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to param [InputObject] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [out-lineoutput]
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Format-Default]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Format-Default]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Format-Default]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Format-Default]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.Management.Automation.ErrorRecord]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to parameter [InputObject]
DEBUG: ParameterBinding Information: 0 :         BIND arg [Cannot find any service with service name
'@{computername=desktop-001}'.] to param [InputObject] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [format-default]
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 :     BIND arg [1] to parameter [Version]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ArgumentToVersionTransformationAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: 1.0
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Version]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         Executing VALIDATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ValidateVersionAttribute]
DEBUG: ParameterBinding Information: 0 :         BIND arg [1.0] to param [Version] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 :     BIND arg [1] to parameter [Version]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ArgumentToVersionTransformationAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: 1.0
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Version]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         Executing VALIDATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ValidateVersionAttribute]
DEBUG: ParameterBinding Information: 0 :         BIND arg [1.0] to param [Version] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 :     BIND arg [1] to parameter [Version]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ArgumentToVersionTransformationAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: 1.0
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Version]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         Executing VALIDATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ValidateVersionAttribute]
DEBUG: ParameterBinding Information: 0 :         BIND arg [1.0] to param [Version] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 :     BIND arg [1] to parameter [Version]
DEBUG: ParameterBinding Information: 0 :         Executing DATA GENERATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ArgumentToVersionTransformationAttribute]
DEBUG: ParameterBinding Information: 0 :             result returned from DATA GENERATION: 1.0
DEBUG: ParameterBinding Information: 0 :         COERCE arg to [System.Version]
DEBUG: ParameterBinding Information: 0 :             Parameter and arg types the same, no coercion is needed.
DEBUG: ParameterBinding Information: 0 :         Executing VALIDATION metadata:
[Microsoft.PowerShell.Commands.SetStrictModeCommand+ValidateVersionAttribute]
DEBUG: ParameterBinding Information: 0 :         BIND arg [1.0] to param [Version] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-StrictMode]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
get-service : Cannot find any service with service name '@{computername=desktop-001}'.
At line:1 char:105
+ ... pression  { [pscustomobject]@{computername='desktop-001'} | get-service }
+                                                             ~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (@{computername=desktop-001}:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing

Thank you js!

We’ve reached the place where my curiosity has ended :slight_smile: Not because I’m lazy, or maybe I am, but because the lack of knowledge, I will back to this someday. Now I try to stick to the schedule and read one chapter per day.

Thank you all guys,
Tom

My curiosity hasn’t. :slight_smile: I tried to roll my own script with one pipe byvalue parameter and one pipe bypropertyname parameter, and hilarity ensued.

myscript.ps1:

[cmdletbinding()]
Param (
  [parameter(ValueFromPipeline=$True)]
  [string]$string1='string1',
  [parameter(ValueFromPipelineByPropertyName=$True)]
  [string]$string2
)
Process {
  "string1 is $string1"
  "string2 is $string2"
}

Running it:

PS C:\users\js> $a = [pscustomobject]@{string2='string2'}
PS C:\users\js> $a

string2
-------
string2


PS C:\users\js> $a | .\myscript
string1 is @{string2=string2}
string2 is string2

$string1 becomes ‘@{string2=string2}’, the string version of the hash table (‘coercion’), even if it has a default value of ‘string1’. The same data is also used for $string2 in the way I intended.

I’ve changed the execution policy for ‘Unrestricted’ just for a while to run your script. Of course, because of curiousity :slight_smile:

PS C:\Windows\system32> $a | C:\PowerShellOutput\Untitled1.ps1
string1 is @{string2=string2}
string2 is string2

Bye the way, thanks for a simple scripting lesson.

You can set the execution policy as remotesigned. That’s the default in later os’s.