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


33

我尝试使用递归删除目录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高速缓存或类似的东西,因此没有任何东西会阻塞目录。

有任何想法吗?

Answers:


31

help Remove-Item 说:

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

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

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

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

因此,您应该将管道get-childitem -recurse插入remove-item


谢谢。刚刚从2006年发现此线程:vistax64.com/powershell/…看起来Microsoft对修复此问题并不真正感兴趣。
Mauricio Scheffer 2010年

@mausch:请参阅以下更新但仍未解决的参考:Remove-Item -Recurse
已暂停,直到另行通知。

如果进行遍历和删除,则必须先遍历子目录,然后遍历它们的文件。
fschwiet 2010年

2
至少文档说明它不起作用。
derekerdmann

6
我必须同时为Remove-Item放置两个-force -recurse标志,否则它会提示我“请确认” Get-ChildItem -Path $ Destination -Recurse | Remove-Item -force
-recurse

17

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

我尝试了另一种解决方法,它奏效了:使用cmd.exe:

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

1
好老rd / s / q!
JamesCW

我已经尝试过Get-ChildItem的所有变体;重试循环;iisreset删除前调用,似乎没有可靠的工作。我要尝试这个,即使当我第一次看到它时,我也不愿意在Powershell中安装DOS ...
Peter McEvoy

不幸的是,它也rd /s间歇性地失败了(虽然看起来不及Remove-Item):github.com/Microsoft/console/issues/309
mklement

对于我来说,它不喜欢c的斜线。您是否必须先使用powershell -command并在cmd.exe部分加单引号?我得到“您必须在'/'运算符之后提供一个值表达式。” “表达式或语句中出现意外的标记'c'。它与前面的powershell -command相同。/是否需要转义?
Michele

7

ETA 20181217:PSVersion 4.0及更高版本仍然会在某些情况下失败,查看备选答案由迈赫达德Mirrezabug报告由申请mklement

mklement在此SO答案中提供了概念验证解决方案,因为该错误正在等待正式修复。

PowerShellPSVersion 4.0)的新版本已完全解决了该问题,并且Remove-Item "targetdirectory" -Recurse -Force可以正常运行,没有任何计时问题。

您可以通过$PSVersiontable在ISE或PowerShell提示中运行来检查版本。4.0版本附带Windows 8.1并且Server 2012 R2,它可以在Windows的早期版本进行安装也是如此。


5
在PowerShell 4.0中,我还是会
遇到

10
在PowerShell v5中仍然会发生!!!!! 11 !! 1!1 !!!
理查德·豪尔

@RichardHauer好吧,我现在很困惑
JamesCW

2
@JamesCW我已转换为rd版本。除了实际工作之外,它的速度要快大约3倍
Richard Hauer

从Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1开始,问题尚未得到解决-请参阅此错误报告。虽然rd /s可能会减少失败的频率,但它也已损坏-请参阅此错误报告
mklement

4

更新:似乎有计划使Windows文件系统项删除API同步,但是从Windows 10版本1903开始它们尚未同步-请参阅GitHub上的注释


现有的答案缓解了该问题,从而减少了发生的频率,但是它们并未解决根本原因,这就是为什么仍会发生故障的原因。

Remove-Item -Recurse意外地是异步的,最终是因为用于删除文件和目录Windows API方法本质上是异步的,并且Remove-Item不能解决这个问题。

这以两种方式之一间歇地,不可预测地体现出来:

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

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

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

由于的Windows PowerShell V5.1的/ PowerShell核心6.2.0-preview.1 / cmd.exe10.0.17134.407 / .NET框架4.7.03056,.NET 2.1的核心,既没有Remove-Item,也没有rd /s,也没有[System.IO.Directory]::Delete()可靠地工作,因为他们没有考虑到异步Windows API文件/目录删除功能的行为

有关提供可靠同步解决方案自定义PowerShell功能,请参见此SO答案


在确定可以删除的文件中处理文件时:while($true) { if ( (Remove-Item [...] *>&1) -ne $null) { Start-Sleep 0.5 } else { break } }
Farway

3

当前答案实际上不会删除目录,只会删除其子目录。此外,它将存在嵌套目录问题,因为它将再次尝试删除目录之前的目录。我写了一些东西以正确的顺序删除文件,尽管有时目录仍然存在,但仍然会遇到相同的问题。

因此,现在我使用可以捕获异常,等待并重试的方法(3次):

现在,我正在使用此:

function EmptyDirectory($directory = $(throw "Required parameter missing")) {

    if ((test-path $directory) -and -not (gi $directory | ? { $_.PSIsContainer })) {
        throw ("EmptyDirectory called on non-directory.");
    }

    $finished = $false;
    $attemptsLeft = 3;

    do {
        if (test-path $directory) {
            rm $directory -recurse -force
        }

        try {
            $null = mkdir $directory
            $finished = $true
        } 
        catch [System.IO.IOException] {
            Start-Sleep -Milliseconds 500
        }

        $attemptsLeft = $attemptsLeft - 1;
    } 
    while (-not $finished -and $attemptsLeft -gt 0)

    if (-not $finished) {
        throw ("Unable to clean and recreate directory " + $directory)
    }
}

1
很好,但是我仍然遇到问题。如果mkdir命令在系统完成rm命令之前运行,则可能引发System.UnauthorizedAccessException且ItemExistsUnauthorizedAccessError的FullyQualifiedErrorId。即,该目录尚未被操作系统删除(在我的慢速硬盘上)。因此也需要捕获该错误。这是一个非终止错误,因此需要将ErrorAction设置为Stop。我也将rm命令放在try块中,以防删除时出现瞬时IO错误。
Mark Lapierre's

我不敢相信甚至必须这样做。该死,Powershell很烂!
jcollum

3

删除目录及其内容需要两个步骤。首先删除内容,然后删除文件夹本身。使用错误的递归删除项的解决方法,解决方案将如下所示:

Get-ChildItem -Path "$folder\\*" -Recurse | Remove-Item -Force -Recurse
Remove-Item $folder

这样,您也可以删除父目录。


1
这就是公认的答案。您有什么要补充的吗?
迈克尔·汉普顿

1
他们指出,接受的答案不会删除目录本身,因此需要两个步骤。
保罗·乔治

2
Remove-Item管道中的命令与最初说明的问题相同。它可能会以相同的方式偶然发现非空的目录项。
Dejan

@Dejan如果此代码的第一行有效,该目录仍然不能为空,可以吗?
Ifedi Okonkwo

1
尽管这可能会减少失败的可能性,但鉴于仍然存在,它仍然可以失败Remove-Item -Recurse。从Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1开始,基本问题仍然存在-请参阅此错误报告
mklement

3

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

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

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


2

这是我的工作:

$Target = "c:\folder_to_delete"

Get-ChildItem -Path $Target -Recurse -force |
  Where-Object { -not ($_.psiscontainer) } |
   Remove-Item Force

Remove-Item -Recurse -Force $Target

第一行删除树中的所有文件。第二个删除所有文件夹,包括顶部。


尽管这可能会减少失败的可能性,但鉴于仍然存在,它仍然可以失败Remove-Item -Recurse。从Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1开始,基本问题仍然存在-请参阅此错误报告
mklement


0

我遇到了无法删除的目录的问题。我发现子文件夹之一已损坏,当我尝试移动或重命名该子目录时,我收到一条错误消息,提示它丢失了一些信息。我尝试使用rm -Force并得到与您相同的错误。

对我有用的是使用7-zip压缩了父目录,并选中了“压缩后删除文件”选项。压缩后,我便可以删除该zip文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.