在 C# 中创建 PowerShell Cmdlet - 管道链
Create PowerShell Cmdlets in C# - Pipeline chaining
我在 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
。
您可以使用 ValueFromPipeline = $true。但是,如果要继续管道,则必须引用类型变量和 return 项目。我不知道解决这个问题的方法。由于它将 return,您必须在末尾添加一个 Out-Null
以防止它到达控制台。
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
简而言之,您需要:
- 使用
[Parameter(ValueFromPipeline =true)]
从管道接受参数
- 通过调用进程方法中的
WriteObject
方法向管道提供输出
详细的步骤回答
在此 post 中,我将稍微重构您的代码,并向您展示如何在 C# 中创建 Powershell Cmdlet 以及如何 定义参数 ,从管道接受参数并向管道提供输出。然后你可以很容易地写这样的东西:
$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
| Add-Option "color1" "place1"`
| Add-Option "color2" "place2" | Out-Null
为此,请按照下列步骤操作:
- 创建一个 C# class 库项目(例如将其命名为
MyCmdlets
)
- 安装包
Microsoft.PowerShell.5.ReferenceAssemblies
- 创建您的模型 classes,独立于 PowerShell。 (见post底部代码)
根据以下注意事项创建 cmdlet:(请参阅 post 底部的代码)
- 为每个 cmdlet 创建一个 C# class
- 源自
Cmdlet
class
- 用
CmdletAttribute
属性修饰 class,指定动词和动词后的名称,例如,如果您想要 Add-Set
,请使用 [Cmdlet(VerbsCommon.Add, "Set")]
。
- 如果您想要管道输出,请使用指定输出类型的
OutputTypeAttribute
属性修饰 class,例如,如果您想要输出类型 Set
对于管道,使用 [OutputType(typeof(Set))]
.
- 为您的 cmdlet 的每个输入参数定义一个 C# 属性。
- 通过
Parameter
属性修饰每个参数 属性。
- 如果你想从管道接受一个参数,当用
ParameterAttribute
attribute, set ValueFromPipeline
修饰时为true,例如[Parameter(ValueFromPipeline =true)
- 要向管道提供输出,覆盖管道处理方法,例如
ProcessRecord
and using WriteObject
写入输出。
构建项目。
打开 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
它将创建这样的结构:
Name Sets
---- ----
suite1 {MyCmdlets.Set}
Type Description Options
---- ----------- -------
type1 desc1 {MyCmdlets.Option, MyCmdlets.Option}
Color Place
----- -----
color1 place1
color2 place2
示例代码
型号类
如上所述,设计您的模型 classes 独立于 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 classes:
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);
}
}
}
我在 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
。
您可以使用 ValueFromPipeline = $true。但是,如果要继续管道,则必须引用类型变量和 return 项目。我不知道解决这个问题的方法。由于它将 return,您必须在末尾添加一个 Out-Null
以防止它到达控制台。
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
简而言之,您需要:
- 使用
[Parameter(ValueFromPipeline =true)]
从管道接受参数
- 通过调用进程方法中的
WriteObject
方法向管道提供输出
详细的步骤回答
在此 post 中,我将稍微重构您的代码,并向您展示如何在 C# 中创建 Powershell Cmdlet 以及如何 定义参数 ,从管道接受参数并向管道提供输出。然后你可以很容易地写这样的东西:
$suite = [MyCmdLets.Suite]::New("suite1")
$suite | Add-Set "type1" "desc1"`
| Add-Option "color1" "place1"`
| Add-Option "color2" "place2" | Out-Null
为此,请按照下列步骤操作:
- 创建一个 C# class 库项目(例如将其命名为
MyCmdlets
) - 安装包
Microsoft.PowerShell.5.ReferenceAssemblies
- 创建您的模型 classes,独立于 PowerShell。 (见post底部代码)
根据以下注意事项创建 cmdlet:(请参阅 post 底部的代码)
- 为每个 cmdlet 创建一个 C# class
- 源自
Cmdlet
class - 用
CmdletAttribute
属性修饰 class,指定动词和动词后的名称,例如,如果您想要Add-Set
,请使用[Cmdlet(VerbsCommon.Add, "Set")]
。 - 如果您想要管道输出,请使用指定输出类型的
OutputTypeAttribute
属性修饰 class,例如,如果您想要输出类型Set
对于管道,使用[OutputType(typeof(Set))]
. - 为您的 cmdlet 的每个输入参数定义一个 C# 属性。
- 通过
Parameter
属性修饰每个参数 属性。 - 如果你想从管道接受一个参数,当用
ParameterAttribute
attribute, setValueFromPipeline
修饰时为true,例如[Parameter(ValueFromPipeline =true)
- 要向管道提供输出,覆盖管道处理方法,例如
ProcessRecord
and usingWriteObject
写入输出。
构建项目。
打开 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
它将创建这样的结构:
Name Sets ---- ---- suite1 {MyCmdlets.Set} Type Description Options ---- ----------- ------- type1 desc1 {MyCmdlets.Option, MyCmdlets.Option} Color Place ----- ----- color1 place1 color2 place2
示例代码
型号类
如上所述,设计您的模型 classes 独立于 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 classes:
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);
}
}
}