/flags/powershell/get-childitem-recurse-filter
Get-ChildItem -Recurse -Filter vs -Include: find files in subfolders
- tool
- PowerShell
- command
- Get-ChildItem
- flag
- -Recurse (with -Filter, -Include, -Exclude, -Depth)
- default
- off (only the items directly in -Path are returned)
Get-ChildItem -Path C:\Logs -Recurse -Filter *.log lists every .log file in C:\Logs and all of its subfolders. -Recurse makes the cmdlet walk the whole tree; -Filter narrows the results with a single wildcard pattern that the file system provider applies while it reads the directories, which makes it the fastest option. -Include and -Exclude take several patterns but are applied by PowerShell afterwards, and -Include behaves differently without -Recurse. Aliases are gci, dir and ls.
Get-ChildItem -Path C:\Logs -Recurse -Filter *.log
Get-ChildItem C:\Logs -Recurse -File -Include *.log, *.txt -Exclude debug*
Get-ChildItem C:\Logs -Recurse -Depth 1 -Filter *.log # this folder plus one level-Filter, -Include, -Exclude and -Depth side by side
Checked in Windows PowerShell 5.1 with a small tree (logs\app.log, logs\2026\old.log, logs\2026\10\today.log, logs\2026\10\notes.txt):
New-Item -ItemType Directory -Path logs\2026\10 -Force | Out-Null
'a' | Set-Content logs\app.log
'b' | Set-Content logs\2026\old.log
'c' | Set-Content logs\2026\10\today.log
'd' | Set-Content logs\2026\10\notes.txt
"-Recurse -Filter *.log:"
Get-ChildItem -Path logs -Recurse -Filter *.log | ForEach-Object { $_.FullName.Substring($PWD.Path.Length + 1) }
"-Recurse -Depth 1 -Filter *.log:"
Get-ChildItem -Path logs -Recurse -Depth 1 -Filter *.log | ForEach-Object { $_.FullName.Substring($PWD.Path.Length + 1) }
"-Include *.log without -Recurse (count):"
(Get-ChildItem -Path logs -Include *.log | Measure-Object).Count
"-Include *.log on logs\*:"
Get-ChildItem -Path logs\* -Include *.log | ForEach-Object Name
"-Recurse -Include *.log,*.txt -Exclude notes*:"
Get-ChildItem -Path logs -Recurse -Include *.log, *.txt -Exclude notes* | Sort-Object Name | ForEach-Object Name
try { Get-ChildItem -Path logs -Filter *.log, *.txt -ErrorAction Stop } catch { "-Filter with two patterns: " + $_.Exception.Message }Output
-Recurse -Filter *.log: logs\app.log logs\2026\old.log logs\2026\10\today.log -Recurse -Depth 1 -Filter *.log: logs\app.log logs\2026\old.log -Include *.log without -Recurse (count): 0 -Include *.log on logs\*: app.log -Recurse -Include *.log,*.txt -Exclude notes*: app.log old.log today.log -Filter with two patterns: Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Filter'. Specified method is not supported.
| Parameter | Patterns | Applied by | Notes |
|---|---|---|---|
| -Filter | one string | the provider (file system) while reading | fastest; passed to the .NET file API, which supports only * and ? |
| -Include | several | PowerShell, after reading | needs -Recurse or a path ending in \* |
| -Exclude | several | PowerShell, after reading | applies to item names, not to folders on the way down |
| -Depth N | number | recursion limit | PowerShell 5.0+; implies -Recurse |
| -File / -Directory | switch | provider | only files or only folders |
| -Force | switch | provider | also hidden and system items |
Pitfalls
- -Include without -Recurse. The reference says
-Includeis effective only when the command includes the contents of an item, such asC:\Windows\*. As the check shows,Get-ChildItem logs -Include *.logreturns nothing. - -Exclude does not prune folders.
-Exclude node_modulesdrops items namednode_modulesfrom the output but still recurses into it. To skip a folder tree, filter onFullNamewithWhere-Object. - Access denied in system folders. Recursing through
C:\or a profile hits folders you cannot read; add-ErrorAction SilentlyContinueto suppress those errors, orStopto fail fast (-ErrorAction Stop). - Wrong path. A missing path fails with Cannot find path because it does not exist.
- Searching inside files. Pipe the result to
Select-Stringto search file contents (Select-String).
FAQ
Why does Get-ChildItem -Include return nothing?
-Include only filters the contents of the path. Without -Recurse, the path must end in a wildcard such as C:\Logs\*; with C:\Logs alone it matches the folder itself, which is not *.log, so the result is empty.
Can -Filter take several patterns?
No. -Filter is a single string, and an array fails with Cannot convert System.Object[] to the type System.String. Use -Include *.log,*.txt with -Recurse, or run Get-ChildItem once per pattern.
How do I get only files or only folders?
Add -File or -Directory (PowerShell 3.0 and later). Get-ChildItem -Recurse -File -Filter *.log returns only files, and -Directory only folders.