70

I am trying to delete a folder with subfolders/files.

Remove-Item -Force -Recurse -Path $directoryPath

I am getting the error Cannot remove item. The directory is not empty.

My PowershellScript.ps1 has executionPolicy unrestricted. The root folder I try to delete with the current logged in user has full permission on this folder.

On my local pc the code works but not on my Windows Server 2012 R2.

Richard
  • 6,812
  • 5
  • 45
  • 60
HelloWorld
  • 4,671
  • 12
  • 46
  • 78
  • Incredibly, the Windows API has _historically_ been _asynchronous_ with respect to file / directory deletion, causing recursive deletion of a directory tree to fail _intermittently_. Therefore, all shells / APIs that build on the Windows API used to failed intermittently: PowerShell, cmd, .NET. Fortunately, since (at least) Windows 10 20H2, the Windows API is now _synchronous_, which made the problem go away, except - curiously - in cmd. See [this answer](https://stackoverflow.com/a/53561052/45375) for more information. – mklement0 Jun 22 '22 at 01:55

5 Answers5

92

You could try the following:

Remove-Item -Force -Recurse -Path "$directoryPath\*"

Note when using the -Recurse parameter with -Include in Remove-Item, it can be unreliable. So it's best to recurse the files first with Get-ChildItem and then pipe into Remove-Item. This may also help if you deleting large folder structures.

Get-ChildItem $directoryPath -Recurse | Remove-Item -Force   
Richard
  • 6,812
  • 5
  • 45
  • 60
  • What PowerShell version are you using? – Richard Jul 01 '16 at 09:51
  • PSVersion is 4.0 but it seems the original error message might be misleading or hiding the real bug. When I remove the SQLCMD transaction from my executed insertstatementscripts.bat then the root folder can be deleted!!! It seems SQLCMD + transaction within powershell is doing asynchronous execution...and the SqlCmd does not wait. – HelloWorld Jul 01 '16 at 09:56
  • Could you try spawning off the `Remove-Item` operation into it's on `PowerShell` instance using a `Start-Job`? – Richard Jul 01 '16 at 10:20
  • Is this a direct answer to my sqlcmd transaction comment? You mean I should seperate the sql_insert_sqlcmd execution in PS1 file and the start-job PS2 file with remove-item so both work synchronously? – HelloWorld Jul 01 '16 at 10:39
  • Your answer is surely right in general, thus I checked it as solution, but my problem is worse I found out. Seems someone changed something in the infrastructure and I cant fix it :/ – HelloWorld Jul 02 '16 at 14:53
  • 12
    Why is `rm -Recurse` unreliable? – Kellen Stuart May 09 '17 at 16:30
  • 4
    @KolobCanyon Take a look at the following MSDN article in the section 'Example 4: Delete files in subfolders recursively' it mentions that the recurse parameter is unreliable. https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/remove-item – Richard May 09 '17 at 17:23
  • @Richard hey, i get this error from having files open within the directory as well. I made an answer to reflect this. In powershell 5, I have had no trouble with the `-Recurse` flag TBH. – Kellen Stuart Aug 15 '18 at 15:03
  • This answer resolved my issue. However, Get-ChildItem was sometimes throwing an UnauthorizedAccessException. I solved this by running my script as an administrator. – thehelix Sep 05 '18 at 17:00
  • 7
    @Richard The documentation only say that `-Recurse` is unreliable *when being used with `-Include`*. – Franklin Yu Nov 01 '18 at 16:11
  • 3
    When trying `Get-ChildItem $directoryPath -Recurse | Remove-Item -Force` in PS 5.1 I get confirmation prompts to confirm that I really do want to delete a directory, and I get sporadic `directory is not empty` errors. I'm guessing this may be because I'm deleting very large and complex file structures. `Get-ChildItem $directoryPath -Recurse | Remove-Item -Force -Recurse` seems to resolve these issues. – Tydaeus Dec 05 '19 at 21:19
  • `Get-ChildItem $directoryPath -Recurse | Remove-Item -Force -Recurse` deleted the deepest children only. I had to run it many times to get all the folders. It feels like one of the dumbest things I've ever done at the command line but I could find no other way. – Christopher Jul 31 '21 at 20:37
  • Historically, this answer was ultimately ineffective, though it may have made the problem surface _less frequently_. The root cause, which this answer didn't address, was the asynchronous behavior of the `DeleteFile` WinAPI function. Since (at least) Windows 10 20H2, this function is now synchronous, which means that `Remove-Item -Force -Recurse -Path $directoryPath` should now work robustly as-is. – mklement0 Jun 22 '22 at 02:02
  • Also: Both solutions in this answer remove only the _content_ of `$directoryPath`, not `$directoryPath` itself. – mklement0 Jun 22 '22 at 02:25
13

File is open in another program

I forgot that I had Visual Studio open with my project open and was getting this error.

Close any files associated with that directory, run PowerShell as admin, then run the command:

Remove-Item "C:\path\to\dir" -Recurse -Force

Pro Tip

You can also run this command to open file explorer:

ii "C:\path\to\dir"

If you right click and try to delete it, it might give you a more verbose error than command line.

Kellen Stuart
  • 7,775
  • 7
  • 59
  • 82
  • 2
    +++1 Yes you have to make sure you dont have any of the files in the dir locked or you will get this error. I have even seen this error pop up when one of the subdirs was open in powershell. – Wjdavis5 Jan 28 '20 at 12:48
  • I had the same problem. To solve it, I had to run windows 10 on safe mode (to activate safe mode use this command line: bcdedit /set bootmenupolicy legacy) + I had to rename all files hierarchy. – Slim Aloui Apr 14 '20 at 09:14
  • 1
    You're describing a _different_ problem: still-open handles would result in error message `The process cannot access the file '...' because it is being used by another process.`. By contrast, the question is about error message `Cannot remove item. The directory is not empty.`, which historically (before Windows 10 20H2) happened when _no_ files were in use, but the asynchronous nature of the `DeleteFile` WinAPI function caused _intermittent_ failures. – mklement0 Jun 22 '22 at 02:35
  • 1
    Man, I can't believe having VS Code open was throwing the errors. Thanks for this! – DaleyKD Aug 11 '22 at 13:42
  • On Windows 10: If not VS-Code then you can use the application 'Resource monitor' to find out which process owns the file you are trying to delete. When inside of the 'Resource Monitor' you can use the search field 'Search Handles' to search for a part of the path or the whole path. – DenLilleMand Oct 06 '22 at 12:42
5

Note that

Remove-Item -Force -Recurse -Path "C:\MyFolder"

Produces this error, but

Remove-Item -Force -Recurse -Path "C:\MyFolder\*"

Does not.

So don't forget the magic sauce

Nick.Mc
  • 18,304
  • 6
  • 61
  • 91
  • 3
    This just produced the same error N times, where N is the number of subfolders in MyFolder. – Christopher Jul 31 '21 at 20:33
  • This is the same as the accepted answer, and, just like the latter, it may have made the underlying problem occur _less frequently_, but _did not prevent it_. Since (at least) Windows 10 20H2, when the underlying `DeleteFile` WinAPI function became _synchronous_, `Remove-Item -Force -Recurse -Path "C:\MyFolder"` works as-is. – mklement0 Jun 22 '22 at 02:09
2

This way works every time, it sorts the files and directories in descending order to ensure the deepest members of the directory structure are deleted first.

Get-ChildItem $output_path -File -Recurse | Sort-Object FullName -Descending | Remove-Item -Force -Confirm:$false;
Get-ChildItem $output_path -Directory -Recurse | Sort-Object FullName -Descending | Remove-Item -Force -Confirm:$false;
Remove-Item $output_path -Force;
Nick Daniels
  • 922
  • 8
  • 13
0

this worked for me where i deleted files and folders older then i year recursively including folders.

Get-ChildItem -Directory -Path X:\AutomateCache | where-Object {$_.Lastwritetime -ile (get-date).AddMonths(-12) } | Remove-Item -Force -Recurse -Verbose