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.
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 @_
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With