SharePoint Online: Delete Version History using PowerShell
The versioning feature in SharePoint Online allows you to access previous copies of a document or list items. By default, versioning is enabled on your SharePoint Online document libraries. When a user makes edits, SharePoint automatically creates a new version with metadata such as created by, Timestamps, etc.
How to Delete Version History in SharePoint Online?
In this blog post, we’ll look at how to delete version history in SharePoint Online. This can come in handy if you need to clear out older versions of files that are taking up storage space, or simply want to clean up previous versions. We’ll also show you how to delete version history in SharePoint Online quickly and easily using PowerShell.
To delete all previous versions of a document in SharePoint, follow these steps:
- Navigate to your SharePoint Library, select the file, and then click on “Version History” from the ribbon menu.
- From the version history page, click on the “Delete all versions” link, and confirm if prompted!
SharePoint Online: Delete Version History using PowerShell
You may delete all versions of a document or leave the latest ‘N’ number of versions and then delete the rest. Here are my PowerShell scripts to delete versions in SharePoint Online:
Case 1: Delete All Versions for a particular file:
This PowerShell script deletes all versions in SharePoint Online.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Config Parameters
$SiteURL= "https://crescent.sharepoint.com/sites/sales/"
$FileURL="/Sites/Sales/ProjectDocuments/ProjectMetrics.xlsx"
#Setup Credentials to connect
$Cred = Get-Credential
$Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Cred
#Get the File
$File = $Ctx.Web.GetFileByServerRelativeUrl($FileURL)
#Get all versions of the file
$Versions = $File.Versions
$Ctx.Load($Versions)
$Ctx.ExecuteQuery()
Write-host -f Yellow "Total Number of Versions Found :" $Versions.count
#Delete all versions of the file
$Versions.DeleteAll()
$Ctx.ExecuteQuery()
Write-host -f Green "All versions Deleted for given File!"
}
Catch {
write-host -f Red "Error deleting versions!" $_.Exception.Message
}
Case 2: Delete All Versions for All Files in a Library:
This PowerShell script clears all previous Major versions from all files in a given document library.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Config Parameters
$SiteURL= "https://crescent.sharepoint.com/sites/Marketing"
$LibraryName="Branding"
$BatchSize = 500
#Setup Credentials to connect
$Cred = Get-Credential
$Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Cred
#Get the web and Library
$Web=$Ctx.Web
$List=$web.Lists.GetByTitle($LibraryName)
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>"
Do {
#Get items from the list in batches
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each file in the library
Foreach($Item in $ListItems | Where {$_.FileSystemObjectType -eq "File"})
{
#Get all versions of the file
$Ctx.Load($Item.File)
$Ctx.Load($Item.File.Versions)
$Ctx.ExecuteQuery()
Write-host "Processing Item:" $Item.file.Name
#Delete all versions of the file
If($Item.File.Versions.count -gt 0)
{
$Item.File.Versions.DeleteAll()
$Ctx.ExecuteQuery()
Write-host -f Green "`tAll Versions deleted on "$Item.file.Name
}
}
} While ($Query.ListItemCollectionPosition -ne $null)
}
Catch {
write-host -f Red "Error Deleting version History!" $_.Exception.Message
}
Case 3: Leave the Last Five versions and Delete the Rest in the Library:
This time, let’s keep only the last “N” number of versions and trim the rest.
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Config Parameters
$SiteURL= "https://crescent.sharepoint.com/sites/sales/"
$LibraryName="Project Documents"
$VersionsToKeep=5
$BatchSize = 500
#Setup Credentials to connect
$Cred = Get-Credential
$Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Cred
#Get the web and Library
$Web=$Ctx.Web
$List=$web.Lists.GetByTitle($LibraryName)
#Get all items from the library
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>"
Do {
#Get items from the list in batches
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each file in the library
Foreach($Item in $ListItems | Where {$_.FileSystemObjectType -eq "File"})
{
#Get all versions of the file
$Versions = $Item.File.Versions
$Ctx.Load($Versions)
$Ctx.Load($Item.File) #To get File Name
$Ctx.ExecuteQuery()
Write-host -f Yellow "Total Number of Versions Found in '$($Item.File.Name )' : $($Versions.count)"
#Check if number of versions are more than limit
While($Item.File.Versions.Count -gt $VersionsToKeep)
{
$Versions[0].DeleteObject()
$Ctx.ExecuteQuery()
Write-host -f Green "`tDeleted Version:" $Versions[0].VersionLabel
#Reload versions
$Ctx.Load($Item.File.Versions)
$Ctx.ExecuteQuery()
}
}
} While ($Query.ListItemCollectionPosition -ne $null)
}
Catch {
write-host -f Red "Error deleting versions!" $_.Exception.Message
}
Trim Excess Versions for All Libraries in a Site
Let’s keep the last “N” number of versions and delete the rest, for all files from all document libraries of a SharePoint Online site:
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Function Cleanup-SPOVersions
{
param
(
[Parameter(Mandatory=$true)] [string] $SiteURL,
[parameter(Mandatory=$false)][int]$VersionsToKeep = 100
)
#Config Parameters
$BatchSize = 500
#Exclude certain libraries
$ExcludedLibraries = @("Form Templates", "Preservation Hold Library", "Site Assets","Site Pages", "Images",
"Site Collection Documents", "Site Collection Images","Style Library")
#Setup Credentials to connect
$Cred = Get-Credential
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
#Get the web and Libraries
$Web=$Ctx.Web
$Ctx.Load($Web)
$Ctx.Load($Web.Lists)
$Ctx.executeQuery()
#Get all document libraries in sharepoint online site
$DocLibraries = $Web.Lists | Where {$_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $False -and $_.Title -notin $ExcludedLibraries}
#Loop through each document library and Get the Title
Foreach ($Library in $DocLibraries)
{
Write-host "Processing Document Library:"$Library.Title -f Yellow
#Get all items from the library
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>"
Do {
#Get items from the library in batches
$ListItems = $Library.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each file in the library
Foreach($Item in $ListItems | Where {$_.FileSystemObjectType -eq "File"})
{
#Get all versions of the file
$Versions = $Item.File.Versions
$Ctx.Load($Versions)
$Ctx.Load($Item.File) #To get File Name
$Ctx.ExecuteQuery()
#Calculate if versions to be cleaned for the file
$VersionsToDelete = $Versions.Count - $VersionsToKeep
If($VersionsToDelete -gt 0)
{
Write-host -f Yellow "`tTotal Number of Versions Found in '$($Item.File.ServerRelativeUrl)' : $($Versions.count)"
#Check if number of versions are more than limit
While($Item.File.Versions.Count -gt $VersionsToKeep)
{
$Versions[0].DeleteObject()
$Ctx.ExecuteQuery()
Write-host -f Green "`tDeleted Version:" $Versions[0].VersionLabel
#Reload versions
$Ctx.Load($Item.File.Versions)
$Ctx.ExecuteQuery()
}
}
}
} While ($Query.ListItemCollectionPosition -ne $null)
}
}
Catch {
write-host -f Red "Error deleting versions!" $_.Exception.Message
}
}
#Call the function to cleanup versions
Cleanup-SPOVersions -SiteURL "https://crescent.sharepoint.com/sites/marketing" -VersionsToKeep 10
If you want to keep the last five versions and delete the rest for a particular file, use:
#Get the File
$File = $Ctx.Web.GetFileByServerRelativeUrl($FileURL)
#Get all versions of the file
$Versions = $File.Versions
$Ctx.Load($Versions)
$Ctx.ExecuteQuery()
$Versionscount = $Versions.count
Write-host -f Yellow "Total Number of Versions Found :" $Versionscount
#Check if number of versions are more than limit
While($File.Versions.Count -gt $VersionsToKeep)
{
write-host "Deleting Version:" $Versions[0].VersionLabel
$Versions[0].DeleteObject()
$Ctx.ExecuteQuery()
#Reload versions
$Ctx.Load($File.Versions)
$Ctx.ExecuteQuery()
}
To delete a particular version by its Label, use: $Versions.DeleteByLabel($LabelID)
You can also delete versions in SharePoint Online using PnP PowerShell: SharePoint Online: Delete Version History using PnP PowerShell
Regarding your statement “In this blog post, we’ll look at how to delete version history in SharePoint Online?”, you don’t put a question mark. That is a statement.
Fixed the typo. Thanks Joe!
Exception calling “ExecuteQuery” with “0” argument(s): “The partner STS returned a wst:RequestFailed error.”
Any tips on this? Getting it trying multiple options (2&3)
Thanks in advance
Hi Salaudeen,
Thank you very much for your script, it helps me a lot !
I have a problem though, I get the error 429. After some searches on the web, I understand that MS is throttling all the requests from my script.
How could I modify the script to “wait” for a while, then to wontinue where it stopped, instead of running it again from the beginning ?
The script could delete some old versions, but now, it can’t reach any other old versions because I get the 429 error code too early.
Thank you for your help !
This seemed to be working like a charm, however after a certain moment it failed with:
Error deleting versions! Exception calling “ExecuteQuery” with “0” argument(s): “The remote server returned an error: (503) Service Unavailable.”
Any ideas?
Thanks, Salaudeen!
those are very helpful.
sadly, for some files im getting an error
‘Exception calling “ExecuteQuery” with “0” argument(s): “Operation is not valid due to the current state of the object.”‘
i moved added try/catch to skip those files, but is there a way to properly fix the error?
Thanks for your great work.
Tried to run Case 2 but get the error after a couple of minutes. Please help to check
Error Deleting version History! Exception calling “ExecuteQuery” with “0” argument(s): “Operation is not valid due to the current state of the object.”
Hi,
Thank you very much for the great job you have done with this script.
Unfortunately after a few seconds after running it I get the error below:
“Error Deleting version History! Exception calling “ExecuteQuery” with “0” argument(s): “The remote server returned an error: (403) Forbidden.”
Any Idea what is causing it?
Thanks,
Nick
add after DO{
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Can you advise on how to do this?
Hi Dan, Any update yet? I have the same isssue.
Hi Salaudeen Rajak, I just used you ps script to delete the version history, many thanks already, it worked like a charm!.
But i have another question: is it possible to prevent sharepoint creating versions for specific extensions please?
Hi Kelly,
You can create a workflow that deletes the version based on the File extension.
How would you implement Case #3 but with a specific folder instead of a whole library name? trying to add the specific folder path in the $LibraryName variable doesnt seem to work
Hello,
I have a client that was having storage issues. I discovered that they had set versioining to 500, reduced this. I then went to clean up the versioning history. Ran the below script, which worked well, however i inevitably get throttled with a 429 error.
Id like to add the snytax to avoid the throttle, but all i can find is one that includes lists and not libriares (as you can see in my below script. Can someone help tell me what syntax i should add and where abouts in my script? Many thanks!
#Load SharePoint CSOM Assemblies
Add-Type -Path “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll”
Add-Type -Path “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll”
#Config Parameters
$SiteURL= “https://XXXXX.sharepoint.com/chcfiles”
$LibraryName=”operations”
$VersionsToKeep=9
#Setup Credentials to connect
$Cred = Get-Credential
$Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = $Cred
#Get the web and Library
$Web=$Ctx.Web
$List=$web.Lists.GetByTitle($LibraryName)
#Get all items from the library
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = “$BatchSize”
Do {
#Get items from the list in batches
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each file in the library
Foreach($Item in $ListItems | Where {$_.FileSystemObjectType -eq “File”})
{
#Get all versions of the file
$Versions = $Item.File.Versions
$Ctx.Load($Versions)
$Ctx.Load($Item.File) #To get File Name
$Ctx.ExecuteQuery()
Write-host -f Yellow “Total Number of Versions Found in ‘$($Item.File.Name )’ : $($Versions.count)”
#Check if number of versions are more than limit
While($Item.File.Versions.Count -gt $VersionsToKeep)
{
$Versions[0].DeleteObject()
$Ctx.ExecuteQuery()
Write-host -f Green “`tDeleted Version:” $Versions[0].VersionLabel
#Reload versions
$Ctx.Load($Item.File.Versions)
$Ctx.ExecuteQuery()
}
}
} While ($Query.ListItemCollectionPosition -ne $null)
}
Catch {
write-host -f Red “Error deleting versions!” $_.Exception.Message
}
Thanks for this. Trying to run Case 2 but get the following error after a couple of minutes. Any suggestions?
Error Deleting version History! Exception calling “ExecuteQuery” with “0” argument(s): “Operation is not valid due to the current state of the object.”
Hello Salaudeen
First of all, many thanks for all your SPO scripts. They’re so usefull !
In order to avoid throttling (error 429), I’m trying to implement the “Batch Execute CSOM PowerShell Scripts to Avoid 429 Resource Throttling Issue in SharePoint Online” method in these scripts (Case #3: delete 5 versions history).
But I don’t know where the batch process should be added
Could you please advise ?
Best
Ciao Salaudeen , thanks for your help! Unfortunately both with Powershell and with PnP I get the error “(401) Not authorized” when I execute these commands, unless I set the user who executes the command as “Admin” or “Additional Admin” on the site. Is there the possibility for a full Sharepoint admin to reduce the versions on all tenant sites (in a simple way, without having to set Admin on 400+ sites)?
401 Unauthorized could be simply because you don’t have access to the site! Its a common misconception that, SharePoint Online Admin or Global Admin gets access to the SharePoint Online sites automatically! NO. You must add your account to the sites still.
Refer:
HI, did it’s possible to have a new SPO connection script plz (i use MFA and he refuse my access).
Use the PnP PowerShell to delete versions in SharePoint Online using PnP PowerShell: How to Delete Version History using PnP PowerShell?
is there a way to run these script being a full Sharepoint admin but not an owner of the Teams/Sharepoint?
I would like tu run a script from an admin that cycle between every sharepoint site and clean the versioning
Post is updated with a script to clean up all libraries in a site. You can call the function with the relevant site URL.
Thank you. It appears to be working now as intended. Thank you for taking the time to freely share your knowledge on this subject! 🙂
I am getting the error “The attempted operation is prohibited because it exceeds the list view threshold” how do I work around this
Hi Matt,
Scripts are updated to handle larger libraries! Please try Now.
Hi Salaudeen,
Is it possible to make a script that delete version history on files that have not been used for the last 90 days ?
Hi Salaudeen,
I am getting the following error. could you please assist why is that?
Error deleting versions! Exception calling “ExecuteQuery” with “0” argument(s): “Cannot contact site at the specified URL URL/Test/. There is no Web named “URL/_vti_bin/sites.asmx”.”
I installed the SharePoint Online Powershell Module as instructed above, but get the following error when running the Case 1 script:
New-Object : Cannot find type [Microsoft.SharePoint.Client.SharePointOnlineCredentials]: verify that the assembly containing this type is
loaded.
At line:7 char:9
+ $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCreden …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
Error deleting versions! Cannot find type [Microsoft.SharePoint.Client.ClientContext]: verify that the assembly containing this type is loaded.
Looks the PowerShell couldn’t load the required CSOM Assemblies. You can try Download and Install CSOM Assemblies for SharePoint Online
Hello,
I got the errors:
“Add-Type : Cannot bind parameter ‘Path’ to the target. Exception setting “Path”: “Cannot find path ‘C:\Program Files\Common Files\Microsoft
Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll’ because it does not exist.”
“Add-Type : Cannot bind parameter ‘Path’ to the target. Exception setting “Path”: “Cannot find path ‘C:\Program Files\Common Files\Microsoft
Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll’ because it does not exist.”
“New-Object : Cannot find type [Microsoft.SharePoint.Client.SharePointOnlineCredentials]: verify that the assembly containing this type is loaded”
Sorry, I’m not familiar with this commands. Also other scripts that pointed at does .dll files, I was able to run without problem eventhough I got the same error message.
You can either Install SharePoint Online PowerShell Module, and remove the first three lines in the script that references DLL files ! Or you can Download and install the SharePoint Online CSOM SDK
how can i use case2 to keep last 5 versions?
Use case 3.
$file.versions.count is not displaying the correct count. Its showing one less than the actual count. In the above screenshot there are 11 versions but $file.versions.count is showing 10. Can you please help?
Yes, That’s right! Because the current version of the file is not actually considered as a “Version”.
This would be a huge help – but I’m getting an error. When I merge this script with the Do/While for large lists I am receiving an error Error deleting versions! Cannot find an overload for “Load” and the argument count: “1”. Any suggestions?
Hello. Thank you for this, it has helped enormously. I have some libraries that exceed the 5000 file limit and am unsure how to integrate the batch process into Case 2. Is that something you could help with please? Thanks
Hi Steve,
You can either batch process the list items (SharePoint Online: How to Get List Items from Large Lists ( >5000 Items) using PowerShell) or use PnP PowerShell script in my another post: SharePoint Online: Delete Version History using PnP PowerShell
Can you please share the script to keep top 5 versions and delete all else, to run it in PowerShell usinf PnP ?
Here you go: How to Delete Version History in SharePoint Online using PnP PowerShell?
I am getting an Error that I do not know how to fix……..could someone help: — Error deleting versions! Exception calling “ExecuteQuery” with “0” argument(s): “Cannot invoke method or retrieve property from null object. Object returned by the following call stack is null. “File
Script has been updated in CAML query to skip Folder objects. Try now!
Hello I’ve got the same error with ExecuteQuery. Any idea how to fix it ?
Salaudeen, Thanks for your quick. This is very helpful but I think many of us need help as our users keep adding files to multiple folders. Is possible to add a script targeting a specific folder and set it up as part of the variables. I believer We have admins here with multiple folders as me with more than 1000 items and set up to 2 or 3 versions that we are trying to keep “LEAN”……..if Possible We will Appreciate the help.
Simple! Just append this line after line#25 in the case 3:
$Query.FolderServerRelativeUrl=”/Project Docs/Active” (or whatever sub-folder path)
This comment has been removed by the author.
Does Case 2 cover all files in all folders? and is it possible to have it filtered to limit rows to 5000 on large sites ?
Thanks !
For large lists with > 5000 list items, You have to process them in batch as in PowerShell to Delete All Items from SharePoint Online List
Thanks. Nice Article
Hi Salaudeen,
These are really great and helpful scripts.
I’m using the script to delete all but 5 versions for all files in a library, but the script fails if the library has any sub-folders. Any ideas what could be added so that the sub-folders are ignored? Thanks!
We’ve to use CAML query to filter Folder Objects. Refer Case #2