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キャッシュなども持っていないため、ディレクトリをブロックしているものはありません。

何か案は?

回答:


31

help Remove-Item 言う:

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

そして

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

例としてこの代替案を提案します。

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

パイプべきそうget-childitem -recurseremove-item


ありがとう。2006年からこのスレッドを見つけました:vistax64.com/powershell/…Microsoftはこれを修正することに本当に興味がないようです。
マウリシオシェファー

@mausch:これを参照してください。ただし、まだ解決されていない最新の参照:Remove-Item -Recurse
通知があるまで一時停止します。

トラバーサルと削除を行う場合、最初に子ディレクトリをトラバースし、最初にそれらのファイルをトラバースする必要があります。
fschwiet

2
少なくともドキュメントには、機能しないと書かれています。
derekerdmann

6
Remove-Itemに-force -recurseフラグの両方を設定する必要がありました。そうしないと、「確認してください」というプロンプトが表示され続けました Remove-Item -force -recurse
MiFreidgeim SO-stop evil(邪悪なことを止める)

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以降は引き続き失敗します。MehrdadMirrezaによる別の回答と、mklementによって提出されたバグレポートを参照してください。

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

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

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


5
PowerShell 4.0ではまだ発生します
ajbeaven

10
PowerShell v5でも引き続き発生します!!!!! 11 !! 1!1 !!!
リチャードハウアー

@RichardHauerはよく、今私は混乱している
JamesCW

2
@JamesCW rdバージョンに変換しました。別に、実際に働いてから、それはより速く3Xについてです
リチャード・ハウアー

この問題は、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あり、それを考慮していないため、最終的に非同期です。

これは、次の2つの方法のいずれかで断続的に予測できません

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

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

問題は、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 Framework 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 } }
ファーウェイ

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
これは良いことですが、まだ問題がありました。システムがrmコマンドを完了する前にmkdirコマンドが実行された場合、ItemExistsUnauthorizedAccessErrorのFullyQualifiedErrorIdでSystem.UnauthorizedAccessExceptionをスローできます。つまり、ディレクトリはまだOSによって削除されていません(低速のHDD上)。そのため、そのエラーもキャッチする必要があります。また、終了しないエラーであるため、ErrorActionをStopに設定する必要があります。また、削除時に一時的なIOエラーが発生した場合に備えて、rmコマンドもtryブロックに配置します。
マークラピエール

これをやらなければならないとは信じられません。くそー、Powershellは吸う!
jcollum

3

ディレクトリとその内容を削除するには、2つのステップが必要です。最初にコンテンツを削除してから、フォルダー自体を削除します。障害のある再帰的な削除アイテムの回避策を使用すると、ソリューションは次のようになります。

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

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


1
これは、受け入れられた答えがまさに言ったことです。追加するものはありますか?
マイケルハンプトン

1
彼らは、受け入れられた答えがディレクトリ自体を削除しないことを指摘しているため、2つのステップが必要です。
ポールジョージ

2
Remove-Itemコマンドあなたの配管には、もともと述べた同じ問題を抱えています。同じ方法で空でないディレクトリ項目でつまずくかもしれません。
デヤン

@Dejanこのコードの最初の行が機能した場合、このディレクトリを空にすることはできませんでしたか?
イフェディオコンコボ

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

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


これにより、失敗の可能性が低下する可能性がありますが、それRemove-Item -Recurseがまだ関与している場合、失敗する可能性があります。根本的な問題は、Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1の時点でまだ存在しています- このバグレポートを参照してください。
mklement


0

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

私のために働いたのは、「圧縮後にファイルを削除する」オプションをオンにして7-zipを使用して親ディレクトリを圧縮することでした。圧縮されたら、zipファイルを削除できました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.