【问题标题】:Stop execution of cmdlet in ProcessRecord在 ProcessRecord 中停止执行 cmdlet
【发布时间】:2014-08-17 03:14:46
【问题描述】:

如何停止执行在 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

【问题讨论】:

  • 已经提到的 PipelineStoppedException 是停止整个管道的方式。不过,它确实确实停止了事情。例如,如果你在 PS4 上这样做:dir | move -destination C:\otherfolder -passthru | select -first 10,Select-Object 将抛出 PipelineStoppedException 并且只会移动前 10 个文件。如果这就是你所追求的,那就完美了。否则,您需要解释“停止执行”的含义;-)
  • @Jaykul - 谢谢。请查看我更新的问题,了解更多详情以及为什么 PipelineStoppedException 似乎不适合我。

标签: c# powershell


【解决方案1】:

我通过抛出StopUpstreamCommandsException 得到Select -First 的行为。但由于它是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;
    }
}

【讨论】:

    【解决方案2】:

    目前不在我的开发机器上。如果你抛出一个System.Management.Automation.PipelineStoppedException,它会起作用吗?

    【讨论】:

    • 谢谢。请查看我更新的问题,了解更多详情以及为什么 PipelineStoppedException 似乎不适合我。
    【解决方案3】:

    许多内置 cmdlet 在想要停止正在运行的管道时会引发 System.Management.Automation.PipelineStoppedException。例如,这就是 select-object -first N 的工作原理。你试过吗?

    【讨论】:

    • 谢谢。请查看我更新的问题,了解更多详细信息以及为什么 PipelineStoppedException 似乎不适合我。
    猜你喜欢
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 2019-06-03
    相关资源
    最近更新 更多