PowerShell 中的强制删除文件和目录有时会失败,但并非总是如此

PowerShell 中的强制删除文件和目录有时会失败,但并非总是如此

我正在尝试使用 递归删除目录rm -Force -Recurse somedirectory,我收到几个“目录不为空”错误。如果我重试相同的命令,它成功了。

例子:

PS I:\Documents and Settings\m\My Documents\prg\net> rm -Force -Recurse .\FileHelpers
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data\RunTime\_svn: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (_svn:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data\RunTime: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (RunTime:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (Data:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (FileHelpers.Tests:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs\nunit\_svn: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (_svn:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs\nunit: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (nunit:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (Libs:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (I:\Documents an...net\FileHelpers:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS I:\Documents and Settings\m\My Documents\prg\net> rm -Force -Recurse .\FileHelpers
PS I:\Documents and Settings\m\My Documents\prg\net>

当然,这不会发生总是。此外,这种情况不仅仅发生在_svn目录中,而且我没有TortoiseSVN缓存或类似的东西,所以没有任何东西阻塞目录。

有任何想法吗?

答案1

help Remove-Item说:

此 cmdlet 中的 Recurse 参数无法正常工作。

由于此 cmdlet 中的 Recurse 参数有缺陷,该命令使用 Get-Childitem cmdlet 获取所需的文件,并使用管道运算符将它们传递给 Remove-Item cmdlet。

并提出以下替代方案作为示例:

get-childitem * -include *.csv -recurse | remove-item

因此您应该get-childitem -recurse插入remove-item

答案2

@JamesCW:该问题在 PowerShell 4.0 中仍然存在

我尝试了另一种解决方法并且成功了:使用 cmd.exe:

&cmd.exe /c rd /s /q $somedirectory

答案3

更新从 Windows 10 版本 20H2 开始(我不知道 Windows服务器 对应的版本和构建;运行winver.exe以检查您的版本和构建),DeleteFileWindows API 函数现在展示同步行为, 哪个隐式地解决了 PowerShellRemove-Item和 .NET 的问题System.IO.File.Delete/ System.IO.Directory.Delete(但奇怪的是,不是cmd.exe's rd /s)。


现有的答案缓解问题,以便它发生的频率降低,但他们没有解决根本原因, 这就是为什么故障仍然可能发生

Remove-Item -Recurse出乎意料异步,最终是因为用于文件和目录删除的 Windows API 方法本质上是异步的并且Remove-Item没有考虑到这一点。

间歇地, 不可预测地表现为以下两种方式之一:

  • 您的情况:如果在尝试删除父目录时尚未完成删除子目录或文件,则删除非空目录本身可能会失败。

  • 不太常见的情况:删除后立即重新创建已删除的目录可能会失败,因为在尝试重新创建时删除可能尚未完成。

问题不仅影响 PowerShell 的Remove-Item,还cmd.exe影响rd /s以及 .NET 的[System.IO.Directory]::Delete()

从 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 / cmd.exe10.0.17134.407 / .NET Framework 4.7.03056、.NET Core 2.1 开始,既不Remove-Item,也不rd /s,也不[System.IO.Directory]::Delete()可靠, 因为他们无法解释 Windows API 文件/目录删除函数的异步行为

为一个自定义 PowerShell 函数提供了可靠的同步解决方法, 看这个答案

答案4

天哪。答案太多了。说实话,我更喜欢这个。它非常简单、完整、易读,并且可以在任何 Windows 机器上运行。它使用 .NET 的(可靠的)递归删除功能,如果由于某种原因失败,它会抛出一个可以使用 try/catch 块处理的适当异常。

$fullPath = (Resolve-Path "directory\to\remove").ProviderPath
[IO.Directory]::Delete($fullPath, $true)

请注意,此Resolve-Path行很重要,因为 .NET 在解析相对文件路径时不知道您的当前目录。这是我能想到的唯一问题。

相关内容