Search code examples
powershellrecursionpromptsubdirectoryconfirmation

Force not suppressing confirmation prompt - removal of directories by name from any level of a directory hierarchy


I have following the PowerShell script to delete folders out of my other project:

 param([Parameter(Mandatory)][String]$path)
     $directories = dir -Path $path -Directory -Recurse 

     foreach ($directory in $directories){
        if ($directory.Name  -eq "bin" -or $directory.Name -eq "obj"){
            Remove-Item -Path $directory.FullName -Force -Confirm:$false
        }
     }

And if I use it, there always is a prompt

Confirm
The item at C:\Users\...\bin has children and the
Recurse parameter was not specified. If you continue, all children will be removed with the item. Are you sure you want
 to continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

I know that adding -Recurse to the Remove-Item cmdlet should do the thing, but this is redundant and because of it there is a possibility for the code to create exceptions. So how do I suppress that confirmation prompt?


Solution

  • While I agree that -Confirm:$False should suppress the confirmation prompt even in the absence of -Recurse, even if it did, the removal would still invariably be recursive.

    Your real problem is the use of a foreach statement, which invariably creates the list of directories up front (even if you used foreach ($dir in Get-ChildItem ...), and therefore potentially attempts to access directories that were already removed in a previous iteration, as part of a previously removed directory's subtree.

    By contrast, using the pipeline directly with Get-ChildItem -Recurse -Directory handles the recursive enumeration gracefully by not enumerating subdirs. that a previous iteration has already removed:

     param([Parameter(Mandatory)][String]$path)
    
     # Note the use of the pipeline and the ForEach-Object cmdlet.
     Get-ChildItem -Path $path -Directory -Recurse | ForEach-Object {
        if ($_.Name  -eq "bin" -or $_.Name -eq "obj"){
            Remove-Item -Recurse -Force -Confirm:$False -LiteralPath $_.FullName
        }
     }
    

    The above can be simplified to:

    Get-ChildItem -Path $path -Directory -Recurse -Include bin, obj | 
      Remove-Item -Recurse -Force -Confirm:$False