1
votes

I am trying to delete all Version History files in SharePoint Online through PowerShell. My research has provided plenty of examples on how to do this in SharePoint 2010 and 2013 but not SharePoint Online. The files reside in Document Libraries. The script below seemed promising for my task but I have been unable to modify it to work for SharePoint Online. What changes would be necessary to make it work for SharePoint Online?

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
# get site
$site = new-object Microsoft.SharePoint.SPSite("http://xxx.sharepoint.com")
# loop through webs
foreach ($web in $site.AllWebs)
{
   write-host $web.url
   # loop through all lists in web
   foreach ($list in $web.Lists)
   {
      # examine if BaseType of list is NOT a Document Library
      if (($list.BaseType -eq "DocumentLibrary") -and ($list.EnableVersioning))
      {
         # Delete all version history
         foreach ($item in $list.Items)
         {
           # work with the file object as we're in a document library
           $file = $item.File
           # delete all versions
           $file.Versions.DeleteAll()
         }
      }
   }
}
$web.Dispose();
$site.Dispose();
2
There's a thing called Sharepoint Online Management Shell to get you started... As an alternative Sharepoint provides several Webservices, which you might access from remote...Peter Schneider

2 Answers

1
votes

The code below combines PowerShell and CSOM. It worked for me. You can delete all Versions or adjust the Versions to be deleted using the Counter in the Loop.

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

$password = Read-Host -Prompt "Enter password" -AsSecureString
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials("userID@yourtenant.com", $password)

$siteUrl = "https://yourtenant.sharepoint.com/sites/yoursitecollection"
$context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$context.Credentials = $credentials


$fileUrl = "/sites/yoursitecollection/path_to_file/filename";
$versions = $context.Web.GetFileByServerRelativeUrl($fileUrl).Versions;

$context.Load($versions)
$context.ExecuteQuery()

for($i=2;$i -lt $versions.Count-2; $i++) 
{
    $versions[$i].DeleteObject()
    $context.ExecuteQuery()
}
0
votes

For older versions of SharePoint you may need to mimic the browser. Essentially, you would request the version history page content, get the REQUESTDIGEST and VIEWSTATE, and perform POST requests to specially crafted URL and request body for each unneeded version using the obtained values.

E.g.:

$httpResponse = Invoke-WebRequest -Uri "$baseUri/_layouts/15/Versions.aspx?list=$listId&ID=$id" -UseDefaultCredentials
$httpResponse.Forms["aspnetForm"].Fields["__VIEWSTATE"]
$httpResponse.Forms["aspnetForm"].Fields["__REQUESTDIGEST"].Replace(" ","+")

...

    $httpResponse = Invoke-WebRequest -UseDefaultCredentials -MaximumRedirection 0 -ErrorAction SilentlyContinue -Method "POST" `
        -Uri "$baseUri/_layouts/15/versions.aspx?list=$listId&ID=$($_.ID)&col=Number&order=d&op=Delete&ver=$($_.Version)" `
        -ContentType "application/x-www-form-urlencoded" -Body ("MSOWebPartPage_PostbackSource=&MSOTlPn_SelectedWpId=&MSOTlPn_View=0&MSOTlPn_ShowSettings=False&MSOGallery_SelectedLibrary=&MSOGallery_FilterString="+
            "&MSOTlPn_Button=none&__EVENTTARGET=&__EVENTARGUMENT=&MSOSPWebPartManager_DisplayModeName=Browse&MSOSPWebPartManager_ExitingDesignMode=false&MSOWebPartPage_Shared=&MSOLayout_LayoutChanges=&MSOLayout_InDesignMode=&MSOSPWebPartManager_OldDisplayModeName=Browse&MSOSPWebPartManager_StartWebPartEditingName=false&MSOSPWebPartManager_EndWebPartEditing=false&_maintainWorkspaceScrollPosition=0"+
            "&__REQUESTDIGEST=$digest&__VIEWSTATE=$([System.Net.WebUtility]::UrlEncode($viewstate))&__VIEWSTATEGENERATOR=01175E75&__SCROLLPOSITIONX=0&__SCROLLPOSITIONY=0"+
            "&__EVENTVALIDATION=$([System.Net.WebUtility]::UrlEncode($ev))")

    if ($httpResponse.StatusCode -eq 302) { #success
        write-host "v" -NoNewline -foregroundcolor DarkGreen
        $vCount++
    } else { #some error
        write-host "x" -NoNewline -foregroundcolor Red

        if ($httpResponse.Forms[0].Action.StartsWith("error")) {
            write-host $httpResponse.Content.Substring($httpResponse.Content.IndexOf("ctl00_PlaceHolderMain_LabelMessage")+36,300).Split("<")[0] -ForegroundColor Magenta
        }

        ...
    }

Note that it is unnecessary to follow the 302 redirect after the POST.