4
\$\begingroup\$

I am sick of File Explorer's super slow deletion speed, so I tried to write a PowerShell script to make deletion faster, and while it does its job, its speed isn't as high as what I intended it to be.

I have written this:

Function Fast-Delete {
    Param(
    [Parameter(Valuefrompipeline=$True, Mandatory=$True)] [String]$Directory0
    )
    Write-Warning "This Process Will Delete Everything In The Target Directory: $Directory0, Do You Want To Confirm Deletion?" -Warningaction Inquire
    $Directory=$Directory0
    While ((Get-Childitem -Path $Directory0 -Depth 0 -Force).Count -Ne 0) {
    If ((Get-Childitem -Path $Directory -Directory -Force -Depth 0).Count -Ne 0) {
    $Directory=(Get-Childitem -Path $Directory -Directory -Force -Depth 0).Fullname | Select-Object -Index 0
    }
    If ((Get-Childitem -Path $Directory -File -Force).Count -Ne 0) {
    (Get-Childitem -Path $Directory -File -Recurse -Force).Fullname | Foreach {Remove-Item -Path $_}
    }
    $Directory1=$Directory
    $Directory=$Directory | Split-Path -Parent
    Remove-Item -Path $Directory1
    }
    Remove-Item -Path $Directory0
}

It is significantly faster than explorer, but still isn't ideal, I have tested it, I used it to delete 208,000 files in 1,000 folders , and the folders disappear at speed of 1 per second, so it's about 208 files/s, now the next challenge should be parallelization, But this is currently really way above me, but it shouldn't be too hard, I am just not experienced enough.

Update2

I have managed to make it run in parallel with this script:

function Parallel-Delete {
    param(
    [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=0)] [array]$filelist,
    [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=1)] [int]$number
    )
    0..($filelist.count-1) | Where-Object {$_ % 16 -eq $number} | foreach {Remove-Item -Path $filelist[$_]}
}

Function Fast-Delete {
    Param(
    [Parameter(Valuefrompipeline=$True, Mandatory=$True)] [String]$Directory0
    )
    Write-Warning "This Process Will Delete Everything In The Target Directory:  $Directory0, Do You Want To Confirm Deletion?" -Warningaction Inquire
    $Directory=$Directory0
    While ((Get-Childitem -Path $Directory0 -Depth 0 -Force).Count -Ne 0) {
        If ((Get-Childitem -Path $Directory -Directory -Force -Depth 0).Count -Ne 0) {
            $Directory=(Get-Childitem -Path $Directory -Directory -Force -Depth 0).Fullname | Select-Object -Index 0
        }
        If ((Get-Childitem -Path $Directory -File -Force).Count -Ne 0) {
            If ((Get-Childitem -Path $Directory -File -Force).Count -Ge 128) {
                [array]$filelist=(Get-Childitem -Path $Directory -File -Force).Fullname
                0..15 | foreach-object {Invoke-Command -ScriptBlock { Parallel-Delete $filelist $_}}
                } else {
                (Get-Childitem -Path $Directory -File -Force).Fullname | Foreach {Remove-Item -Path $_}
            }
        }
        $Directory1=$Directory
        $Directory=$Directory | Split-Path -Parent
        Remove-Item -Path $Directory1
        }
    Remove-Item -Path $Directory0 -erroraction silentlycontinue
}
$Directory0=Read-Host "Please input target directory to be deleted"
Fast-Delete $Directory0

But it still isn't ideal, it isn't 15 times faster as expected, what did I miss?

Edit: simplified the creation of parallel processes.

\$\endgroup\$
8
  • 2
    \$\begingroup\$ the fastest way to delete an entire dir tree is to use robocopy. you mirror a blank "source" dir to the one you want removed ... and the "destination" gets emptied quickly. [grin] \$\endgroup\$
    – Lee_Dailey
    Dec 9 '20 at 7:33
  • \$\begingroup\$ @Lee_Dailey, in fact I wanted to write a new script, not to use existing things, and the method you mentioned sounds like a bug... \$\endgroup\$ Dec 9 '20 at 7:51
  • 3
    \$\begingroup\$ i understand your desire. [grin] as for a bug ... it is exactly what the options mean - mirror empty source to full destination gives empty source and empty destination. so ... have fun playing with a script ...but PoSh will always be slower than any well written utility. \$\endgroup\$
    – Lee_Dailey
    Dec 9 '20 at 8:08
  • \$\begingroup\$ And I have tried Start-Job, but they just hang in place, they are not working so I used stop-job to terminate them... And still I can't pass to variables to new powershell process started by start-process... \$\endgroup\$ Dec 15 '20 at 10:37
  • \$\begingroup\$ i would narrow your problems to specifics ... and open a Question for each of them. the pass variable to start-process question has been answered here OR in stackoverflow many times. \$\endgroup\$
    – Lee_Dailey
    Dec 15 '20 at 23:37
0
\$\begingroup\$

May be try this:

#solution 1 - Remove content of dir 
remove-item "C:\temp\tmp2\*" -Recurse -Force

#Solution 2 - Remove dir and recreate dir
remove-item "C:\temp\tmp2\" -Recurse -Force
New-Item "C:\temp\tmp2\" -ItemType Directory

#Solution 3 - Loop into dir and remove all with intercept error
Get-ChildItem "C:\temp\tmp2\" -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
\$\endgroup\$
1
  • \$\begingroup\$ You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Apr 25 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.