使用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
答案 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上,自定义实现:
不能阻止可靠删除的原因:
文件资源管理器(至少在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
。Windows上可靠的自定义实现是以降低性能为代价的。
Remove-Item -Force