简体   繁体   English

在 C# 中创建 PowerShell Cmdlet - 管道链接

[英]Create PowerShell Cmdlets in C# - Pipeline chaining

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.我在 C# 中有一些类,我想在管道中使用它们,我已经看过有关它的文章,但我还没有做到。

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:这是我的 C# 类:

//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.我正在努力使这些 function 可以以管道形式调用。

I also added a comment like call this method in pipeline before each comment that I need to call.我还在需要调用的每个注释之前添加了一条注释,例如call this method in pipeline

In short, you need to:简而言之,您需要:

  • Accept parameter from pipeline by using [Parameter(ValueFromPipeline =true)]使用[Parameter(ValueFromPipeline =true)]接受来自管道的参数
  • Provide output to pipeline by calling WriteObject method in process method通过在 process 方法中调用WriteObject方法将 output 提供给管道

Detailed Step by Step answer详细的一步一步的答案

In 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 .在这篇文章中,我将对您的代码进行一些重构,并将向您展示如何在 C# 中创建Powershell Cmdlet以及如何定义参数接受来自管道的参数并将Z78E6221F6393D1356681DB.D 管道提供给管道 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:为此,请按照下列步骤操作:

  1. Create a C# class Library Project (for example name it MyCmdlets )创建一个 C# class 库项目(例如将其命名为MyCmdlets
  2. Install Package Microsoft.PowerShell.5.ReferenceAssemblies安装 Package Microsoft.PowerShell.5.ReferenceAssemblies
  3. Create your model classes, independent from PowerShell.创建您的 model 类,独立于 PowerShell。 (See the code at the bottom of post) (见帖子底部的代码)
  4. Create the cmdlets considering the following notes: (See the code at the bottom of post)考虑以下注意事项创建 cmdlet:(请参阅帖子底部的代码)

    • Per each cmdlet, create a C# class对于每个 cmdlet,创建一个 C# class
    • Derive from Cmdlet classCmdlet class 派生
    • Decorate the class with CmdletAttribute attribute specifying the verb and the name after verb, for example if you want to have Add-Set , use [Cmdlet(VerbsCommon.Add, "Set")] .使用CmdletAttribute属性来装饰 class,指定动词和动词后的名称,例如,如果您想要Add-Set ,请使用[Cmdlet(VerbsCommon.Add, "Set")]
    • If you want to have an output for pipeline, decorate the class with 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))] . If you want to have an output for pipeline, decorate the class with 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))] .
    • Per each input parameter of your cmdlet, define a C# property.根据 cmdlet 的每个输入参数,定义一个 C# 属性。
    • Decorate each parameter property by Parameter attribute.通过Parameter属性装饰每个参数属性。
    • If you want to accept a parameter from pipeline, when decorating with ParameterAttribute attribute, set ValueFromPipeline to true, fro example [Parameter(ValueFromPipeline =true)如果你想接受来自管道的参数,当使用ParameterAttribute属性进行装饰时,将ValueFromPipeline设置为 true,例如[Parameter(ValueFromPipeline =true)
    • To provide output to pipeline, override pipeline processing methods like ProcessRecord and using WriteObject write the to output.要将 output 提供给管道,请覆盖ProcessRecord等管道处理方法并使用WriteObject将其写入 output。
  5. Build the project.构建项目。

  6. Open PowerShell ISE and run the following code:打开 PowerShell ISE 并运行以下代码:

     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

Sample Code示例代码

Model Classes Model 类

As mentioned above, design your model classes independent from PowerShell like this:如上所述,设计独立于 PowerShell 的 model 类,如下所示:

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 CmdLet 类

Also design the cmdlet classes based on notes which I describe above:还要根据我上面描述的注释设计 cmdlet 类:

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);
        }
    }
}

You can use ValueFromPipeline = $true.您可以使用 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.由于它会返回,因此您必须在末尾添加一个Out-Null以防止它击中控制台。

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-6 https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-6

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM