Reputation: 31
I want to search all directory recursively except the directory which starts with
_
(underscore).
Ex: _archive
, _DO_NOT_DELETE
, _processing
, etc.
I used below code and it is not working. It seems exclude will not work with recurse . Any ideas?
$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Directory -Exclude $exclude -Recurse
foreach($myItem in $allitems)
{
echo $myItem.fullname
}
Output:
C:\code\Powershell\delete empty folders\New folder\New folder\New folder C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2) C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3) C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder C:\code\Powershell\delete empty folders\New folder\_archive\New folder
So, as I told before I want to avoid the directory started with underscore, hence the last line should not come.
Even I used below code as well, still same output:
$exclude = @("_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory |
Where {$_.FullName -notlike $exclude}
foreach($myItem in $allitems)
{
echo $myItem.fullname
}
Upvotes: 3
Views: 1180
Reputation: 24091
What happens here is that Get-ChildItem's -exclude
parameter works based on item's name property. When wildcards are being used, the name must match the non-wildcarded parts. This doesn't happen when your directory name begins with a space. Let's see an example:
# Create two files, one starts with a space, the other doesn't
Set-Content -Path " data1.txt" -Value $null
Set-Content -Path "data2.txt" -Value $null
gci -name "data*"
data2.txt
gci -name " data*"
data1.txt
The result is a single match, tough a wildcard was used. The reason is that data1.txt
's first character is a space and that doesn't match parameter's first character, namely d
.
The -exclude
is notorious for being tricky. It is often easier to work around by piping results to where-object
. Like so,
Get-ChildItem $source -Directory -recurse | ? {$_.fullname -NotMatch "\\\s*_"} | % { $_.fullname }
# "\\\s*_" is regex for \, any amount of whitespace, _
C:\code\Powershell\delete empty folders\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (2)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)
C:\code\Powershell\delete empty folders\New folder\New folder\New folder\New folder
C:\code\Powershell\delete empty folders\New folder\New folder\New folder (3)\New folder
Get-ChildItem $source -Directory -recurse | ? {$_.fullname -Match "\\\s*_"} | % { $_.fullname }
C:\code\Powershell\delete empty folders\New folder\ _archive
C:\code\Powershell\delete empty folders\New folder\ _archive\New folder
Note that the matching needs to evaluate FullName
property. Just using Name
would match only the leaf level.
Upvotes: 4
Reputation: 8442
As @Paxz says in the comments, the command is working as intended, just not as you'd hoped. It is definitely excluding the folders starting with _
from the output, but this does not apply to the -Recurse
switch, so it still looks inside those folders for other items, which it displays (if their name does not start with _
).
You can use your own filter to get what you want:
Get-ChildItem -Path $source -Directory -recurse |
Where-Object {$_.FullName -notlike "*\_*"} |
Format-Table FullName
Note that this still finds all the folders with _
, but just discards them (so, no performance improvement). Also, using the simpler filter: -notlike "*_*"
would exclude any folder with an underscore in the middle or end of its name (e.g. Hello_World
), not just the beginning.
Upvotes: 2
Reputation: 3046
Haven't found an answer to the first attempt. But if you want to go with Where-Object
you have to change your Filter from _*
to *_*
.
This is because .Fullname
displays the full path, so alot more characters before the actual _
of the Path.
$exclude = @("*_*")
$source = "C:\code\Powershell\delete empty folders\New folder\"
$allitems = Get-ChildItem $source -Recurse -Directory | Where {$_.FullName -notlike $exclude}
$allitems.Fullname
Should give you the expected output.
Upvotes: 2