find first directory containing .htm file

This topic contains 6 replies, has 4 voices, and was last updated by Profile photo of Tim Curwick Tim Curwick 1 year, 8 months ago.

  • Author
    Posts
  • #31512
    Profile photo of Shane Lindberg
    Shane Lindberg
    Participant

    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
    
  • #31513
    Profile photo of tommymaynard
    tommymaynard
    Member

    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).

  • #31523
    Profile photo of Shane Lindberg
    Shane Lindberg
    Participant

    "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?

  • #31534
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    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.

  • #31537
    Profile photo of Tim Curwick
    Tim Curwick
    Participant

    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
    
  • #31538
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    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!

  • #31539
    Profile photo of Tim Curwick
    Tim Curwick
    Participant

    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.

You must be logged in to reply to this topic.