Reputation: 301177
How does one stop the execution of a cmdlet that takes in pipeline input in the ProcessRecord method. If a condition in ProcessRecord is not met, I need to immediately stop execution and return a 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
seems to work, but doesn't give me the exact behaviour.
Updated with a more concrete example, using PipelineStoppedException
:
Let's consider a cmdlet First-List
which is supposed to behave similar to First()
in LINQ. An implementation of this cmdlet would be like:
[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();
}
}
With Select -First
, I am able to do the following:
$a = 1..10 | Select -First 1
#$a is 1
But with my implementtion:
$a = 1..10 | First-List { $input -ge 5 }
#$a should be assigned 5, but it is not
But 1..10 | First-List { $input -ge 5 }
does indeed output 5.
Update 2:
It seems like Select-Object
actually throws StopUpstreamCommandsException
.
There is also a feedback to have this available here - https://connect.microsoft.com/PowerShell/feedback/details/768650/enable-users-to-stop-pipeline-making-stopupstreamcommandsexception-public
Upvotes: 2
Views: 1212
Reputation: 301177
I got the behaviour of Select -First
by throwing the StopUpstreamCommandsException
. But since it was internal to System.Management.Automation
, had to use reflection. Wrote a utility method that looks like below:
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;
}
}
Upvotes: 4
Reputation: 1151
Many of the built-in cmdlets throw a System.Management.Automation.PipelineStoppedException when they want to halt the running pipeline. E.g., that's how select-object -first N works. Have you tried that?
Upvotes: 1
Reputation: 201692
Not at my dev machine at the moment. Does it work if you throw a System.Management.Automation.PipelineStoppedException
?
Upvotes: 1