簡體   English   中英

無法讓 ValueFromPipeline 在 Powershell 模塊中工作

[英]Can't get ValueFromPipeline to work in Powershell Module

我正在創建一個 Powershell 模塊,它充當與 RESTful API 接口的包裝器。

為了簡化腳本編寫者的工作,我提供了這個 Cmdlet 來“建立連接”到 API(本質上是創建 Worker 類對象並指定身份驗證令牌):

public class GetAPIConnection : Cmdlet
{

    [Parameter(Position=0, Mandatory = true, ValueFromPipeline = true)]
    [Alias("T","Password","Pwd","APIKey")]
    public string Key { get; set; }

    //This is the object I intend to send to the pipeline
    private APIWorker API;

    protected override void BeginProcessing()
    {
        base.BeginProcessing();
        BuildOutputObject();
    }

    protected override void ProcessRecord()
    {
        base.ProcessRecord();
        WriteObject(API);
    }

    private BuildOutputObject()
    {
        API = new APIWorker(APIKey);
    }

我遇到的問題是我希望其他 cmdlet 能夠從管道中接受Get-APIConnection生成的對象。 這是我如何嘗試在另一個 Cmdlet 中實現它的示例:

[Cmdlet(VerbsCommon.Get, @"SecurityGroups")]
[OutputType(typeof(string))]
public class GetSecurityGroups : Cmdlet
{
    private APIWorker connection;

    [Parameter(Position = 0,
               Mandatory = true,
               ValueFromPipeline = true)]
    public APIWorker Connection
    {
        get { return connection; }
        set 
        {
            //Confirmation that set is actually being called
            Console.WriteLine(@"Got here!");

            connection = value; 
        }
    }

    [Parameter(Mandatory = true)]
    public string Identity { get; set; }

    private IEnumerable<string> Result;

    protected override void BeginProcessing()
    {
        base.BeginProcessing();
        BuildOutputObject();
    }

    protected override void ProcessRecord()
    {
        base.ProcessRecord();
        WriteObject(Result);
    }

    private BuildOutputObject()
    {
        Result = Connection.GetUserGroups(Identity);
    }

因此,在導入模塊后,我可以使用 Get-APIConnection cmdlet 很好地創建 PoshAPI 對象:

>$API = Get-APIConnection -Key '[My Token]'

...如果我將 $Connection 作為命名參數傳遞,則Get-SecurityGroups工作:

>Get-SecurityGroups -Connection $API -Identity 'abcdefg'
Got here!
PowershellUsers
DotNetCOE
CompanyCarOwners 
...

請注意“到了這里!” 發送到屏幕,表明確實在“Connection”參數上調用了set

...但是,即使我在“Get-SecurityGroups”中為“Connection”參數指定了ValueFromPipeline屬性,由於某種原因,我無法從管道傳遞 $API:

$API | Get-SecurityGroups -Identity 'abcdefg'

Get-SecurityGroups : Object reference not set to an instance of an object.
At line:1 char:7
+ $API | Get-SecurityGroups -Identity 'abcdefg'
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-SecurityGroups], NullReferenceException
    + FullyQualifiedErrorId : System.NullReferenceException,APIHelper.GetSecurityGroups

異常詳細信息表明在 BuildOutputObject() 中拋出了空引用異常:

> $error[0] | select *


PSMessageDetails      :
Exception             : System.NullReferenceException: Object reference not set to an instance of an object.
                           at APIHelper.GetSecurityGroups.BuildOutputObject()
                           at System.Management.Automation.Cmdlet.DoBeginProcessing()
                           at System.Management.Automation.CommandProcessorBase.DoBegin()
TargetObject          :
CategoryInfo          : NotSpecified: (:) [Get-SecurityGroups], NullReferenceException
FullyQualifiedErrorId : System.NullReferenceException,APIHelper.GetSecurityGroups
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}

對我來說很有趣的是,鑒於 Connection 是一個強制性參數,並且沒有調用 set(因此沒有“到了這里!”),我完全能夠訪問 BuildOutputObject()。 提示我定義該參數不是正確的行為嗎??

任何幫助將不勝感激!

在 PowerShell 管道中,參數綁定在進程塊中完成,而不是在開始塊中。 如果您正在構建 PowerShell commandlet,我認為同樣的規則將適用。

看看這個例子,它類似於你的GetSecurityGroups

function Test-Pipeline {
    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory,ValueFromPipeline)]
        [string]$a
    )

    BEGIN {Write-Verbose "begin $a"}
    PROCESS {Write-Verbose "process $a"}
    END {Write-Verbose 'end'}

}

在沒有管道的情況下調用它,會按您的預期提供輸出:

PS C:\> Test-Pipeline 'abc' -Verbose
VERBOSE: begin abc
VERBOSE: process abc
VERBOSE: end

但是,使用管道參數調用它的區別很小。 你看到了嗎?

PS C:\> 'abc' | Test-Pipeline -Verbose
VERBOSE: begin 
VERBOSE: process abc
VERBOSE: end

是的,在 begin 塊中 $a 沒有價值 在這種情況下,$a 是簡單類型,因此沒有錯誤。 在您的情況下,您調用null對象的方法,因此您收到錯誤。

原因很簡單。 在本例中可見。

PS C:\> 'abc','def' | Test-Pipeline -Verbose
VERBOSE: begin 
VERBOSE: process abc
VERBOSE: process def
VERBOSE: end

管道執行甚至在管道中每個 PowerShell 函數中的執行開始塊處理第一個值之前就開始了。

PS我想如果你嘗試這個,你也會得到意想不到的結果:

'[My Token]' | Get-APIConnection

簡單來說,我的問題是我需要將 BuildOutputObject() 方法移動到 ProcessRecord() 中。 當 BeginProcessing() 正在執行時,管道還沒有被讀取。 因此,在 ProcessRecord() 方法中設置輸出對象的值

[Cmdlet(VerbsCommon.Get, @"SecurityGroups")]
[OutputType(typeof(string))]
public class GetSecurityGroups : Cmdlet
{
    private APIWorker connection;

    [Parameter(Position = 0,
               Mandatory = true,
               ValueFromPipeline = true)]
    public APIWorker Connection
    {
        get { return connection; }
        set 
        {
            //Confirmation that set is actually being called
            Console.WriteLine(@"Got here!");

            connection = value; 
        }
    }

    [Parameter(Mandatory = true)]
    public string Identity { get; set; }

    private IEnumerable<string> Result;

    protected override void BeginProcessing()
    {
        base.BeginProcessing();
    }

    protected override void ProcessRecord()
    {
        base.ProcessRecord();
        BuildOutputObject();
        WriteObject(Result);
    }

    private BuildOutputObject()
    {
        Result = Connection.GetUserGroups(Identity);
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM