2015-10-14 31 views
2

我正在用C#編寫一個二進制Powershell模塊,我想要一個具有提供動態運行時選項卡完成的參數的Cmdlet。但是,我正在努力弄清楚如何在二進制模塊中執行此操作。這是我試圖得到這個工作:Powershell二進制模塊:Cmdlet參數值的動態選項卡完成

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的非二進制模塊中,隨後是構建並返回RuntimeParameterDictionary對象的語句。基於這個例子,我期望PSCmdlet類中的等價物,也許是一個可重寫的GetDynamicParameters()方法或類似的東西,就像存在一個可覆蓋的方法BeginProcessing()一樣。

以這樣的速度,二進制模塊正在Powershell世界中成爲二等公民。當然有一種方法可以做到這一點,我錯過了?

+1

我相信至少你需要添加[IDynamicParameters](https://msdn.microsoft.com/en-us/library/system.management .automation.idynamicparameters(v = vs.85).aspx)接口到您的cmdlet以使用動態參數。從那裏我相信你會做和你在示例中一樣的東西(創建一個RuntimeParameterDictionary等),但我無法證實這一點。 –

回答

6

這是一種如何在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接口。實現這個接口的類應該有公共的默認構造函數。
  • ArgumentCompleterAttribute屬性應用於字段的屬性,用作cmdlet參數。作爲屬性的參數,您應該通過IArgumentCompleter實現。
  • IArgumentCompleter.CompleteArgument中,您有wordToComplete參數,因此您可以按用戶輸入的文本過濾完成選項。

而且嘗試一下:

Test-Completion -Name Tab
+0

我不得不安裝Windows Management Framework 5.0預覽版,但是一旦我做到了,它實際上可以工作!非常感謝! –