Real-Time Processing for Language Structures

by Apr 26, 2019

In the previous tip we looked at queues and how they can search the entire file system:

# create a new queue
$dirs = [System.Collections.Queue]::new()

# add an initial path to the queue
# any folder path in the queue will later be processed
$dirs.Enqueue('c:\windows')

# process all elements on the queue until all are taken
While ($current = $dirs.Dequeue())
{
    # find subfolders of current folder, and if present,
    # add them all to the queue
    try
    {
        foreach ($_ in [IO.Directory]::GetDirectories($current))
        {
                $dirs.Enqueue($_)
        }
    } catch {}

    try
    {
        # find all files in the folder currently processed
        [IO.Directory]::GetFiles($current, "*.exe") 
        [IO.Directory]::GetFiles($current, "*.ps1") 
    } catch { }
}

How would you process the data created by the loop though, i.e. to display it in a grid view window? You cannot pipe it in real-time, so this fails:

$dirs = [System.Collections.Queue]::new()
$dirs.Enqueue('c:\windows')

While ($current = $dirs.Dequeue())
{
    try
    {
        foreach ($_ in [IO.Directory]::GetDirectories($current))
        {
                $dirs.Enqueue($_)
        }
    } catch {}

    try
    {
        [IO.Directory]::GetFiles($current, "*.exe") 
        [IO.Directory]::GetFiles($current, "*.ps1") 
    } catch { }
# this fails
} | Out-GridView

You can save the results produced by do-while to a variable. That works but takes forever because you’d have to wait for the loop to complete until you can do something with the variable:

$dirs = [System.Collections.Queue]::new()
$dirs.Enqueue('c:\windows')

# save results to variable...
$all = while ($current = $dirs.Dequeue())
{
    try
    {
        foreach ($_ in [IO.Directory]::GetDirectories($current))
        {
                $dirs.Enqueue($_)
        }
    } catch {}

    try
    {
        [IO.Directory]::GetFiles($current, "*.exe") 
        [IO.Directory]::GetFiles($current, "*.ps1") 
    } catch { }
}

# then process or output
$all | Out-GridView

The same limitation applies when you use $() or other constructs. To process the results emitted by do-while in true real-time, use a script block instead:

$dirs = [System.Collections.Queue]::new()
$dirs.Enqueue('c:\windows')

# run the code in a script block
& { while ($current = $dirs.Dequeue())
    {
        try
        {
            foreach ($_ in [IO.Directory]::GetDirectories($current))
            {
                    $dirs.Enqueue($_)
            }
        } catch {}

        try
        {
            [IO.Directory]::GetFiles($current, "*.exe") 
            [IO.Directory]::GetFiles($current, "*.ps1") 
        } catch { }
    } 
} | Out-GridView

With this approach, results start to show in the grid view window almost momentarily, and you don’t have to wait for the loop to complete.


psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!