Reputation: 817
I have some classes in C# which I would like to use them in pipelines, I've seen articles about it but I haven't been able to do it yet.
Here's how I am using it right now:
$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')
$houseSet = $suite.AddSet('doors', 'These represents doors')
$houseSet.AddOption('blue', 'kitchen')
$houseSet.AddOption('black', 'bedreoom')
$houseSet.AddOption('white', 'toilet')
And I want to be able to use it like this with pipelines:
$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')
$suite | AddSet('doors', 'These represents doors') `
| AddOption('blue', 'kitchen') `
| AddOption('black', 'bedreoom') `
| AddOption('white', 'toilet')
Here are my C# classes:
//SuiteBuilder.cs
public static class SuiteBuilder
{
public static Suite CreateTestSuite(string name)
{
return new Suite(name);
}
}
//Suite.cs
public class Suite : PSCmdlet
{
public string Name { get; set; }
public IEnumerable<Set> Sets { get; set; }
public Suite(string name)
{
Name = name;
Sets = new List<Set>();
}
// call this method in pipeline
public Set AddSet(string type, string description)
{
Sets.Add(new Set(type, description));
return Sets.Last();
}
}
//Set.cs
public class Set : PSCmdlet
{
public string Type { get; set; }
public string Description { get; set; }
public IEnumerable<Option> Options { get; set; }
public Set(string type, string description)
{
Type = type;
Description = description;
Options = new List<Option>();
}
// call this method from pipeline
public Set AddOption(string color, string place)
{
Options.Add(new Option(color, place));
return this;
}
}
//option.cs
public class Option : PSCmdlet
{
public string Color { get; set; }
public string Place { get; set; }
public Option(string color, string place)
{
Color = color;
Place = place;
}
}
And I am struggling to make these function available to call in the pipeline form.
I also added a comment like call this method in pipeline
before each comment that I need to call.
Upvotes: 5
Views: 1021
Reputation: 125197
In short, you need to:
[Parameter(ValueFromPipeline =true)]
WriteObject
method in process methodIn this post I'll refactor your code a bit and will show you how you can create Powershell Cmdlet in C# and how to define parameters, accept parameter from pipeline and provide output to pipeline. Then you can easily write something like:
$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
| Add-Option "color1" "place1"`
| Add-Option "color2" "place2" | Out-Null
To do so, follow these steps:
MyCmdlets
)Microsoft.PowerShell.5.ReferenceAssemblies
Create the cmdlets considering the following notes: (See the code at the bottom of post)
Cmdlet
classCmdletAttribute
attribute specifying the verb and the name after verb, for example if you want to have Add-Set
, use [Cmdlet(VerbsCommon.Add, "Set")]
.OutputTypeAttribute
attribute specifying the type of output, for example if you want to have an output of type Set
for the pipeline, use [OutputType(typeof(Set))]
.Parameter
attribute.ParameterAttribute
attribute, set ValueFromPipeline
to true, fro example [Parameter(ValueFromPipeline =true)
ProcessRecord
and using WriteObject
write the to output.Build the project.
Open PowerShell ISE and run the following code:
Import-Module "PATH TO YOUR BIN DEBUG FOLDER\MyCmdlets.dll"
$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
| Add-Option "color1" "place1"`
| Add-Option "color2" "place2" | Out-Null
It will create a structure like this:
Name Sets
---- ----
suite1 {MyCmdlets.Set}
Type Description Options
---- ----------- -------
type1 desc1 {MyCmdlets.Option, MyCmdlets.Option}
Color Place
----- -----
color1 place1
color2 place2
Model Classes
As mentioned above, design your model classes independent from PowerShell like this:
using System.Collections.Generic;
namespace MyCmdlets
{
public class Suite
{
public string Name { get; set; }
public List<Set> Sets { get; } = new List<Set>();
public Suite(string name) {
Name = name;
}
}
public class Set
{
public string Type { get; set; }
public string Description { get; set; }
public List<Option> Options { get; } = new List<Option>();
public Set(string type, string description) {
Type = type;
Description = description;
}
}
public class Option
{
public string Color { get; set; }
public string Place { get; set; }
public Option(string color, string place) {
Color = color;
Place = place;
}
}
}
CmdLet Classes
Also design the cmdlet classes based on notes which I describe above:
using System.Management.Automation;
namespace MyCmdlets
{
[Cmdlet(VerbsCommon.Add, "Set"), OutputType(typeof(Set))]
public class AddSetCmdlet : Cmdlet
{
[Parameter(ValueFromPipeline = true, Mandatory = true)]
public Suite Suite { get; set; }
[Parameter(Position = 0, Mandatory = true)]
public string Type { get; set; }
[Parameter(Position = 1, Mandatory = true)]
public string Description { get; set; }
protected override void ProcessRecord() {
var set = new Set(Type, Description);
Suite.Sets.Add(set);
WriteObject(set);
}
}
[Cmdlet(VerbsCommon.Add, "Option"), OutputType(typeof(Option))]
public class AddOptionCmdlet : Cmdlet
{
[Parameter(ValueFromPipeline = true, Mandatory = true)]
public Set Set { get; set; }
[Parameter(Position = 0, Mandatory = true)]
public string Color { get; set; }
[Parameter(Position = 1, Mandatory = true)]
public string Place { get; set; }
protected override void ProcessRecord() {
var option = new Option(Color, Place);
Set.Options.Add(option);
WriteObject(Set);
}
}
}
Upvotes: 4
Reputation: 115
You can use ValueFromPipeline = $true. However, you will have to reference the type variable, and return the item if you want to continue the pipeline. I don't know of a way to work around this. Since it will return, you would have to add an Out-Null
at the end to prevent it from hitting console.
function Add-Option {
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[ref]$Item,
[Parameter(Mandatory = $true, Position = 0)]
[String]$Color
[Parameter(Mandatory = $true, Position = 1)]
[String]$Room
)
$Item.Value.AddOption($Color,$Room)
return $Item
}
$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')
[ref]$suite | Add-Option 'blue' 'kitchen' `
| Add-Option 'black' 'bedroom' `
| Out-Null
Upvotes: 0