บังคับให้ลบไฟล์และไดเรกทอรีใน 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 ใน cmdlet นี้ทำงานไม่ถูกต้อง

และ

เนื่องจากพารามิเตอร์ Recurse ใน cmdlet นี้มีข้อบกพร่องคำสั่งใช้ Get-Childitem cmdlet เพื่อรับไฟล์ปรารถนา d และใช้ผู้ดำเนินการไปป์ไลน์เพื่อส่งไปยัง cmdlet ลบรายการ

และเสนอทางเลือกนี้เป็นตัวอย่าง:

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

ดังนั้นคุณควรท่อเข้าไปในget-childitem -recurseremove-item


ขอบคุณ เพิ่งพบกระทู้นี้จากปี 2006: vistax64.com/powershell/ …ดูเหมือนว่า Microsoft ไม่สนใจที่จะแก้ไขปัญหานี้
— Mauricio Scheffer

@mausch: ดูข้อมูลนี้ล่าสุด แต่ยังไม่ได้รับการแก้ไขอ้างอิง: ลบรายการ
— หยุดชั่วคราวจนกว่าจะมีประกาศเพิ่มเติม

หากคุณทำการสำรวจเส้นทางและลบคุณจะต้องสำรวจไดเรกทอรีลูกก่อนและไฟล์ก่อน
— fschwiet

2
อย่างน้อยเอกสารบอกว่ามันไม่ทำงาน
— derekerdmann

6
ฉันต้องใส่ทั้ง -force -recurse flag สำหรับ Remove-Item มิฉะนั้นจะทำให้ฉันแจ้งเตือน "โปรดยืนยัน" Get-ChildItem -Path $ Destination -Recurse ลบรายการ - บังคับ
— ชดเชย

17

@JamesCW: ปัญหายังคงมีอยู่ใน PowerShell 4.0

ฉันลองวิธีแก้ปัญหาอื่นและใช้งานได้: ใช้ cmd.exe:

&cmd.exe /c rd /s /q $somedirectory

1
ดี rd / s / q!
— JamesCW

ฉันได้ลองใช้ชุดรูปแบบของ Get-ChildItem ทุกครั้ง ลองซ้ำลูป โทรiisresetก่อนที่จะลบและไม่มีอะไรดูเหมือนว่าจะทำงานได้อย่างน่าเชื่อถือ ฉันจะลองอันนี้แม้ว่าฉันจะได้เห็นมันครั้งแรกฉันก็รู้สึกอึดอัดใจที่มีดอสอยู่ภายใน Powershell ของฉัน ...
— Peter McEvoy

น่าเสียดายที่rd /sล้มเหลวเป็นระยะเช่นกัน (แต่ดูเหมือนว่าจะน้อยกว่าRemove-Item): github.com/Microsoft/console/issues/309
— mklement

ไม่ชอบเครื่องหมายทับด้วยคสำหรับฉัน คุณต้องนำหน้ามันโดย powershell - คำสั่งและอ้างส่วน cmd.exe? ฉันได้รับ "คุณต้องระบุค่านิพจน์หลังจากตัวดำเนินการ '/' "โทเค็นที่ไม่คาดคิด 'c' ในการแสดงออกหรือคำสั่งมันเหมือนกันกับ powershell - คำสั่งที่อยู่ด้านหน้ามัน / จำเป็นต้องหลบหนีหรือไม่
— มิเชล

7

ETA 20181217: PSVersion 4.0 และใหม่กว่าจะยังคงล้มเหลวในบางสถานการณ์ดูคำตอบอื่นโดยMehrdad Mirrezaและรายงานข้อผิดพลาดที่ยื่นโดยmklement

mklementมอบโซลูชัน Proof of Concept ที่คำตอบ SOนี้เนื่องจากข้อบกพร่องกำลังรอการแก้ไขอย่างเป็นทางการ

เวอร์ชันใหม่ของPowerShell( PSVersion 4.0) ได้แก้ไขปัญหานี้แล้วและRemove-Item "targetdirectory" -Recurse -Forceทำงานได้โดยไม่มีปัญหาเรื่องเวลา

