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



我在C#中有一些类,我想在管道中使用它们,我看过关于它的文章,但我还没能做到。

以下是我现在如何使用它:

$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')

我希望能够像这样与管道一起使用:

$suite = [MyProject.SuiteBuilder]::CreateSuite('my house')
$suite | AddSet('doors', 'These represents doors') `
| AddOption('blue', 'kitchen') `
| AddOption('black', 'bedreoom') `
| AddOption('white', 'toilet')

以下是我的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;
}
}

我正在努力使这些函数可以在管道形式中调用

我还在每个需要调用的评论之前添加了一个类似call this method in pipeline的评论。

简而言之,您需要:

  • 使用[Parameter(ValueFromPipeline =true)]接受管道中的参数
  • 通过调用process方法中的WriteObject方法向管道提供输出

详细的逐步回答

在这篇文章中,我将重构您的代码,并向您展示如何在C#中创建Powershell Cmdlet,以及如何定义参数接受管道中的参数管道提供输出。然后你可以很容易地写下这样的东西:

$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
| Add-Option "color1" "place1"`
| Add-Option "color2" "place2" | Out-Null

为此,请执行以下步骤:

  1. 创建一个C#类库项目(例如,将其命名为MyCmdlets(
  2. 安装程序包Microsoft.PowerShell.5.ReferenceAssemblies
  3. 创建独立于PowerShell的模型类。(请参阅帖子底部的代码(
  4. 创建cmdlet时要考虑以下注意事项:(请参阅文章底部的代码(

    • 对于每个cmdlet,创建一个C#类
    • 源自Cmdlet
    • 用指定动词和动词后的名称的CmdletAttribute属性装饰类,例如,如果您想要Add-Set,请使用[Cmdlet(VerbsCommon.Add, "Set")]
    • 如果要为管道提供输出,请使用指定输出类型的OutputTypeAttribute属性来装饰类,例如,如果要为管线提供Set类型的输出,则使用[OutputType(typeof(Set))]
    • 根据cmdlet的每个输入参数,定义一个C#属性
    • Parameter属性修饰每个参数属性
    • 如果要接受管道中的参数,则在使用ParameterAttribute属性进行装饰时,请将ValueFromPipeline设置为true,例如[Parameter(ValueFromPipeline =true)
    • 要向管道提供输出,请重写管道处理方法,如ProcessRecord和使用WriteObject将写入输出
  5. 构建项目。

  6. 打开PowerShell ISE并运行以下代码:

    Import-Module "PATH TO YOUR BIN DEBUG FOLDERMyCmdlets.dll"
    $suite = [MyCmdLets.Suite]::New("suite1")
    $suite | Add-Set "type1" "desc1"`
    | Add-Option "color1" "place1"`
    | Add-Option "color2" "place2" | Out-Null
    

    它将创建这样一个结构:

    Name   Sets           
    ----   ----           
    suite1 {MyCmdlets.Set}
    
    Type  Description Options                             
    ----  ----------- -------                             
    type1 desc1       {MyCmdlets.Option, MyCmdlets.Option}
    
    Color  Place 
    -----  ----- 
    color1 place1
    color2 place2
    

示例代码

型号类别

如上所述,设计独立于PowerShell的模型类,如下所示:

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类

还根据我上面描述的注释设计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);
}
}
}

您可以使用ValueFromPipeline=$true。但是,如果要继续管道,则必须引用类型变量并返回项。我不知道如何解决这个问题。由于它将返回,您必须在末尾添加一个Out-Null,以防止它进入控制台。

https://learn.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

最新更新