Powershell 二进制模块:Cmdlet 参数值的动态制表符完成
Powershell binary module: Dynamic tab completion for Cmdlet parameter values
我正在用 C# 编写二进制 Powershell 模块,我想要一个 Cmdlet,其参数提供动态的 运行-time tab 完成。但是,我正在努力弄清楚如何在二进制模块中执行此操作。这是我尝试让它工作的尝试:
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
namespace DynamicParameterCmdlet
{
[Cmdlet("Say", "Hello")]
public class MyCmdlet : PSCmdlet
{
[Parameter, PSTypeName("string")]
public RuntimeDefinedParameter Name { get; set; }
public MyCmdlet() : base() {
Collection<Attribute> attributes = new Collection<Attribute>() {
new ParameterAttribute()
};
string[] allowedNames = NameProvider.GetAllowedNames();
attributes.Add(new ValidateSetAttribute(allowedNames));
Name = new RuntimeDefinedParameter("Name", typeof(string), attributes);
}
protected override void ProcessRecord()
{
string name = (string)Name.Value;
WriteObject($"Hello, {Name}");
}
}
public static class NameProvider
{
public static string[] GetAllowedNames()
{
// Hard-coded array here for simplicity but imagine in reality this
// would vary at run-time
return new string[] { "Alice", "Bob", "Charlie" };
}
}
}
这行不通。我没有任何制表符完成功能。我也收到一个错误:
PS > Say-Hello -Name Alice
Say-Hello : Cannot bind parameter 'Name'. Cannot convert the "Alice" value of type "System.String" to type "System.Management.Automation.RuntimeDefinedParameter".
At line:1 char:17
+ Say-Hello -Name Alice
+ ~~~~~
+ CategoryInfo : InvalidArgument: (:) [Say-Hello], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,DynamicParameterCmdlet.MyCmdlet
我发现 an article 有一个示例,说明如何在非二进制 Powershell 模块中执行此操作。似乎在非二进制模块中,您包含 DynamicParam
后跟构建和 return 一个 RuntimeParameterDictionary
对象的语句。基于这个例子,我期望 PSCmdlet
class 中的等价物,也许是一个可覆盖的 GetDynamicParameters()
方法或类似的东西,就像有一个可覆盖的 BeginProcessing()
方法一样。
按照这个速度,二进制模块有望成为 Powershell 世界中的二等 class 公民。当然有一种我错过的方法可以做到这一点?
这是一种在 PowerShell v5 中实现自定义参数完成器的方法:
Add-Type @‘
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
[Cmdlet(VerbsDiagnostic.Test,"Completion")]
public class TestCompletionCmdlet : PSCmdlet {
private string name;
[Parameter,ArgumentCompleter(typeof(NameCompleter))]
public string Name {
set {
name=value;
}
}
protected override void BeginProcessing() {
WriteObject(string.Format("Hello, {0}", name));
}
private class NameCompleter : IArgumentCompleter {
IEnumerable<CompletionResult> IArgumentCompleter.CompleteArgument(string commandName,
string parameterName,
string wordToComplete,
CommandAst commandAst,
IDictionary fakeBoundParameters) {
return GetAllowedNames().
Where(new WildcardPattern(wordToComplete+"*",WildcardOptions.IgnoreCase).IsMatch).
Select(s => new CompletionResult(s));
}
private static string[] GetAllowedNames() {
return new string[] { "Alice", "Bob", "Charlie" };
}
}
}
’@ -PassThru|Select-Object -First 1 -ExpandProperty Assembly|Import-Module
特别是,您需要:
- 实现
IArgumentCompleter
接口。 Class 实现此接口应具有 public 默认构造函数。
- 将
ArgumentCompleterAttribute
属性应用于字段的 属性,用作 cmdlet 参数。作为属性的参数,您应该传递 IArgumentCompleter
实现。
- 在
IArgumentCompleter.CompleteArgument
中您有 wordToComplete
参数,因此您可以按用户已输入的文本过滤完成选项。
并尝试一下:
Test-Completion -Name Tab
我正在用 C# 编写二进制 Powershell 模块,我想要一个 Cmdlet,其参数提供动态的 运行-time tab 完成。但是,我正在努力弄清楚如何在二进制模块中执行此操作。这是我尝试让它工作的尝试:
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
namespace DynamicParameterCmdlet
{
[Cmdlet("Say", "Hello")]
public class MyCmdlet : PSCmdlet
{
[Parameter, PSTypeName("string")]
public RuntimeDefinedParameter Name { get; set; }
public MyCmdlet() : base() {
Collection<Attribute> attributes = new Collection<Attribute>() {
new ParameterAttribute()
};
string[] allowedNames = NameProvider.GetAllowedNames();
attributes.Add(new ValidateSetAttribute(allowedNames));
Name = new RuntimeDefinedParameter("Name", typeof(string), attributes);
}
protected override void ProcessRecord()
{
string name = (string)Name.Value;
WriteObject($"Hello, {Name}");
}
}
public static class NameProvider
{
public static string[] GetAllowedNames()
{
// Hard-coded array here for simplicity but imagine in reality this
// would vary at run-time
return new string[] { "Alice", "Bob", "Charlie" };
}
}
}
这行不通。我没有任何制表符完成功能。我也收到一个错误:
PS > Say-Hello -Name Alice
Say-Hello : Cannot bind parameter 'Name'. Cannot convert the "Alice" value of type "System.String" to type "System.Management.Automation.RuntimeDefinedParameter".
At line:1 char:17
+ Say-Hello -Name Alice
+ ~~~~~
+ CategoryInfo : InvalidArgument: (:) [Say-Hello], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,DynamicParameterCmdlet.MyCmdlet
我发现 an article 有一个示例,说明如何在非二进制 Powershell 模块中执行此操作。似乎在非二进制模块中,您包含 DynamicParam
后跟构建和 return 一个 RuntimeParameterDictionary
对象的语句。基于这个例子,我期望 PSCmdlet
class 中的等价物,也许是一个可覆盖的 GetDynamicParameters()
方法或类似的东西,就像有一个可覆盖的 BeginProcessing()
方法一样。
按照这个速度,二进制模块有望成为 Powershell 世界中的二等 class 公民。当然有一种我错过的方法可以做到这一点?
这是一种在 PowerShell v5 中实现自定义参数完成器的方法:
Add-Type @‘
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
[Cmdlet(VerbsDiagnostic.Test,"Completion")]
public class TestCompletionCmdlet : PSCmdlet {
private string name;
[Parameter,ArgumentCompleter(typeof(NameCompleter))]
public string Name {
set {
name=value;
}
}
protected override void BeginProcessing() {
WriteObject(string.Format("Hello, {0}", name));
}
private class NameCompleter : IArgumentCompleter {
IEnumerable<CompletionResult> IArgumentCompleter.CompleteArgument(string commandName,
string parameterName,
string wordToComplete,
CommandAst commandAst,
IDictionary fakeBoundParameters) {
return GetAllowedNames().
Where(new WildcardPattern(wordToComplete+"*",WildcardOptions.IgnoreCase).IsMatch).
Select(s => new CompletionResult(s));
}
private static string[] GetAllowedNames() {
return new string[] { "Alice", "Bob", "Charlie" };
}
}
}
’@ -PassThru|Select-Object -First 1 -ExpandProperty Assembly|Import-Module
特别是,您需要:
- 实现
IArgumentCompleter
接口。 Class 实现此接口应具有 public 默认构造函数。 - 将
ArgumentCompleterAttribute
属性应用于字段的 属性,用作 cmdlet 参数。作为属性的参数,您应该传递IArgumentCompleter
实现。 - 在
IArgumentCompleter.CompleteArgument
中您有wordToComplete
参数,因此您可以按用户已输入的文本过滤完成选项。
并尝试一下:
Test-Completion -Name Tab