Skip to content

Remove-Item should provide -File parameter #20637

Closed

Description

@SetTrend

Summary of the new feature / enhancement

Current Situation

Currently, trying to recursively delete files with a particular file extension also deletes all sub directories in a call like this:

Remove-Item * -Recurse -Filter '*.java'

Example

PS C:\Temp\Test> Get-ChildItem * -Recurse -Name -Filter '*.java'
trunk\MyProject\File1.java
trunk\MyProject\File2.java
trunk\MyProject\MyFolder\File1.java
trunk\MyProject\MyFolder\File2.java

PS C:\Temp\Test> Remove-Item * -Recurse -Verbose -Filter '*.java'
VERBOSE: Performing the operation "Remove Directory" on target "C:\Temp\Test\Something".
VERBOSE: Performing the operation "Remove Directory" on target "C:\Temp\Test\Something\trunk".
VERBOSE: Performing the operation "Remove Directory" on target "C:\Temp\Test\Something\trunk\MyProject".
VERBOSE: Performing the operation "Remove Directory" on target "C:\Temp\Test\Something\trunk\MyProject\MyFolder".
VERBOSE: Performing the operation "Remove File" on target "C:\Temp\Test\Something\trunk\MyProject\MyFolder\File1.java".
VERBOSE: Performing the operation "Remove File" on target "C:\Temp\Test\Something\trunk\MyProject\MyFolder\File2.java".
VERBOSE: Performing the operation "Remove File" on target "C:\Temp\Test\Something\trunk\MyProject\File1.java".
VERBOSE: Performing the operation "Remove File" on target "C:\Temp\Test\Something\trunk\MyProject\File2.java".

PS C:\Temp\Test> Get-ChildItem
PS C:\Temp\Test>

Desired Situation

(a) Directories not matching the filter should not be deleted.

(b) Add a -File parameter, providing the same functionality as the Get-ChildItem -File parameter.

Version

PS C:\Temp\Test> $psversiontable

Name                           Value
----                           -----
PSVersion                      7.3.9
PSEdition                      Core
GitCommitId                    7.3.9
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Proposed technical implementation details (optional)

See above.

Activity

  1. added
    Issue-Enhancementthe issue is more of a feature request than a bug
    Needs-TriageThe issue is new and needs to be triaged by a work group.
    on Nov 6, 2023
  2. SteveL-MSFT commented on Nov 6, 2023

    @SteveL-MSFT
    Member

    Workaround is to use Get-ChildItem -File | Remove-Item

  3. mklement0 commented on Nov 6, 2023

    @mklement0
    Contributor

    While I understand the desire to enhance Remove-Item, I think what Steve Lee (@SteveL-MSFT) is showing is more than just a workaround:

    Given that all provider cmdlets (Get-Command *-Item*) other than Get-ChildItem (as well as Select-String) lack advanced filtering capabilities, it makes sense to confine those to Get-ChildItem, and require use of the latter to provide the list of input objects via the pipeline.

  4. SetTrend commented on Nov 7, 2023

    @SetTrend
    Author

    I comprehend the tendency for not touching a running system. Yet, the current implementation adds serious hazard by deleting more items than stated in the command as unwanted side effect, and there is no way of avoiding that other than having another command do the job.

  5. mklement0 commented on Nov 7, 2023

    @mklement0
    Contributor
    • My fundamental concern is that adding additional switches to only one other provider cmdlet introduces an awkward inconsistency - why don't the others have them?

      • By contrast, clearly documenting that Get-ChildItem is the provider cmdlet to use for advanced filtering capabilities, and using its output as pipeline input to the others, if needed, is a conceptually straightforward solution that avoids either inconsistencies or a lot of duplication of functionality.
    • I hear you re the risks of inadvertent deletion of items with Remove-Item, but the problem goes deeper - see below.

      • Just as a general tip (you may already know this): Adding -WhatIf previews what items would be targeted for deletion by a given call.

    Taking a closer look at your specific Remove-Item command:

    • A conceptual problem is that -Recurse mostly does not work the way it does in Get-ChildItem; its purpose is to be an opt-in to quietly remove any directories among the targeted items.

      • To me, this semantic difference is problematic, and -Recurse never made much sense as an override-a-confirmation-prompt switch (there is -Force, but it already combines two behaviors: including hidden items and, on Windows, overriding a ReadOnly attribute).
    • A bug is that that adding -Recurse causes the -Filter argument to be ignored.

      • In other words: your command targets all items - both files and subdirs. - in the current directory, and quietly removes them.

      • Curiously:

        • If you use -Include rather than -Filter, -Recurse does also recurse into subdirs. and the filtering works as intended (but still wouldn't protect you from matching subdirs. too).

        • As an aside:

          • If Remove-Item worked like Get-ChildItem, Remove-Item *.java -Recurse -WhatIf should work the same, but doesn't: -Recurse then again only acts as the confirmation-prompt override switch.
          • That said, Get-ChildItem behavior in this case is itself highly problematic, especially if the -Path argument doesn't contain wildcard characters: it is still treated as a name to search for in the entire subtree - see Get-ChildItem -Recurse treats literals passed to -Path like wildcard expressions #5699

    The above isn't the only problem; there's a number of open Remove-Item bugs as of this writing:

    GitHub
    PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.
  6. mklement0 commented on Nov 9, 2023

    @mklement0
    Contributor

    Axel D. (@SetTrend), to me the tl;dr is (keep in mind that I'm just a fellow user):

    • I don't think what you're suggesting should be added to Remove-Item.

    • Remove-Item does need changing, however:

      • The aforementioned bugs need fixing.
      • For the sake of usability and to avoid conceptual confusion - without breaking backward compatibility [too much] - it is worth hiding the current -Recurse switch (primarily from the documentation), in one of two ways:
        • Either: By making it an (effective) alias of -Force (while exceptionally tolerating the presence of both -Force and -Recurse), meaning that the existing semantics of -Force would be overloaded (technically, a breaking change, though arguably one that falls into bucket 3).
        • Or: By introducing a new switch with an unambiguous name and make -Recurse an alias of it; however, it's hard to come up with a good name; -WithContent?
  7. jdhitsolutions commented on Mar 6, 2024

    @jdhitsolutions
    Collaborator

    The WG has reviewed this and considers this to be more of a documentation issue. The PowerShell paradigm is to get a group of things and then perform some action. The get cmdlet provides the filtering which is what is asked for here. The Remove-Item cmdlet is working as designed.

  8. added and removed
    Needs-TriageThe issue is new and needs to be triaged by a work group.
    WG-NeedsReviewNeeds a review by the labeled Working Group
    on Mar 6, 2024
  9. microsoft-github-policy-service commented on Mar 7, 2024

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as by-design and has not had any activity for 1 day. It has been closed for housekeeping purposes.

  10. microsoft-github-policy-service commented on Mar 7, 2024

    @microsoft-github-policy-service
    Contributor

    📣 Hey Axel D. (@SetTrend), how did we do? We would love to hear your feedback with the link below! 🗣️

    🔗 https://aka.ms/PSRepoFeedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugResolution-By DesignThe reported behavior is by design.WG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions