web-dev-qa-db-ja.com

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>

もちろん、これは起こりませんalways。また、これは_svnディレクトリでのみ発生するわけではありません。 TortoiseSVN キャッシュなどがないため、ディレクトリをブロックしているものはありません。

何か案は?

34

help Remove-Itemさんのコメント:

このコマンドレットのRecurseパラメーターは正しく機能しません。

そして

このコマンドレットのRecurseパラメーターに欠陥があるため、コマンドはGet-Childitemコマンドレットを使用して目的のdファイルを取得し、パイプライン演算子を使用してそれらをRemove-Itemコマンドレットに渡します。

そして、この代替案を例として提案します:

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

だからあなたはget-childitem -recurseからremove-item

@JamesCW:問題はPowerShell 4.0にまだ存在します

私は別の回避策を試してみましたが、うまくいきました:cmd.exeを使用してください:

&cmd.exe /c rd /s /q $somedirectory
19
Mehrdad Mirreza

ETA 20181217:PSVersion 4.0以降は、状況によっては失敗します。 Mehrdad Mirreza による代替回答を参照してください バグレポート による提出- mklement

mklement これで概念実証ソリューションが提供されます SO回答 、バグは公式の修正を待っているため

新しいバージョンのPowerShellPSVersion 4.0)はこの問題を完全に解決し、Remove-Item "targetdirectory" -Recurse -Forceはタイミングの問題なしに機能します。

ISEまたはPowerShellプロンプトから$PSVersiontableを実行すると、バージョンを確認できます。 4.0はWindows 8.1およびServer 2012 R2に同梱されているバージョンであり、以前のバージョンのWindowsにもインストールできます。

8
JamesCW

更新:Windowsファイルシステムのアイテム削除APIを同期させるためのプランがあるようですが、現時点ではまだ同期していませんWindows 10バージョン1903- GitHubのこのコメント を参照してください。


既存の回答は問題を軽減するため、発生頻度は低くなりますが、根本原因は解決されません。それでも障害が発生する理由。

_Remove-Item -Recurse_は予期せずasynchronousになります。これは、最終的にファイルとディレクトリの削除のためのWindows APIメソッドは本質的に非同期および_Remove-Item_はそれを考慮していません。

これは断続的に、予測不可能に2つの方法のいずれかで現れます。

  • あなたのケース:空でないディレクトリ自体の削除は、親ディレクトリを削除しようとする時点でサブディレクトリまたはその中のファイルの削除がまだ完了していない場合、失敗する可能性があります。

  • あまり一般的ではありません。削除後すぐに削除されたディレクトリの再作成は失敗する可能性があります。再作成が試行されるまでに削除がまだ完了していない可能性があるためです。

問題は、PowerShellの_Remove-Item_だけでなく、_cmd.exe_の_rd /s_だけでなく、.NETの[System.IO.Directory]::Delete()にも影響します。

Windows PowerShell v5.1以降/ PowerShell Core 6.2.0-preview.1/_cmd.exe_ 10.0.17134.407/.NET Framework 4.7.03056、.NET Core 2.1、never _Remove-Item_、また、_rd /s_も[System.IO.Directory]::Delete()も確実に機能しますなぜなら、これらはWindows APIファイル/ディレクトリ削除関数の非同期動作の説明に失敗する

信頼できる同期の回避策を提供するカスタムPowerShell関数については、 this SO answer を参照してください。

7
mklement

ディレクトリとその内容を削除するには、2つの手順を実行します。最初にコンテンツを削除し、次にフォルダ自体を削除します。障害のある再帰的な削除項目の回避策を使用すると、ソリューションは次のようになります。

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

この方法で、親ディレクトリも削除できます。

3
Carl Baker

現在の答えは実際にはディレクトリを削除するのではなく、その子だけを削除します。さらに、ネストされたディレクトリでは問題が発生します。これは、コンテンツの前にディレクトリを削除しようとするためです。ファイルを正しい順序で削除するために何かを書きましたが、時々ディレクトリがまだ残っているかもしれませんが、同じ問題がまだあります。

だから、今私は例外をキャッチし、待機し、再試行するものを使用します(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)
    }
}
3
fschwiet

まあ。たくさんの答え。私は正直なところ、これらすべてよりもこの1つを好みます。とてもシンプルで、完全で、読みやすく、どんなWindowsマシンでも動作します。 .NETの(信頼できる)再帰的な削除機能を使用し、何らかの理由で失敗した場合は、try/catchブロックで処理できる適切な例外をスローします。

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

Resolve-Path行は重要です。NETは相対ファイルパスを解決するときに現在のディレクトリを認識しないためです。それは私が考えることができる唯一の落とし穴についてです。

3
Phil

これは私が働いているものです:

$Target = "c:\folder_to_delete"

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

Remove-Item -Recurse -Force $Target

この最初の行は、ツリー内のすべてのファイルを削除します。 2番目は、トップを含むすべてのフォルダーを削除します。

2
James Copeland

最初にTakeown.exeを使用してファイル/ディレクトリの所有権を取得し、次に削除します

https://learn-powershell.net/2014/06/24/changing-ownership-of-file-or-folder-using-powershell/

0
AveryFreeman

削除されないディレクトリでこの問題が発生しました。サブフォルダの1つが破損していることがわかり、その子ディレクトリを移動または名前変更しようとすると、見つからないことを示すエラーメッセージが表示されました。 rm -Forceを使用してみたところ、同じエラーが発生しました。

私にとってうまくいったのは、「圧縮後にファイルを削除する」オプションがチェックされた7-Zipを使用して親ディレクトリを圧縮することでした。圧縮された後、Zipファイルを削除することができました。

0
RedDawnRising