คุณสามารถตรวจสอบเวอร์ชั่นของคุณโดยเรียกใช้$PSVersiontableจากภายใน ISE หรือPowerShellพร้อมท์ 4.0 เป็นรุ่นที่มาพร้อมกับWindows 8.1และServer 2012 R2สามารถติดตั้งบน Windows รุ่นก่อนหน้าได้เช่นกัน


5
ยังคงเกิดขึ้นกับฉันใน PowerShell 4.0
— ajbeaven

10
ยังคงเกิดขึ้นใน PowerShell v5 !!!!! 11 !! 1! 1 !!!
— Richard Hauer

@ RichardHauer ดีตอนนี้ฉันแค่สับสน
— JamesCW

2
@JamesCW ฉันได้แปลงเป็นrdเวอร์ชั่นแล้ว นอกเหนือจากการทำงานจริงแล้วมันเร็วกว่าประมาณ 3 เท่า
— Richard Hauer

ปัญหายังไม่ได้รับการแก้ไขตั้งแต่ Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - ดูรายงานข้อผิดพลาดนี้ ในขณะที่rd /sอาจล้มเหลวน้อยลงมันก็พัง - ดูรายงานข้อผิดพลาดนี้
— mklement

4

ปรับปรุง : ดูเหมือนว่ามีแผนการที่จะทำให้การกำจัดของ Windows APIs ระบบแฟ้มรายการซิงโคร แต่พวกเขาไม่ได้ซิงโครยังเป็นของวินโดวส์ 10 รุ่น 1903 - ดูความคิดเห็นนี้บน GitHub


คำตอบที่มีอยู่ช่วยลดปัญหาเพื่อให้เกิดขึ้นน้อยลง แต่พวกเขาไม่ได้ระบุสาเหตุที่แท้จริงซึ่งเป็นสาเหตุที่ความล้มเหลวยังคงสามารถเกิดขึ้นได้

Remove-Item -Recurseไม่ตรงกันโดยไม่คาดคิดท้ายที่สุดเนื่องจากวิธีการWindows API สำหรับการลบไฟล์และไดเรกทอรีนั้นไม่ตรงกันโดยเนื้อแท้และRemove-Itemไม่ได้คำนึงถึงสิ่งนั้น

สิ่งนี้เกิดขึ้นเป็นระยะ ๆ อย่างไม่อาจคาดการณ์ได้ในหนึ่งในสองวิธี:

  • กรณีของคุณ: การลบไดเรกทอรีที่ไม่ได้รับอนุญาตนั้นอาจล้มเหลวได้หากการลบไดเรกทอรีย่อยหรือไฟล์ในนั้นยังไม่เสร็จสิ้นเมื่อถึงเวลาที่มีความพยายามที่จะลบไดเรกทอรีหลัก

  • น้อยกว่าปกติ: การสร้างไดเรกทอรีที่ถูกลบใหม่ในทันทีหลังจากการลบอาจล้มเหลวได้เนื่องจากการลบอาจยังไม่เสร็จตามเวลาที่พยายามสร้างใหม่

ปัญหาไม่เพียง แต่ส่งผลกระทบต่อ PowerShell ของRemove-Itemแต่ยังcmd.exeเป็นrd /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 } }
— Farway

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
นี่เป็นสิ่งที่ดี แต่ฉันยังคงมีปัญหากับมัน หากคำสั่ง mkdir รันก่อนที่ระบบจะเสร็จสิ้นคำสั่ง rm สามารถโยน System.UnauthorizedAccessException ด้วย FullyQualifiedErrorId ของ ItemExistsUnauthorizedAccessError นั่นคือระบบปฏิบัติการยังไม่ได้ลบไดเรกทอรี (ใน HDD ที่ช้าของฉัน) ดังนั้นข้อผิดพลาดนั้นจะต้องถูกจับเช่นกัน และเป็นข้อผิดพลาดที่ไม่สิ้นสุดดังนั้น ErrorAction จะต้องตั้งค่าเป็น Stop ฉันยังใส่คำสั่ง rm ในบล็อกลองด้วยเช่นกันในกรณีที่มีข้อผิดพลาด IO ชั่วคราวเมื่อลบ
— Mark Lapierre

ฉันไม่อยากจะเชื่อเลยว่าสิ่งนี้จะต้องทำ ประณาม Powershell ครับ!
— jcollum

