Author Posts

October 29, 2015 at 6:13 pm

I want to do a recursive search to find the first directory containing an .htm file and setting the directory it was found to a variable, then stop.

The code below I wrote will keep recursing until it finds the last .htm file and sets that directory to the variable. which is not what I want

cd C:\Users\shane\Desktop\findfolder\mass
$dir = (Get-ChildItem  -filter *.htm -Recurse).Directory

October 29, 2015 at 8:13 pm

Work with your Get-ChildItem command, piping the results to Select-Object -First 1 before returning the Directory property (pipe to select inside the parenthesis).

October 30, 2015 at 9:01 am

"Beginning in Windows PowerShell 3.0, Select-Object includes an optimization feature that prevents commands from creating and processing objects that are not used. When you include a Select-Object command with the First or Index parameters in a command pipeline, Windows PowerShell stops the command that generates the objects as soon as the selected number of objects is generated, even when the command
generates the objects appears before the Select-Object command in the pipeline. To turn off this optimizing behavior, use the Wait
parameter."

Ideally I want the search to stop once the object is found. If I am reading this correctly, that is what it does as of powershell 3.0. I would like to be able to do this with powershell 2.0, what options would be suggested?

October 30, 2015 at 10:14 am

Well the best option would be to upgrade to a current revision of PowerShell. The only other option I can come up wiht is to loop through your structure one directory at a time using get-childitem without the -recurse option. You can look and see if you found a .htm file in the current directory, and if so kill your loop. If not, continue looking in the next directory.

October 30, 2015 at 12:59 pm

Shane,

I disagree with Curtis that you should upgrade to PowerShell 4.0. I think you should wait a few weeks, and upgrade to PowerShell 5.0 instead. : )

But I like a PowerShell challenge, especially when I can use it as an excuse to show off obscure .Net classes, so here is what I came up with in the alternative. These should work on 2.0, but I did not test them on 2.0.

There are two versions, depending on how you want to crawl through the directory tree. The first script, using a [queue] object, will explore each branch in its entirety before moving on. The second script, using a [stack] object, explores the root level folders first, then the second level folders, etc. Each will quit as soon as if finds a folder with a matching child.

Queues and Stacks are ordered arrays with methods that both give you the next item in the array and remove it from the array at the same time. Queues are first in, first out; you add things to the end of the queue, and take them from the front of the queue. Stacks are first in, last out; you add things to the top of the stack, and take things from the top of the stack. Instead of Add/Remove, you use Enqueue/Dequeue for Queues and Push/Pop for Stacks.

$Path = 'C:\Users\shane\Desktop\findfolder\mass'
 
$FolderList = New-Object System.Collections.Queue
$FolderList.Enqueue( $Path )
$HTMFolder = ''
 
While ( -not $HTMFolder -and $FolderList.Count -gt 0 )
    {
    $Folder = $FolderList.Dequeue()
 
    If ( Get-ChildItem -LiteralPath $Folder -Filter *.htm )
        {
        $HTMFolder = $Folder
        }
    Else
        {
        Get-ChildItem -LiteralPath $Folder | Where { $_.PSIsContainer } | Sort FullName | ForEach { $FolderList.Enqueue( $_.FullName ) }
        }
    }
$HTMFolder
$Path = 'C:\Users\shane\Desktop\findfolder\mass'
 
$FolderList = New-Object System.Collections.Stack
$FolderList.Push( $Path )
$HTMFolder = ''
 
While ( -not $HTMFolder -and $FolderList.Count -gt 0 )
    {
    $Folder = $FolderList.Pop()
 
    If ( Get-ChildItem -LiteralPath $Folder -Filter *.htm )
        {
        $HTMFolder = $Folder
        }
    Else
        {
        Get-ChildItem -LiteralPath $Folder | Where { $_.PSIsContainer } | Sort FullName -Descending | ForEach { $FolderList.Push( $_.FullName ) }
        }
    }
$HTMFolder

October 30, 2015 at 1:54 pm

I don't know Tim. PowerShell 5.0 has some nice features coming, but it's just a little bleeding edge for me. I guess I'm an old fuddy duddy.

Nice examples on the queue and stack!

October 30, 2015 at 2:32 pm

Some of the new PowerShell 5.0 stuff doesn't actually work. But all of the old 4.0 stuff is still there and still works and still works the same. And some of the new things are cool.

The "jump" from 4 to 5 is easily the smallest one yet. It's more of a service pack than a full version increment. The .Net version only goes from 4.5 to 4.6. I wouldn't expect datacenters that are currently on 4 to install 5 the day it comes out. But anyone on 2 needs to get off of it, and going from 2 to 5 is not a significantly bigger jump than from 2 to 4.