Search code examples
powershellpowershell-cmdlet

PowerShell - Remove-Item working weirdly when -Filter value passed


Can anyone please help me understand why "Remove-Item" cmdlet behaves weirdly when using -Filter option for removing specific list of files? Same if I passed in other cmdlets its working fine, but if use the -Filter option within the remove-item cmdlet it is not working. Please help me undersand this behavior? Thanks in advance.

get-childitem -path '.\mydir\*.txt' | remove-item  # working fine and able to understand
 
get-childitem -path '.\mydir' -Filter "*.txt" | remove-item # working fine and able to understand

remove-item -Path '.\mydir' -Filter '*.txt' # Trying to give warnng message to delete all contents within mydir folder, unable to understand, why?

Solution

  • Perhaps surprisingly, Remove-Item invariably tries to remove a targeted directory itself as well, irrespective of the presence of a -Filter argument.

    Thus, if the target directory is non-empty, you'll get the usual "The item at c:\path\to\dir has children and the Recurse parameter was not specified." confirmation prompt.

    However, adding -Recurse is best avoided, because you'll get an error message if, after removing the filter-matching files, the directory is still non-empty; conversely, if it is (then) empty, it will be removed as a whole.


    Solutions:

    • Make the filter part of the -Path argument:

      Remove-Item -Path '.\mydir\*.txt'
      
      • Note that this can result in subtly different behavior, because with -Filter it is the platform file-system APIs that handle the wildcard matching, not PowerShell; PowerShell's wildcard patterns are more powerful than the former, while not exhibiting certain legacy quirks.
        Also, letting PowerShell do the wildcard matching after the fact (via -Path or -Include / -Exclude) is slower than using -Filter, which is applied at the source; for that reason, use of -Filter is preferable when performance matters.
    • Or, as already shown in your question, use Get-ChildItem to select the files of interest, and pipe to Remove-Item:

      Get-ChildItem -Path '.\mydir' -Filter "*.txt" | Remove-Item
      
      • While slower than direct Remove-Item use, this gives you better control over what is to be deleted.

      • You can add the -WhatIf common parameter to Remove-Item to preview what files will be deleted.

      • Generally (not necessary in this case), you may have to add -Recurse to Remove-Item, should there be (by design) subdirectories among the items output by Get-ChildItem.