Pipeline Deeper

Welcome Forums General PowerShell Q&A Pipeline Deeper

This topic contains 11 replies, has 4 voices, and was last updated by

js
 
Participant
6 months ago.

  • Author
    Posts
  • #100461

    Participant
    Points: 1
    Rank: Member

    Hey Guys,

    I've read chapter nine, done lab, started to play with the shell and I have one question 🙂

    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

  • #100468

    Keymaster
    Points: 1,624
    Helping HandTeam Member
    Rank: Community Hero

    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.

  • #100474

    Participant
    Points: 1
    Rank: Member

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

    Tom

  • #100476

    Participant
    Points: 160
    Helping Hand
    Rank: Participant

    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} 
  • #100480

    Participant
    Points: 1
    Rank: Member

    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 🙂

    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

  • #100485

    Participant
    Points: 160
    Helping Hand
    Rank: Participant

    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. 🙂

  • #100491

    Participant
    Points: 1
    Rank: Member

    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}
    
  • #100497
    js

    Participant
    Points: 207
    Helping Hand
    Rank: Participant

    Yep, providing the name works:

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

    You can try trace-command, but it's hard to read (http://www.itprotoday.com/management-mobility/updated-figuring-out-pipeline-input-binding-using-trace-command). 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
    
  • #100500

    Participant
    Points: 1
    Rank: Member

    Thank you js!

    We've reached the place where my curiosity has ended 🙂 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

    • #100528
      js

      Participant
      Points: 207
      Helping Hand
      Rank: Participant

      My curiosity hasn't. 🙂 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.

  • #100536

    Participant
    Points: 1
    Rank: Member

    I've changed the execution policy for 'Unrestricted' just for a while to run your script. Of course, because of curiousity 🙂

    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.

    • #100540
      js

      Participant
      Points: 207
      Helping Hand
      Rank: Participant

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

The topic ‘Pipeline Deeper’ is closed to new replies.