Reputation: 41
Given a folder structure like this:
C:\rootFolder\D
C:\rootFolder\D\D
C:\rootFolder\D\E
C:\rootFolder\E
C:\rootFolder\E\D
C:\rootFolder\E\E
C:\rootFolder\F
C:\rootFolder\F\D
C:\rootFolder\F\E
And a List of subfolders to exclude in C:\rootFolder like this:
$excludeFolders = "C:\rootFolder\D", "C:\rootFolder\E"
I need to recursively get all the files in C:\rootFolder and its subfolders, excluding any files in $excludeFolders and their subfolders. I can't hard code $excludeFolders because they're being loaded from a text file. I've been able to do it with the following:
# 1. Get the files in the root Folder
Get-ChildItem -Path $rootFolder -File | Select-Object FullName
# 2. Get all the directories in the root folder
Get-ChildItem -Path $rootFolder -Directory | ForEach-Object {
# Exclude those folders that are in the excludeFolders list
if (-not ($excludeFolders -contains $_.FullName)) {
#Process files in folders not in the excludeFolders list
Get-ChildItem -Path $_.FullName -File -Recurse | Select-Object FullName
}
}
But this 2-step approach is cumbersome and I'd prefer to do it in a single step. I've searched here and found something close using -Exclude, but that also eliminates the subfolders
C:\rootFolder\F\D
C:\rootFolder\F\E
Any help will be greatly appreciated.
Upvotes: 1
Views: 58
Reputation: 61208
You can simplify your code and use just one Get-ChildItem call combined with a Where-Object clause to omit the files in the excluded folders like below:
$rootFolder = 'C:\rootFolder'
# read the folders to exclude from your text file, removing empty and whitespace only lines
# $excludeFolders = Get-Content -Path 'C:\SomeFolder\Excludes.txt' | Where-Object { $_ -match '\S' }
# for demo use:
$excludeFolders = 'C:\rootFolder\D', 'C:\rootFolder\E'
# next, create a regex of the folders to exclude
# each item will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($excludeFolders | ForEach-Object { [Regex]::Escape($_) }) -join '|'
# now just iterate the files and omit those in the folders to exclude
(Get-ChildItem -Path $rootFolder -File -Recurse |
Where-Object { $_.DirectoryName -notmatch $notThese }).FullName
If the files or folder names inside the rootfolder may contain characters like [
or ]
, use -LiteralPath
instead of -Path
Upvotes: 1
Reputation: 34421
You can recursively get files using code like below. The code below takes a file structure and creates an XML report of the files in the folder(s) enumerating one folder at a time. You can modify to exclude files/folders to meet your requirements.
using assembly System.Xml
using assembly System.Xml.Linq
Function WriteTree
{
Param ([System.IO.DirectoryInfo]$info, [System.Xml.XmlWriter]$writer)
begin{
$size = [long]0;
$writer.WriteStartElement("Folder");
}
process{
try
{
$writer.WriteAttributeString('name', $info.Name);
$writer.WriteAttributeString('numberSubFolders', $info.GetDirectories().Count.ToString());
$writer.WriteAttributeString('numberFiles', $info.GetFiles().Count.ToString());
$writer.WriteAttributeString('date', $info.LastWriteTime.ToString());
foreach ($childInfo in $info.GetDirectories())
{
$size += WriteTree -info $childInfo -writer $writer;
}
}
catch
{
$errorMsg = [string]::Format("Exception Folder : {0}, Error : {1}", $info.FullName, $_);
Write-Host $errorMsg;
$writer.WriteElementString('Error', $errorMsg);
}
$fileInfo = $null;
try
{
$fileInfo = $info.GetFiles();
}
catch
{
$errorMsg = [string]::Format('Exception FileInfo : {0}, Error : {1}', $info.FullName, $_);
Write-Host $errorMsg;
$writer.WriteElementString('Error',$errorMsg);
}
if($fileInfo -ne $null)
{
foreach ($finfo in $fileInfo)
{
try
{
$writer.WriteStartElement('File');
$writer.WriteAttributeString('name', $finfo.Name);
$writer.WriteAttributeString('size', $finfo.Length.ToString());
$writer.WriteAttributeString('date', $info.LastWriteTime.ToString());
$writer.WriteEndElement();
$size += $finfo.Length;
}
catch
{
$errorMsg = [string]::Format('Exception File : {0}, Error : {1}', $finfo.FullName, $_);
Write-Host $errorMsg;
$writer.WriteElementString('Error', $errorMsg);
}
}
}
$writer.WriteElementString('size', $size.ToString());
$writer.WriteEndElement();
return $size;
}
end{}
}
$filename = 'c:\temp\test.xml'
$folder = 'c:\temp'
$writer = $null
$settings = [System.Xml.XmlWriterSettings]::new();
$settings.Indent = $true;
$writer = [System.Xml.XmlWriter]::Create($filename, $settings);
$writer.WriteStartDocument($true);
$info = [System.IO.DirectoryInfo]::new($folder);
WriteTree -info $info -writer $writer;
$writer.WriteEndDocument();
$writer.Flush();
$writer.Close();
Read-Host 'Enter Return'
Upvotes: -2