Hapus paksa file dan direktori di PowerShell terkadang gagal, tetapi tidak selalu

33

Saya mencoba menghapus direktori secara rekursif rm -Force -Recurse somedirectory, saya mendapatkan beberapa kesalahan "Direktori tidak kosong". Jika saya coba lagi perintah yang sama , itu berhasil.

Contoh:

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>

Tentu saja, ini tidak selalu terjadi . Juga, itu tidak terjadi hanya dengan _svndirektori, dan saya tidak memiliki cache TortoiseSVN atau hal-hal seperti itu sehingga tidak ada yang menghalangi direktori.

Ada ide?

Mauricio Scheffer
sumber

Jawaban:

31

help Remove-Item mengatakan:

Parameter Perulangan dalam cmdlet ini tidak berfungsi dengan benar.

dan

Karena parameter Perulangan di cmdlet ini salah, perintah menggunakan cmdlet Get-Childitem untuk mendapatkan file d keinginan, dan menggunakan operator pipa untuk meneruskannya ke cmdlet Remove-Item.

dan mengusulkan alternatif ini sebagai contoh:

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

Jadi Anda harus menyalurkan get-childitem -recurseke remove-item.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
Terima kasih. Baru saja menemukan utas ini dari 2006: vistax64.com/powershell/… sepertinya Microsoft tidak benar-benar tertarik untuk memperbaikinya.
Mauricio Scheffer
@mausch: Lihat ini lebih baru, tetapi masih belum terselesaikan, referensi: Remove-Item -Recurse
Dijeda sampai pemberitahuan lebih lanjut.
jika Anda melakukan traversal dan menghapus, Anda harus menelusuri direktori anak terlebih dahulu, dan file mereka terlebih dahulu.
fschwiet
2
Setidaknya dokumentasi mengatakan itu tidak berfungsi.
derekerdmann
6
Saya harus meletakkan kedua flag-force -recurse untuk Remove-Item, jika tidak hal itu membuat saya meminta "tolong konfirmasi" Get-ChildItem -Path $ Destination -Recurse | Remove-Item -force -recurse
MiFreidgeim BEGITU berhenti menjadi jahat
17

@ JamesCW: Masalahnya masih ada di PowerShell 4.0

Saya mencoba solusi lain dan berhasil: gunakan cmd.exe:

&cmd.exe /c rd /s /q $somedirectory
Mehrdad Mirreza
sumber
1
Rd / s / q yang bagus!
JamesCW
Saya sudah mencoba setiap variasi Get-ChildItem; coba lagi loop; menelepon iisresetsebelum menghapus dan tidak ada yang bekerja andal . Saya akan mencoba yang ini, walaupun ketika pertama kali melihatnya saya menolak keras untuk memiliki DOS di dalam Powershell saya ...
Peter McEvoy
Sayangnya, rd /sgagal sesekali juga (meskipun tampaknya lebih jarang Remove-Item): github.com/Microsoft/console/issues/309
mklement
Tidak suka garis miring c bagi saya. Apakah Anda harus mendahului dengan PowerShell -command dan mengutip bagian cmd.exe Saya mendapatkan "Anda harus memberikan ekspresi nilai mengikuti operator '/'." "Token yang tidak terduga 'c' dalam ekspresi atau pernyataan. Itu sama dengan PowerShell - perintah di depannya. Apakah saya perlu melarikan diri?
Michele
7

ETA 20181217: PSVersion 4.0 dan yang lebih baru masih akan gagal dalam beberapa keadaan, lihat jawaban alternatif oleh Mehrdad Mirreza , dan laporan bug yang diajukan oleh mklement

mklement menyediakan solusi Bukti Konsep pada jawaban SO ini , karena bug sedang menunggu perbaikan resmi

Versi baru PowerShell( PSVersion 4.0) telah menyelesaikan masalah ini sepenuhnya dan Remove-Item "targetdirectory" -Recurse -Forceberfungsi tanpa masalah waktu.

Anda dapat memeriksa versi Anda dengan menjalankan $PSVersiontabledari dalam ISE atau PowerShellprompt. 4.0 adalah versi yang disertakan bersama Windows 8.1dan Server 2012 R2, dan dapat diinstal pada versi Windows sebelumnya juga.

JamesCW
sumber
5
Masih terjadi bagi saya di PowerShell 4.0
ajbeaven
10
Masih terjadi di PowerShell v5 !!!!! 11 !! 1! 1 !!!
Richard Hauer
@ RichardHauer baik sekarang saya hanya bingung
JamesCW
2
@ JamesCW Saya sudah mengonversi ke rdversi. Selain benar-benar berfungsi, ini sekitar 3x lebih cepat
Richard Hauer
Masalahnya belum diperbaiki pada Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - lihat laporan bug ini . Meskipun rd /smungkin gagal lebih jarang, itu juga rusak - lihat laporan bug ini .
mklement
4

Pembaruan : Tampaknya ada rencana untuk membuat API penghapusan item-sistem file Windows sinkron, tetapi mereka belum sinkron pada Windows 10 versi 1903 - lihat komentar ini di GitHub .


Jawaban yang ada mengurangi masalah, sehingga jarang terjadi, tetapi mereka tidak mengatasi akar penyebabnya , itulah sebabnya kegagalan masih bisa terjadi.

Remove-Item -Recursesecara tak terduga tidak sinkron , pada akhirnya karena metode Windows API untuk penghapusan file dan direktori secara inheren tidak sinkron dan Remove-Itemtidak menjelaskan hal itu.

