markb
markb

Reputation: 1295

Return first matched folder in Powershell

I have an array of IDs that have corresponding directories in a share:

$ids = @('12345','25356','74678')
- C:
-- 2020
--- 12345678 SURNAME
---- 12345
----- 12345_SubDir01
----- 12345_SubDir[n]
--- 23648844 SURNAME
---- 25256
----- 25256_SubDir01
----- 25256_SubDir[n]

I want to loop through all the directories in the letter C: and find the first match (the ID not the ID with the sub directory). So I want to match on 12345 not 12345_SubDir01.

The line that I've found so far (though inefficient) works but then keeps searching until it has iterated every directory in the the root share (we have over 500,000 folders and sub-folders).

The script line I am working with:

Get-ChildItem C: -Recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "12345" }

Is there a way to get the script to stop once it has matched on the ID so it doesn't continue searching once it has found the directory?

I want to be able to use the output path in the second half of the script, but its taking about 20 minutes per ID match before it can pass it on..

Upvotes: 3

Views: 574

Answers (1)

zett42
zett42

Reputation: 27766

Credits go to Doug Maurer for | Select-Object -First 1. The docs could be clearer about the fact that the pipeline will actually exit as soon as the specified number of input objects have been received (in our case, when the first matching name has been found).

Get-ChildItem C:\ -Directory -Recurse | Where-Object -Property Name -eq 12345 | Select-Object -First 1

Further improvements:

  • In this simple case, we can make everything more concise by using only parameters instead of a script block for Where-Object.

    Get-ChildItem -Directory limits retrieval to directories. Analogously, there's -File. Note that these require PS v3+. For older PS versions, one can query $_.PSIsContainer as shown in the question.

  • Make sure to append a backslash to C:. If you pass the drive without backslash, you will search only in the current directory of the drive! Try it: cd c:\windows; Get-ChildItem C:. You will list the content of the "windows" directory. The backslash fixes that, as you now specify the root directory, not just the drive.

  • Use operator -eq for an exact (case insensitive) match. With operator -match you would get an unwanted match for 12345_SubDir01, because -match does a sub-string search by default.

Upvotes: 2

Related Questions