Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Can';无法从管道获取值以在Powershell模块中工作_C#_Powershell_Pipeline - Fatal编程技术网

C# Can';无法从管道获取值以在Powershell模块中工作

C# Can';无法从管道获取值以在Powershell模块中工作,c#,powershell,pipeline,C#,Powershell,Pipeline,我正在创建一个Powershell模块,它充当与RESTful API接口的包装器 为了简化脚本编写者的工作,我提供了此Cmdlet来“建立与API的连接”(基本上是创建Worker类对象并指定身份验证令牌): 我遇到的问题是,我希望其他cmdlet能够接受由管道中的Get-APIConnection生成的对象。下面是我如何在另一个Cmdlet中实现该功能的示例: [Cmdlet(VerbsCommon.Get, @"SecurityGroups")] [OutputType

我正在创建一个Powershell模块,它充当与RESTful API接口的包装器

为了简化脚本编写者的工作,我提供了此Cmdlet来“建立与API的连接”(基本上是创建Worker类对象并指定身份验证令牌):

我遇到的问题是,我希望其他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);
    }
…如果我将$Connection作为命名参数传递,则Get SecurityGroups和会起作用:

>Get-SecurityGroups -Connection $API -Identity 'abcdefg'
Got here!
PowershellUsers
DotNetCOE
CompanyCarOwners 
...
请注意,“Got here!”被发送到屏幕,表明set确实在“Connection”参数上被调用

…但是,尽管我在“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]|选择*
psmessage详情:
异常:System.NullReferenceException:对象引用未设置为对象的实例。
在APIHelper.GetSecurityGroups.BuildOutputObject()上
在System.Management.Automation.Cmdlet.DoBeginProcessing()中
在System.Management.Automation.CommandProcessorBase.DoBegin()中
目标对象:
CategoryInfo:NotSpecified:(:)[Get SecurityGroups],NullReferenceException
FullyQualifiedErrorId:System.NullReferenceException,APIHelper.GetSecurityGroups
错误详细信息:
调用信息:System.Management.Automation.InvocationInfo
ScriptStackTrace:at,:第1行
PipelineIterationInfo:{}
我很感兴趣的是,如果连接是一个强制参数,并且没有对其调用set(因此没有“get here!”),那么我完全能够访问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 block中,$a没有值!在本例中,$a是简单类型,因此没有错误。在您的例子中,调用
null
对象的方法,这样您就得到了错误

原因很简单。在本例中,它是可见的

PS C:\> 'abc','def' | Test-Pipeline -Verbose
VERBOSE: begin 
VERBOSE: process abc
VERBOSE: process def
VERBOSE: end
管道执行甚至在管道中每个PowerShell函数的execution begin块处理第一个值之前就开始了

另外,如果你尝试以下方法,我想你也会得到意想不到的结果:

'[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);
    }
[Cmdlet(VerbsCommon.Get,@“SecurityGroups”)]
[输出类型(类型(字符串))]
公共类GetSecurityGroups:Cmdlet
{
私人联系;
[参数(位置=0,
强制=真,
ValueFromPipeline=true)]
公共工作者联系
{
获取{返回连接;}
设置
{
//确认集合实际上正在被调用
控制台。WriteLine(@“到了!”);
连接=值;
}
}
[参数(强制=真)]
公共字符串标识{get;set;}
私人的不可数结果;
受保护的覆盖void BeginProcessing()
{
base.BeginProcessing();
}
受保护的覆盖无效ProcessRecord()
{
base.ProcessRecord();
BuildOutputObject();
写入对象(结果);
}
私有BuildOutputObject()
{
结果=Connection.GetUserGroups(标识);
}

如果删除
位置=0,
位,是否会遇到同样的问题?@TheMadTechnician是的,尝试了在结束括号前缺少
[参数(位置=0,必需=true,ValueFromPipeline=true)]@cf谢谢,这是将代码改装为在SO上公开发布的一个输入错误。添加
ValueFromPipelineByPropertyName=true
,这样一个对象只要有一个具有可接受名称的属性(在本例中为
连接
)就可以通过管道传输我还添加了一个稍微复杂一点的示例。所以,长话短说,如果我在ProcessRecord中调用BuildOutputObject而不是BeginProcess,我应该很好,对吧?一般来说,是的。任何依赖于管道中的值的操作都不应该在begin块中完成。但是,正如最后一个示例,请注意,
ProcessRecord
可以是c我打了好几次电话。
PS C:\> 'abc','def' | Test-Pipeline -Verbose
VERBOSE: begin 
VERBOSE: process abc
VERBOSE: process def
VERBOSE: end
'[My Token]' | Get-APIConnection
[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);
    }