在ProcessRecord中停止执行cmdlet

时间:2014-08-14 18:08:26

标签: c# powershell

如何停止执行在ProcessRecord方法中接收管道输入的cmdlet。如果不满足ProcessRecord中的条件,我需要立即停止执行并返回false

protected override void BeginProcessing()
{
    _output = true;
}

protected override void ProcessRecord()
{
    //processing
    if(condtion == true) return;

    _output = false;
    //How do I stop processing now, and ensure _output is returned as result?
}

protected override void EndProcessing()
{
    WriteObject(_output);
}

PipelineStoppedException似乎有效,但并没有给我确切的行为。

使用PipelineStoppedException

更新了一个更具体的示例

让我们考虑一个cmdlet First-List,它应该与LINQ中的First()行为类似。此cmdlet的实现类似于:

[Cmdlet("First", "List")]
public class FirstList : Cmdlet
{
    [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
    public object Input { get; set; }

    [Parameter(Position = 0, Mandatory = true)]
    public ScriptBlock ScriptBlock { get; set; }

    protected override void ProcessRecord()
    {
        var output = ScriptBlock.InvokeWithContext(null, new List<PSVariable>
        {
            new PSVariable("input", Input),
        })[0];

        if (output.ToString() != "True") return;

        WriteObject(Input);
        throw new PipelineStoppedException();
    }

    protected override void EndProcessing()
    {
        Error.NoMatch();
    }
}

使用Select -First,我可以执行以下操作:

$a = 1..10 | Select -First 1
#$a is 1

但是我的实施:

$a = 1..10 | First-List { $input -ge 5 }
#$a should be assigned 5, but it is not

但是1..10 | First-List { $input -ge 5 }确实输出了5。

更新2:

似乎Select-Object实际上抛出了StopUpstreamCommandsException

此处还提供了反馈意见 - https://connect.microsoft.com/PowerShell/feedback/details/768650/enable-users-to-stop-pipeline-making-stopupstreamcommandsexception-public

3 个答案:

答案 0 :(得分:4)

我通过抛出Select -First得到了StopUpstreamCommandsException的行为。但由于它是System.Management.Automation的内部,因此不得不使用反射。写了一个如下所示的实用方法:

internal static class Error
{
    private static readonly Type StopUpstreamCommandsExceptionType =
        Assembly.GetAssembly(typeof (PSCmdlet))
            .GetType("System.Management.Automation.StopUpstreamCommandsException");

    internal static Exception StopUpstreamCommandsException(Cmdlet cmdlet)
    {
        var stopUpstreamCommandsException = (Exception) Activator.CreateInstance(StopUpstreamCommandsExceptionType,
            BindingFlags.Default | BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public,
            null,
            new Object[] {(InternalCommand) cmdlet},
            null
            );
        return stopUpstreamCommandsException;
    }
}

答案 1 :(得分:1)

此刻不在我的开发机器上。抛出System.Management.Automation.PipelineStoppedException

是否有效?

答案 2 :(得分:1)

许多内置cmdlet在想要暂停正在运行的管道时抛出System.Management.Automation.PipelineStoppedException。例如,select-object-first N的工作原理。你试过了吗?