Problem Statement
If a document library has a large number of documents and each document has too many versions, then one day, the content database will reach its maximum limit and have a space issue, preventing the addition of any new records/documents in the site. This scenario is valid for SP 2007 and SP2010 as there is no Shredded Storage feature before SP2013 versions.
Solution
As we all know, every version of the document takes a space in the content database so if we have many versions of documents, then every version will have a separate memory allocated in the content database. What we can do in this kind of case is, we can remove all the versions of the document except the latest one and we can have a multi-line field in the document library (let’s say ‘Notes’) which will have all the version history for all the versions filled in it.
Most of the time, these kinds of issues occur in production and there are not many free tools available for this. Also, customers will not allow you to install anything on the production server due to several reasons. Therefore, I came up with the below PowerShell script to achieve the goal.
Please find the PowerShell script attached with this blog. Do let me know if you need any help with respect to the script. I will be glad to help you.
- ##############################################################################################################################
- ## Developed By- Sandeep Kumar
- ## Purpose - Powershell script to be used to retain only the lates verison of file and put version history in Notes Column.
- ##############################################################################################################################
-
- if(!(Get-PSSnapin Microsoft.SharePoint.PowerShell -ea 0))
- {
- Write-Progress -Activity "Loading Modules" -Status "Loading Microsoft.SharePoint.PowerShell"
- Add-PSSnapin Microsoft.SharePoint.PowerShell
- }
-
- #Custom Function to get the version history for the document.
- function GetVersionHistory([Microsoft.SharePoint.SPListItem]$item)
- {
- $versions = $item.Versions
- $versionStr = "$($item["Title"])`n"
- $fldStr = ""
- for($i = 0; $i -lt $versions.Count; $i++)
- {
- $currentVersion = $versions[$i]
- $checkInComment = $item.File.Versions[$item.File.Versions.Count - $i].CheckInComment
- if($i -eq 0)
- {
- $fileSize = $item.File.Length
- }
- else
- {
- $fileSize = $item.File.Versions[$item.File.Versions.Count - $i].Size
- }
- if($fileSize -lt 1MB)
- {
- $fileSize = "{0:N1}" -f ($fileSize / 1KB) + " KB"
- }
- else
- {
- $fileSize = "{0:N1}" -f ($fileSize / 1MB) + " MB"
- }
- $modifiedTime = $web.RegionalSettings.TimeZone.UTCToLocalTime($currentVersion.Created)
- # CSV formatting: escape double quotes allow quotations, new line and commas within cell. Do not use space between comma and double quote escapes due to csv formating.
- $versionStr += ",$($currentVersion.VersionLabel),$($modifiedTime),""$($currentVersion.CreatedBy.User.DisplayName)"",""$($fileSize)"",""$($checkInComment)"",`n"
- $fldStr += "<b>Version: $($currentVersion.VersionLabel)</b></br> Modified time: $($modifiedTime) </br> Created By: ""$($currentVersion.CreatedBy.User.DisplayName)""</br> File Size:""$($fileSize)""</br> Comment:""$($checkInComment)"",</br>"
- if($i -lt ($versions.Count - 1))
- {
- # If more than one version:
- $previousVersion = $versions[$i+1]
- foreach($field in $currentVersion.Fields)
- {
- if(($field.ShowInVersionHistory -eq $true) -and ($currentVersion[$field.Title] -ne $previousVersion[$field.Title]) -and ($currentVersion[$field.Title] -ne "<div></div>"))
- {
- $fieldStr = GetFieldValue $field $currentVersion
- $versionStr +=",,""$fieldStr""`n"
- $fldStr +="""$fieldStr""</br>"
- }
- }
- }
- else
- {
- # If first version:
- foreach($field in $currentVersion.Fields)
- {
- if(($field.ShowInVersionHistory -eq $true) -and ($currentVersion[$field.Title] -ne "<div></div>"))
- {
- $fieldStr = GetFieldValue $field $currentVersion
- $versionStr +=",,""$fieldStr""`n"
- $fldStr +="""$fieldStr""</br>"
- }
- }
- }
- }
- return $fldStr
- }
-
- #Custom Function to get the value of different field types like lookup, User etc.
- function GetFieldValue([Microsoft.SharePoint.SPField]$field, [Microsoft.SharePoint.SPListItemVersion]$currentVersion)
- {
- if(($field.Type -eq "User") -and ($currentVersion[$field.Title] -ne $null))
- {
- $newUser = [Microsoft.SharePoint.SPFieldUser]$field;
- $fieldStr = $newUser.GetFieldValueAsText($currentVersion[$field.Title])
- $fieldStr = "$($field.Title): $fieldStr"
- }
- elseif(($field.Type -eq "Lookup") -and ($currentVersion[$field.Title] -ne $null))
- {
- $newLookup = [Microsoft.SharePoint.SPFieldLookup]$field;
- $fieldStr = $newLookup.GetFieldValueAsText($currentVersion[$field.Title])
- $fieldStr = "$($field.Title): $fieldStr"
- }
- elseif(($field.Type -eq "ModStat") -and ($currentVersion[$field.Title] -ne $null))
- {
- $newModStat = [Microsoft.SharePoint.SPFieldModStat]$field;
- $fieldStr = $newModStat.GetFieldValueAsText($currentVersion[$field.Title])
- $fieldStr = "$($field.Title): $fieldStr"
- }
- else
- {
- $fieldStr = "$($field.Title): $($currentVersion[$field.Title])"
- }
- return $fieldStr
- }
-
- #Custom Function to Copy Files from Source Folder to Target
- Function Copy-Files($SourceFolder, $TargetFolder)
- {
- write-host "Copying Files from:$($SourceFolder.URL) to $($TargetFolder.URL)"
- #Get Each File from the Source
- $SourceFilesColl = $SourceFolder.Files
-
- #Iterate through each item from the source
- Foreach($SourceFile in $SourceFilesColl)
- {
- #Copy File from the Source
- $NewFile = $TargetFolder.Files.Add($SourceFile.Name, $SourceFile.OpenBinary(),$True)
-
- #Copy Meta-Data from Source
- Foreach($Field in $SourceFile.Item.Fields)
- {
- If(!$Field.ReadOnlyField)
- {
- if($NewFile.Item.Fields.ContainsField($Field.InternalName))
- {
- $NewFile.Item[$Field.InternalName] = $SourceFile.Item[$Field.InternalName]
- }
- }
- }
- $NewFile.Item['File Version History'] = GetVersionHistory $SourceFile.Item
- #Update
- $NewFile.Item.UpdateOverwriteVersion()
-
- Write-host "Copied File:"$SourceFile.Name
- }
-
- #Process SubFolders
- Foreach($SubFolder in $SourceFolder.SubFolders)
- {
- if($SubFolder.Name -ne "Forms")
- {
- #Check if Sub-Folder exists in the Target Library!
- $NewTargetFolder = $TargetFolder.ParentWeb.GetFolder($SubFolder.Name)
-
- if ($NewTargetFolder.Exists -eq $false)
- {
- #Create a Folder
- $NewTargetFolder = $TargetFolder.SubFolders.Add($SubFolder.Name)
- }
- #Call the function recursively
- Copy-Files $SubFolder $NewTargetFolder
- }
- }
- }
-
- #Variables for Processing
- $WebURL="http://xxxxxxxxxxxxxxxxxxxxxxxxx/sites/SPTesting/"
- $SourceLibrary ="Source Library"
- $TargetLibrary = "Destination Library"
-
- #Get Objects
- $web = Get-SPWeb $WebURL
- $SourceFolder = $web.GetFolder($SourceLibrary)
- $TargetFolder = $web.GetFolder($TargetLibrary)
-
- #Call the Function to Copy All Files
- Copy-Files $SourceFolder $TargetFolder