Reputation: 26349
I'm pretty sure I got it right, but want to double check with community.
I have a folder structure that starts, say from c:\test\
it has many files and folders. I also have a folder in this structure, say c:\test\something\another\temp\
this folder and its subfolders account for about 50% or more of all the files in c:\test\
.
I want to get a list of all *.txt
files in c:\test\
and its subfolders, excluding those, that are in c:\test\something\another\temp\
and deeper.
I don not want to enumerate the whole thing including c:\test\something\another\temp\
and then pipe out and filter for performance reason: there is just no need to walk through the whole c:\test\something\another\temp\
tree, since there is nothing of interest there.
It does not look like Get-ChildItem
cmdlet can help me here, I have to resort to .NET calls and write the recursion myself to exclude the folder I don't need.
Get-ChildItem
has -Exclude
parameter but it does not work on folders, only on files.
I'm fine with calling .NET library I'll just want to make sure I'm not missing anything and there is no <easier> way to do this with stock powershell cmdlets.
Is there?
Upvotes: 0
Views: 893
Reputation: 68341
If the directory is really large,
(cmd /c dir c:\test\*.txt /b /s) -notlike 'c:\test\something\another\temp\*'
should give you much quicker results than get-childitem.
Edit:
Here a different version that doesn't search the excluded directories:
$files =
(cmd /c dir c:\test /b /s /ad) -notlike 'c:\test\something\another\temp*' |
foreach { iex "cmd /c dir $_\*.txt /b /s /a-d" }
Don't know how to get it any quicker than that.
Upvotes: 3
Reputation: 7638
Another option utilizing the pipeline:
function Get-FilesInDir {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
$Path,
$Exclude
)
Process {
$Path | ForEach-Object {
if( (Resolve-path $_).Path.StartsWith($Exclude) ) { return }
Get-ChildItem -Path:$_ |
ForEach-Object {
if($_.PSIsContainer) { Get-FilesInDir -Path:$_.FullName -Exclude:$Exclude }
$_.FullName
}
}
}
}
Upvotes: 0
Reputation: 202072
Or you could do:
Get-ChildItem C:\test -r *.txt | Where {$_.FullName -notlike 'c:\test\something\another\temp\*'}
Upvotes: 1
Reputation: 28194
You can do this by creating your own function which recursively calls itself, skipping the directory you don't want to look at. I think it's doing what you're envisioning in your mind, but just with built-in cmdlets instead of resorting to .NET Framework methods.
$searchroot = 'c:\test';
function Get-FilesInDir {
param (
$DirToSearch
)
$ItemsInDir = Get-ChildItem -path $DirToSearch;
foreach ($item in $ItemsInDir) {
if ($item.FullName -eq 'c:\test\something\another\temp') {
continue;
}
if ($item.PSIsContainer) {
Get-FilesInDir $item.FullName;
}
$item.FullName;
}
}
Get-FilesInDir $searchroot
This will output the full path to each file found.
If you have a list of directories you want to exclude, you can put them into an array and modify the if
test around the continue
to check each path to see if it's in that array.
Upvotes: 0