Short answer
To display the names of the PDF files directly or indirectly contained in a direct or indirect subdirectory of d:\root
named purchases
, you can use:
gci -Directory -Recurse d:\root\purchases | % { gci -Recurse "$_\*.pdf" } | % FullName
Short explanation: the command recursively finds all direct and indirect subdirectories of d:\root
named purchases
, then recursively finds all PDF files in each one of these subdirectories, then returns the full path of each one of these PDF files.
Other use cases
To remove these PDF files:
gci -Directory -Recurse d:\root\purchases | % { gci -Recurse "$_\*.pdf" } | ri
To rename these PDF files (e.g. by adding a prefix and a suffix to the base name):
gci -Directory -Recurse d:\root\purchases | % { gci -Recurse "$_\*.pdf" } | % { rni $_ "pref-$($_.BaseName)-suff.pdf" }
To remove the purchases
directories along with their entire content:
gci -Directory -Recurse d:\root\purchases | ri -Recurse
Detailed explanation
gci
is an alias for Get-ChildItem.
gci -Directory -Recurse d:\root\purchases
returns all directories (-Directory
) whose name is purchases
that are direct or indirect (-Recurse
) subfolders of d:\root\
. In other words, it would return d:\root\purchases
(if it existed) as well as d:\root\b\c\purchases
and d:\root\a\purchases
. This is not very intuitive and does not seem to be explained in the documentation, but it is the current behavior (as of PowerShell 6).
%
is an alias for ForEach-Object. It executes a script block (enclosed in curly braces ({}
) for each object in the pipeline.
gci -Recurse "$_\*.pdf"
retrieves the list of PDF files that are (directly or indirectly) contained in the previously found purchases
directories.
% FullName
is just used to display the path of these PDF files.
ri
is an alias for Remove-Item. It removes the previously computed list of PDF files (because the -Path
parameter of the Remove-Item
command accepts pipeline input).
ri -Recurse
allows to remove the previously computed list of purchases
directories along with their content.
rni $_ "pref-$($_.BaseName)-suff.pdf"
adds a prefix (pref-
) and a suffix (-suff
) to the base name $_.BaseName
of the current file in the pipeline (i.e. each one of the PDF files that we are looking for). The base name of a file is the name of the file without its extension and rni
is an alias for Rename-Item.
Testing this solution (online or locally)
The easiest is to try this solution online.
Otherwise, you can create a sample directory structure in a test
folder of the current working directory, with the following snippet (be careful: change .\test
to something else if you already have a test
folder in the current directory):
mkdir -ErrorAction SilentlyContinue .\test\a\purchases, .\test\a\e\, .\test\b\c\purchases\
Out-File .\test\a\purchases\invoice1.pdf
Out-File .\test\a\order1.pdf
Out-File .\test\a\e\order2.pdf
Out-File .\test\b\c\purchases\invoice2.pdf
Out-File .\test\b\c\purchases\invoice3.pdf
To view all files in this directory structure, you can use:
gci -Recurse -File .\test | % FullName
Which would return something like:
D:\test\a\order1.pdf
D:\test\a\e\order2.pdf
D:\test\a\purchases\prefix-invoice1-suffix.pdf
D:\test\b\c\purchases\prefix-invoice2-suffix.pdf
D:\test\b\c\purchases\prefix-invoice3-suffix.pdf
(Where D:
is replaced with your current working directory.)
Executing the command provided as an answer (gci -Directory -Recurse .\test\purchases | % { gci -Recurse "$_\*.pdf" } | % FullName
), will display the files that need to be removed or deleted:
D:\test\a\purchases\invoice1.pdf
D:\test\b\c\purchases\invoice2.pdf
D:\test\b\c\purchases\invoice3.pdf
To clean up after your test:
rm -Recurse .\test
1instead of making two
gci
calls as the other answers suggest, you could simply do this:gci C:\Root *.pdf -Recurse | ? DirectoryName -imatch 'purchase'
this will only return PDF files that have the stringpurchase
anywhere in their directoryname (path) – SimonS – 2018-09-18T09:36:20.030You're right @SimonS! One can use
gci -Recurse \root\*.pdf | ? { $_.DirectoryName -imatch '.*\\purchases(\\.*|$)' } | % FullName
instead of my answer, but it is not necessarily faster (depending on the exact file structure) because it doesn't use the PowerShell FileSystem Provider filtering capabilities (i.e. efficient support for globbing). – Youssef Abidi – 2018-09-19T09:33:30.060