无法删除项目,目录不为空

时间:2018-11-30 08:18:41

标签: windows powershell

使用Remove-Item命令时,即使使用-r-Force参数,有时也会返回以下错误消息:

  

删除项目:无法删除项目C:\ Test文件夹\ Test文件夹\目标:目录不为空。

尤其是在Windows资源管理器中打开要删除的目录时,就会发生这种情况。

现在,虽然可以通过关闭Windows资源管理器或不浏览该位置来避免这种情况,但是我在多用户环境中工作脚本,在这种环境下,人们有时会忘记关闭Windows资源管理器窗口,但我对删除整个文件夹和目录的解决方案,即使它们已在Windows资源管理器中打开。

有没有比我可以设置的-Force功能更强大的选项了?

要可靠地重现此文件,请创建文件夹C:\Test Folder\Origin,并在其中填充一些文件和子文件夹(重要),然后采用以下脚本或类似脚本并执行一次。现在打开C:\Test Folder\Target的子文件夹之一(在我的情况下,我使用了C:\Test Folder\Target\Another Subfolder包含A third file.txt的子文件夹),然后尝试再次运行脚本。您现在将得到错误。如果您第三次运行该脚本,则不会再次收到该错误(不过,根据我尚未确定的情况,该错误有时会第二次发生,然后再也不会发生,有时又发生第二次)。

$SourcePath =  "C:\Test Folder\Origin"
$TargetPath =  "C:\Test Folder\Target"

if (Test-Path $TargetPath) {
    Remove-Item -r $TargetPath -Force
}
New-Item -ItemType directory -Path $TargetPath 

Copy-Item $SourcePath -Destination $TargetPath -Force -Recurse -Container 

1 个答案:

答案 0 :(得分:5)

最终仅是一个 timing 问题:子目录的最后一个句柄在尝试删除父目录时可能尚未关闭-这是一个根本性问题,不仅限于打开文件资源管理器窗口:

令人难以置信的是, Windows文件和目录删除API是异步 :也就是说,当函数调用返回时,不能保证删除具有完成

令人遗憾的是, Remove-Item无法解决这一问题-并且cmd.exe的{​​{1}}和.NET的rd /s都没有-参见{{ 3}}。 这会导致 间歇性,不可预测的失败。

解决方法来自this answer(从7:35开始)提供,其PowerShell实现如下:


同步目录删除功能[System.IO.Directory]::Delete()

重要提示:

  • 仅在 Windows 上才需要同步自定义实现,因为在类似Unix的平台上,文件删除系统调用首先是同步的。因此,该函数仅在类似Unix的平台上遵循Remove-FileSystemItem。在Windows上,自定义实现:

    • 要求要删除的目录的 parent 目录为可写 ,以使同步自定义实现正常工作。
    • 删除任何网络驱动器上的目录时,也会应用
  • 不能阻止可靠删除的原因:

    • 文件资源管理器(至少在Windows 10上)不会锁定其显示的目录,因此不会阻止删除。

    • PowerShell也不锁定目录,因此拥有当前位置为目标目录或其子目录之一的另一个PowerShell窗口也不会阻止删除(相反,Remove-Item 不会< / em>锁定-参见下文)。

    • 在目标目录的子树中以cmd.exe / FILE_SHARE_DELETE(很少见)打开的文件也不会阻止删除,尽管它们确实以父目录中的临时名称存在。直到关闭了它们的最后一个手柄。

  • 将阻止删除的内容

    • 如果存在权限问题(如果ACL阻止删除),则删除中止。

    • 如果遇到不确定的 锁定 文件或目录,则删除将中止。值得注意的是,其中包括:

      • [System.IO.FileShare]::Delete(命令提示符),与PowerSell不同,确实锁定了当前目录,因此,如果您打开的cmd.exe窗口当前directory是目标目录或其子目录之一,删除将失败

      • 如果应用程序在文件共享模式cmd.exe / FILE_SHARE_DELETE下打开了在目标目录的子树中打开的文件,而该子目录打开(使用此模式是罕见),删除将失败。请注意,这仅适用于在处理内容时打开文件的应用程序。 (例如Microsoft Office应用程序),相比之下,记事本和Visual Studio Code等文本编辑器不会保持打开状态。

  • 隐藏的文件和具有只读属性的文件:

    • 这些已被删除;换句话说:此功能的行为始终类似于[System.IO.FileShare]::Delete
    • 但是请注意,为了将隐藏文件/目录定位为 input ,您必须将其指定为 literal 路径,因为它们不会通过通配符表达式。
  • Windows上可靠的自定义实现是以降低性能为代价的。

Remove-Item -Force