Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I pass two parameters to pipeline?

Tags:

powershell

I wrote a PowerShell cmdlet in C# which originally took several parameters, but only accepted one from pipeline input. I condensed the other parameters into a single, custom C# object, which I want to take as input from the pipeline. Here is the relevant code:

[Parameter(ValueFromPipeline = true, Mandatory = true)]
public DataObj Data {get; set;}

[Parameter(ValueFromPipeline = true, Mandatory = false)]
public DataSettings Settings {get; set;} = new DataSettings();

public class DataObj {
     public string Name {get; set;}
     public int Value {get; set;}
     ...
}

public class DataSettings {
    public DataInfo Info {get; set;} = new DataInfo();
    public string Description {get; set} = "";
}

I have been able to succesfully create the DataSettings object from a HashTable in PowerShell before modified it to be taken as pipeline input.

I have tried:

@{Data = $DataObj; Settings = $DataSettings;} | Add-Data

As well as:

$DataObj $DataSettings | Add-Data

With the thought that from what I have read on PowerShell parameter binding, the pipeline input would be bound to the parameter which it could be converted to. In my PowerShell script both $DataSettings and $DataObj are a HashTable containing the relevant properties.

When I run either of the above lines in my PowerShell script I get the "Input object cannot be bound to any parameters..." error.

Is it possible to take two inputs from the pipeline in this way? I had considered creating a single custom C# object to encapsulate both of the input objects, but I had been trying to keep the mandatory portion separate from the non-required portion.

Also, I tried running the Trace-Command, but after trying:

Trace-Command ParameterBinding {Add-Data $Input} -PSHost -InputObject @{Data = $DataObj; Settings = $DataSettings;}

I received an error that no parameter matched the name Data. I was trying to follow this tutorial, but evidently I am doing something wrong.

like image 234
pavuxun Avatar asked Sep 03 '25 10:09

pavuxun


1 Answers

When you use the pipeline, wrapping your input objects into a single object is the only way to bind them each to a distinct parameter, and to do so you can use delay-bind script blocks:

@{ Data = $DataObj; Settings = $DataSettings } |
  Add-Data -Data { $_.Data } -Settings { $_.Settings }

Independently of the pipeline, you can use splatting to achieve the same effect more elegantly:

# Construct the arguments to pass as a hashtable.
$htArgs = @{ Data = $DataObj; Settings = $DataSettings }

# Pass the arguments via splatting (note the '@')
Add-Data @htArgs

You can combine the two techniques via ForEach-Object, but note that this will be less efficient with multiple inputs, because a separate call to Add-Data is then made in each iteration:

@{ Data = $DataObj; Settings = $DataSettings } | ForEach-Object {
  Add-Data @_
}
like image 111
mklement0 Avatar answered Sep 04 '25 23:09

mklement0