Powershell Get Child Item Exclude doesn't work in current directory

1.8k views Asked by At

As I mentioned in question, this seems like bug in Powershell engine.

When I try to print the files in the current directory(where the said powershell script is also present) by excluding some file-types(extensions), it doesn't print anything. For eg. below codes print contents of Current Folder in the Powershell console:

gci
gci -pa .

Both the above codes print the directory contents as below:

Mode                LastWriteTime         Length Name                                                                                     
----                -------------         ------ ----                                                                                     
-a----       20-09-2020     22:37      835799796 file1.mkv                                                                      
-a----       20-09-2020     22:25            148 file1.srt                                      
-a----       23-09-2020     04:53            357 scriptv1.ps1                                                           
-a----       20-09-2020     22:25            678 file1.txt

But when I run below code, it doesn't print anything, when it must print file1.txt:

$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | Write-Host { $_.FullName }

Can anyone assist figuring out why is it happening and how to get what I mentioned ?

3

There are 3 answers

0
AdminOfThings On BEST ANSWER

The use of -Exclude with Get-ChildItem is not intuitive. To get consistent results with Get-ChildItem, you must qualify your path with \* or use the -Recurse switch. If you do not care to recurse, you can just use Get-Item with a \* qualifying the path.

# Works but includes all subdirectory searches
Get-ChildItem -Path .\* -Exclude $excluded
Get-ChildItem -Path .\* -Exclude $excluded -File
Get-ChildItem -Path . -Exclude $excluded -File -Recurse

# Best results for one directory
Get-Item -Path .\* -Exclude $excluded

The reason recursion should be used is because -Exclude values are applied to the leaf of -Path value first. If any of those exclusions match your target directory, then it will be excluded and prevent any of its items from being displayed. See below:

$path = 'c:\temp'
# produces nothing because t* matches temp
Get-ChildItem -Path $path -Exclude 't*'
0
muratiakos On

you are doing exclusion parameter correctly in your gci example, but where it may fail in your console silently is processing the results into write-host as it doesn't process the { .. } script block as a foreach-object would do for the individual items. The silent error should be:

Write-Host: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

With this respect, the correct short foreach-object pipeline notation would be:

$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | % { Write-Host $_.FullName }

Regarding the silent errors, I assume your session is set to be Silent, which you can check with the $ErrorActionPreference variable. If you wish to see all errors - in a non-blocking mode, you can set this to Continue eg:

$ErrorActionPreference='Continue'

Relevant PS7 pages and examples:

0
eduherminio On

Get-ChildItem -Exclude $excluded | Write-Host { $_.FullName } shouldn't fail silently unless all children in your directory are excluded by your filter.

If you try to run Get-ChildItem | Write-Host { $_.FullName } in a non empty directory, it should a throw an error similar to this one:

Write-Host: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

The reason is that Write-Host can't take an array as parameter (and we know that's an array by doing (Get-ChildItem).GetType()).

Therefore, you need to first iterate over the elements of the array using ForEach-Object or one of its aliases: foreach or %.

$excluded = @('*.mkv','*.mp4','*.srt','*.sub','*.ps1')
Get-ChildItem -Exclude $excluded | ForEach-Object { Write-Host $_.FullName }
Get-ChildItem -Exclude $excluded | foreach { Write-Host $_.FullName }
Get-ChildItem -Exclude $excluded | % { Write-Host $_.FullName }