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.
param($url,$libraryName)
if($null -eq $url -or $null -eq $libraryName)
{
write-host "Must provide params URL and LibraryName."
break
}
$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");
}
$f.Delete()
}
}
}
function BuildBatchDeleteCommand($items)
{
$sb = new-object System.Text.StringBuilder
$sb.Append("< ?xml version=`"1.0`" encoding=`"UTF-8`"?><batch>")
$items | %{
$item = $_
$sb.AppendFormat($format,$item.ID.ToString(),$item.File.ServerRelativeUrl.ToString())
}
$sb.Append("</batch>")
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];
$f.TakeOverCheckOut()
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`""
$q.RowLimit=1000
$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 = $_
$folder
$f = $w.GetFolder($folder)
$f.Files.Count
$f.Delete()
}