3

ในการลบไดเรกทอรีและเนื้อหาในสองขั้นตอน ก่อนอื่นให้ลบเนื้อหาจากนั้นจึงทำการสร้างโฟลเดอร์เอง การใช้วิธีแก้ปัญหาสำหรับรายการลบแบบเรียกซ้ำที่ผิดพลาดโซลูชันจะมีลักษณะดังนี้

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

วิธีนี้คุณสามารถลบไดเรคทอรีหลักได้เช่นกัน


1
นี่คือสิ่งที่คำตอบที่ได้รับการยอมรับกล่าวว่า คุณมีอะไรเพิ่มหรือไม่
— Michael Hampton

1
พวกเขากำลังชี้ให้เห็นว่าคำตอบที่ยอมรับไม่ได้ลบไดเรกทอรีตัวเองจึงใช้เวลาสองขั้นตอน
— Paul George

2
Remove-Itemคำสั่งของคุณลงในท่อมีปัญหาเดียวกันกับที่ระบุไว้ มันอาจสะดุดกับรายการไดเรกทอรีที่ไม่ว่างเปล่าในทางเดียวกัน
— Dejan

@Dejan ไดเรกทอรีนี้ยังไม่ว่างถ้าบรรทัดแรกของรหัสนี้ใช้งานได้ใช่ไหม
— Ifedi Okonkwo

1
แม้ว่าสิ่งนี้อาจลดโอกาสเกิดความล้มเหลว แต่ก็ยังสามารถล้มเหลวได้เนื่องจากRemove-Item -Recurseยังมีส่วนเกี่ยวข้องอยู่ ปัญหาพื้นฐานยังคงมีอยู่ใน Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - ดูรายงานข้อผิดพลาดนี้
— mklement

3

เอ้ย คำตอบมากมาย ฉันชอบอันนี้มากกว่าทุกคน มันง่ายมากสมบูรณ์อ่านได้และทำงานบนเครื่อง Windows ทุกเครื่อง มันใช้ฟังก์ชั่นการลบซ้ำของ. NET (ที่เชื่อถือได้) และหากล้มเหลวด้วยเหตุผลบางอย่างมันจะส่งข้อยกเว้นที่เหมาะสมที่สามารถจัดการได้ด้วยบล็อกลอง / catch

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

โปรดสังเกตว่าResolve-Pathบรรทัดนั้นมีความสำคัญเนื่องจาก. NET ไม่ทราบถึงไดเรกทอรีปัจจุบันของคุณเมื่อแก้ไขพา ธ ของไฟล์ที่เกี่ยวข้อง นั่นเป็นเพียง gotcha เดียวที่ฉันนึกได้


2

นี่คือสิ่งที่ฉันทำงาน:

$Target = "c:\folder_to_delete"

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

Remove-Item -Recurse -Force $Target

บรรทัดแรกนี้จะลบไฟล์ทั้งหมดในทรี ครั้งที่สองจะลบโฟลเดอร์ทั้งหมดรวมถึงด้านบน


แม้ว่าสิ่งนี้อาจลดโอกาสเกิดความล้มเหลว แต่ก็ยังสามารถล้มเหลวได้เนื่องจากRemove-Item -Recurseยังมีส่วนเกี่ยวข้องอยู่ ปัญหาพื้นฐานยังคงมีอยู่ใน Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - ดูรายงานข้อผิดพลาดนี้
— mklement


0

ฉันมีปัญหานี้กับไดเรกทอรีที่จะไม่ลบ ฉันพบว่าหนึ่งในโฟลเดอร์ย่อยเสียหายและเมื่อฉันพยายามย้ายหรือเปลี่ยนชื่อเด็กคนนั้นฉันได้รับข้อความแสดงข้อผิดพลาดว่ามีบางอย่างหายไป ฉันพยายามใช้ rm -Force และได้รับข้อผิดพลาดเดียวกับที่คุณทำ

สิ่งที่ใช้ได้ผลสำหรับฉันคือการบีบอัด dir พาเรนต์โดยใช้ 7-zip พร้อมตัวเลือก "ลบไฟล์หลังจากการบีบอัด" เมื่อมันถูกบีบอัดฉันสามารถลบไฟล์ zip ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.