Bulk delete items and folders from Sharepoint document library using Powershell

Fri, Aug 10, 2018 2-minute read

I’ll cut to the chase. A lot has been written about how to handle large lists and how to handle bulk deleting things. To summarise: getting all items and iterating one by one is *not* the way to do it.

The right way to do it is to use the ProcessBatchData method on the SPWeb object.

Have done this plenty of times in C# but this time I wanted to cut straight to Powershell. A quick Google later and I found Daniel Root’s boiler plate. It properly handles checked out files as well, and deletes folders. Ideal!

I’ve made a quick tweak to check for null parameters.


if($null -eq $url -or $null -eq $libraryName)
write-host "Must provide params URL and LibraryName."

$w = get-spweb $url 
$l = $w.Lists[$libraryName] 
$format = "<method><setlist Scope=`"Request`">$($l.ID)</setlist><setvar Name=`"ID`">{0}</setvar><setvar Name=`"Cmd`">Delete</setvar><setvar Name=`"owsfileref`">{1}</setvar></method>"

function DeleteAllFiles($folder) 
    $count = $folder.Files.Count - 1 
    if($count -gt -1){ 
    Write-Host "Deleting $count files..." 
    for($i = $count; $i -gt -1; $i--){ 
        $f = $folder.Files[$i]; 
        if($f.CheckOutStatus -ne [Microsoft.SharePoint.SPFile+SPCheckOutStatus]::None){ 
            $f.CheckIn("Checkin by admin");    

function BuildBatchDeleteCommand($items) 
    $sb = new-object System.Text.StringBuilder 
    $sb.Append("< ?xml version=`"1.0`" encoding=`"UTF-8`"?><batch>") 
    $items | %{ 
        $item = $_ 
return $sb.ToString() 

$count = $l.CheckedOutFiles.Count -1; 
Write-Host "Taking over $count items that have never been checked in." 
for($i = $count; $i -gt -1; $i--){ 
    $f = $l.CheckedOutFiles[$i]; 
    Write-Host $f.Url 


Write-Host "Deleting $($l.Items.Count) items" 
while($l.Items.Count -gt 0){ 
    $q = new-object "Microsoft.SharePoint.SPQuery" 
    $q.ViewFields="<fieldref Name=`"ID`"></fieldref>" 
    $q.ViewAttributes = "Scope=`"Recursive`"" 

    $items = $l.GetItems($q) 
    $cmd = BuildBatchDeleteCommand($items) 
    Write-Host "Deleting $($items.Count) items..." 
    $result = $w.ProcessBatchData($cmd) 
    if ($result.Contains("ErrorText")){ break; } 
    Write-Host "Deleted. $($l.Items.Count) items left..." 

Write-Host "Deleting $count folders..." 
$l.Folders | %{$_.Url.ToString()} | sort -descending | %{ 
    $folder = $_ 
    $f = $w.GetFolder($folder)