Ini sebentar-sebentar, tak terduga dapat dimanifestasikan dalam salah satu dari dua cara:

  • Kasus Anda: Menghapus direktori nonempty itu sendiri bisa gagal, jika penghapusan subdirektori atau file di dalamnya belum selesai pada saat upaya dilakukan untuk menghapus direktori induk.

  • Lebih jarang: Menciptakan direktori yang dihapus segera setelah penghapusan bisa gagal, karena penghapusan mungkin belum selesai pada saat penciptaan kembali dicoba.

The Masalah tidak hanya mempengaruhi PowerShell ini Remove-Item, tetapi juga cmd.exe's rd /sserta NET[System.IO.Directory]::Delete() :

Pada Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 / cmd.exe10.0.17134.407 / .NET Framework 4.7.03056, .NET Core 2.1, tidak Remove-Item, juga rd /s, atau [System.IO.Directory]::Delete()bekerja dengan andal , karena mereka gagal untuk memperhitungkan asinkron perilaku fungsi penghapusan / direktori file Windows API :

Untuk fungsi PowerShell khusus yang menyediakan solusi sinkronisasi yang andal , lihat jawaban SO ini .

mklement
sumber
Saat menangani file di mana penghapusan pasti:while($true) { if ( (Remove-Item [...] *>&1) -ne $null) { Start-Sleep 0.5 } else { break } }
Farway
3

Jawaban saat ini sebenarnya tidak akan menghapus direktori, hanya anak-anaknya. Selain itu akan ada masalah dengan direktori bersarang karena akan mencoba menghapus direktori sebelum isinya. Saya menulis sesuatu untuk menghapus file dalam urutan yang benar, masih akan memiliki masalah yang sama meskipun kadang-kadang direktori masih ada setelahnya.

Jadi, sekarang saya menggunakan sesuatu yang akan menangkap pengecualian, tunggu, dan coba lagi (3 kali):

Untuk saat ini saya menggunakan ini:

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)
    }
}
fschwiet
sumber
1
Ini bagus tapi saya masih punya masalah dengan itu. Jika perintah mkdir berjalan sebelum sistem menyelesaikan perintah rm, ia dapat melempar Sistem. Yaitu, direktori belum dihapus oleh OS (pada HDD lambat saya). Jadi kesalahan itu perlu ditangkap juga. Dan ini adalah kesalahan yang tidak berakhir, jadi ErrorAction perlu diatur ke Stop. Saya juga menempatkan perintah rm di blok coba juga, hanya dalam kasus ada kesalahan IO sementara saat menghapus.
Mark Lapierre
Aku tidak percaya ini harus dilakukan. Sial, Powershell menyebalkan!
jcollum
3

Untuk menghapus direktori dan isinya dibutuhkan dua langkah. Pertama-tama hapus isinya, lalu folder itu sendiri. Menggunakan solusi untuk item hapus rekursif yang salah solusinya akan terlihat seperti ini:

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

Dengan cara ini Anda dapat menghapus direktori induk juga.

Carl Baker
sumber
1
Inilah tepatnya jawaban yang diterima. Apakah Anda punya sesuatu untuk ditambahkan?
Michael Hampton
1
Mereka menunjukkan bahwa jawaban yang diterima tidak menghapus direktori itu sendiri, oleh karena itu dibutuhkan dua langkah.
Paul George
2
The Remove-Itemperintah perpipaan Anda ke memiliki masalah yang sama yang awalnya menyatakan. Mungkin tersandung pada item direktori yang tidak kosong dengan cara yang sama.
Dejan
@Jejan Direktori ini masih belum bisa kosong jika baris pertama dari kode ini berfungsi, bukan?
Ifedi Okonkwo
1
Meskipun ini dapat mengurangi kemungkinan kegagalan, itu masih bisa gagal, mengingat Remove-Item -Recursemasih terlibat. Masalah mendasar masih ada pada Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - lihat laporan bug ini .
mklement
3

Astaga. Banyak jawaban. Jujur saya lebih suka yang ini daripada mereka semua. Ini sangat sederhana, lengkap, dapat dibaca, dan bekerja di semua mesin Windows. Ia menggunakan fungsionalitas penghapusan rekursif .NET (andal) dan jika gagal karena suatu alasan, ia mengeluarkan pengecualian yang dapat ditangani dengan blok coba / tangkap.

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

Perhatikan bahwa Resolve-Pathjalur ini penting karena .NET tidak mengetahui direktori Anda saat ini ketika menyelesaikan jalur file relatif. Itu tentang satu-satunya gotcha yang bisa saya pikirkan.

Phil
sumber
2

Inilah yang saya kerjakan:

$Target = "c:\folder_to_delete"

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

Remove-Item -Recurse -Force $Target

Baris pertama ini menghapus semua file di pohon. Yang kedua menghapus semua folder termasuk bagian atas.

James Copeland
sumber
Meskipun ini dapat mengurangi kemungkinan kegagalan, itu masih bisa gagal, mengingat Remove-Item -Recursemasih terlibat. Masalah mendasar masih ada pada Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - lihat laporan bug ini .
mklement
0

Saya punya masalah dengan direktori yang tidak mau dihapus. Saya menemukan bahwa salah satu subfolder rusak dan ketika saya mencoba untuk memindahkan atau mengganti nama anak itu dir saya mendapat pesan kesalahan mengatakan sesuatu tentang hal itu hilang. Saya mencoba menggunakan rm -Force dan mendapatkan kesalahan yang sama seperti yang Anda lakukan.

Apa yang berhasil bagi saya adalah mengompresi dir induk menggunakan 7-zip dengan opsi "Hapus file setelah kompresi" dicentang. Setelah dikompresi, saya bisa menghapus file zip.

RedDawnRising
sumber