Aborting the PowerShell Pipeline (Part 2: Manual Abort)

by Dec 20, 2019

In the previous tip you learned how to abort the PowerShell pipeline once the required number of results is in, potentially saving a lot of time:

$fileToSearch = 'ngen.log'
Get-ChildItem -Path c:\Windows -Recurse -ErrorAction SilentlyContinue -Filter $fileToSearch |
Select-Object -First 1

Apparently, Select-Object can send a secret message to the upstream pipeline cmdlets, telling them to stop when the number of expected results have passed Select-Object. In fact, Select-Object emits a special exception that is handled by PowerShell and does the magic trick.

But what if you don’t know the exact number of results? What if you’d like to abort the pipeline on other criteria? What if you’d like to implement some sort of timeout for example? To manually abort a pipeline, all you need to do is make Select-Object emit its secret exception. Here is the function Stop-Pipeline that does exactly this:

function Stop-Pipeline
{
    $pipeline = { Select-Object -First 1 }.GetSteppablePipeline()
    $pipeline.Begin($true)
    $pipeline.Process(1)
    $pipeline.End()
}

It takes a Select-Object and mimics it is running in a pipeline. This is accomplished by GetSteppablePipeline(). You can now manually feed data into Select-Object via Process(). Since Select-Object was executed with the -First 1 parameter, the moment you feed anything into Select-Object, it emits its secret exception.

Now you are in control and can take whatever condition you like to call Stop-Pipeline. The following example will search for files and abort the pipeline after a maximum of 2 seconds:

function Stop-Pipeline
{
    $pipeline = { Select-Object -First 1 }.GetSteppablePipeline()
    $pipeline.Begin($true)
    $pipeline.Process(1)
    $pipeline.End()
}

# abort pipeline after 2000 milliseconds
$timeout = 2000
# create a stopwatch
$stopwatch =  [system.diagnostics.stopwatch]::StartNew()

Get-ChildItem -Path c:\Windows -Recurse -ErrorAction SilentlyContinue |
  ForEach-Object {
    if ($stopwatch.ElapsedMilliseconds -gt $timeout)
    {
      $stopwatch.Stop()
      Write-Warning "Timeout, Pipeline Aborted."
      # abort pipeline
      Stop-Pipeline
    }
    
    # return the original object
    $_
  }

You are a PowerShell Professional, passionate about improving your code and skills? You take security seriously and are always looking for the latest advice and guidance to make your code more secure and faster? You’d love to connect to the vibrant PowerShell community and get in touch with other PowerShell Professionals to share tricks and experience? Then PowerShell Conference EU 2020 might be just the right place for you: https://psconf.eu (June 2-5, 2020 in Hanover, Germany).

It’s a unique mixture of classic conference with three parallel tracks filled with fast-paced PowerShell presentations, and advanced learning class with live discussions, Q&A and plenty of networking.

Secure your seat while they last: https://psconf.eu/register.html. Help build the agenda and make this “your” event by submitting hypothetical sessions you’d like to hear: https://powershell.one/psconfeu/psconf.eu-2020/reverse-cfp. And if you’d like to present yourself and join the psconf.eu speakers’ team, submit proposals: https://sessionize.com/psconfeu/.

Twitter This Tip! ReTweet this Tip!