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.

  1. ##############################################################################################################################
  2. ## Developed By- Sandeep Kumar
  3. ## Purpose - Powershell script to be used to retain only the lates verison of file and put version history in Notes Column.
  4. ##############################################################################################################################
  5. if(!(Get-PSSnapin Microsoft.SharePoint.PowerShell -ea 0))
  6. {
  7. Write-Progress -Activity "Loading Modules" -Status "Loading Microsoft.SharePoint.PowerShell"
  8. Add-PSSnapin Microsoft.SharePoint.PowerShell
  9. }
  10. #Custom Function to get the version history for the document.
  11. function GetVersionHistory([Microsoft.SharePoint.SPListItem]$item)
  12. {
  13. $versions = $item.Versions
  14. $versionStr = "$($item["Title"])`n"
  15. $fldStr = ""
  16. for($i = 0; $i -lt $versions.Count; $i++)
  17. {
  18. $currentVersion = $versions[$i]
  19. $checkInComment = $item.File.Versions[$item.File.Versions.Count - $i].CheckInComment
  20. if($i -eq 0)
  21. {
  22. $fileSize = $item.File.Length
  23. }
  24. else
  25. {
  26. $fileSize = $item.File.Versions[$item.File.Versions.Count - $i].Size
  27. }
  28. if($fileSize -lt 1MB)
  29. {
  30. $fileSize = "{0:N1}" -f ($fileSize / 1KB) + " KB"
  31. }
  32. else
  33. {
  34. $fileSize = "{0:N1}" -f ($fileSize / 1MB) + " MB"
  35. }
  36. $modifiedTime = $web.RegionalSettings.TimeZone.UTCToLocalTime($currentVersion.Created)
  37. # 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.
  38. $versionStr += ",$($currentVersion.VersionLabel),$($modifiedTime),""$($currentVersion.CreatedBy.User.DisplayName)"",""$($fileSize)"",""$($checkInComment)"",`n"
  39. $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>"
  40. if($i -lt ($versions.Count - 1))
  41. {
  42. # If more than one version:
  43. $previousVersion = $versions[$i+1]
  44. foreach($field in $currentVersion.Fields)
  45. {
  46. if(($field.ShowInVersionHistory -eq $true) -and ($currentVersion[$field.Title] -ne $previousVersion[$field.Title]) -and ($currentVersion[$field.Title] -ne "<div></div>"))
  47. {
  48. $fieldStr = GetFieldValue $field $currentVersion
  49. $versionStr +=",,""$fieldStr""`n"
  50. $fldStr +="""$fieldStr""</br>"
  51. }
  52. }
  53. }
  54. else
  55. {
  56. # If first version:
  57. foreach($field in $currentVersion.Fields)
  58. {
  59. if(($field.ShowInVersionHistory -eq $true) -and ($currentVersion[$field.Title] -ne "<div></div>"))
  60. {
  61. $fieldStr = GetFieldValue $field $currentVersion
  62. $versionStr +=",,""$fieldStr""`n"
  63. $fldStr +="""$fieldStr""</br>"
  64. }
  65. }
  66. }
  67. }
  68. return $fldStr
  69. }
  70. #Custom Function to get the value of different field types like lookup, User etc.
  71. function GetFieldValue([Microsoft.SharePoint.SPField]$field, [Microsoft.SharePoint.SPListItemVersion]$currentVersion)
  72. {
  73. if(($field.Type -eq "User") -and ($currentVersion[$field.Title] -ne $null))
  74. {
  75. $newUser = [Microsoft.SharePoint.SPFieldUser]$field;
  76. $fieldStr = $newUser.GetFieldValueAsText($currentVersion[$field.Title])
  77. $fieldStr = "$($field.Title): $fieldStr"
  78. }
  79. elseif(($field.Type -eq "Lookup") -and ($currentVersion[$field.Title] -ne $null))
  80. {
  81. $newLookup = [Microsoft.SharePoint.SPFieldLookup]$field;
  82. $fieldStr = $newLookup.GetFieldValueAsText($currentVersion[$field.Title])
  83. $fieldStr = "$($field.Title): $fieldStr"
  84. }
  85. elseif(($field.Type -eq "ModStat") -and ($currentVersion[$field.Title] -ne $null))
  86. {
  87. $newModStat = [Microsoft.SharePoint.SPFieldModStat]$field;
  88. $fieldStr = $newModStat.GetFieldValueAsText($currentVersion[$field.Title])
  89. $fieldStr = "$($field.Title): $fieldStr"
  90. }
  91. else
  92. {
  93. $fieldStr = "$($field.Title): $($currentVersion[$field.Title])"
  94. }
  95. return $fieldStr
  96. }
  97. #Custom Function to Copy Files from Source Folder to Target
  98. Function Copy-Files($SourceFolder, $TargetFolder)
  99. {
  100. write-host "Copying Files from:$($SourceFolder.URL) to $($TargetFolder.URL)"
  101. #Get Each File from the Source
  102. $SourceFilesColl = $SourceFolder.Files
  103. #Iterate through each item from the source
  104. Foreach($SourceFile in $SourceFilesColl)
  105. {
  106. #Copy File from the Source
  107. $NewFile = $TargetFolder.Files.Add($SourceFile.Name, $SourceFile.OpenBinary(),$True)
  108. #Copy Meta-Data from Source
  109. Foreach($Field in $SourceFile.Item.Fields)
  110. {
  111. If(!$Field.ReadOnlyField)
  112. {
  113. if($NewFile.Item.Fields.ContainsField($Field.InternalName))
  114. {
  115. $NewFile.Item[$Field.InternalName] = $SourceFile.Item[$Field.InternalName]
  116. }
  117. }
  118. }
  119. $NewFile.Item['File Version History'] = GetVersionHistory $SourceFile.Item
  120. #Update
  121. $NewFile.Item.UpdateOverwriteVersion()
  122. Write-host "Copied File:"$SourceFile.Name
  123. }
  124. #Process SubFolders
  125. Foreach($SubFolder in $SourceFolder.SubFolders)
  126. {
  127. if($SubFolder.Name -ne "Forms")
  128. {
  129. #Check if Sub-Folder exists in the Target Library!
  130. $NewTargetFolder = $TargetFolder.ParentWeb.GetFolder($SubFolder.Name)
  131. if ($NewTargetFolder.Exists -eq $false)
  132. {
  133. #Create a Folder
  134. $NewTargetFolder = $TargetFolder.SubFolders.Add($SubFolder.Name)
  135. }
  136. #Call the function recursively
  137. Copy-Files $SubFolder $NewTargetFolder
  138. }
  139. }
  140. }
  141. #Variables for Processing
  142. $WebURL="http://xxxxxxxxxxxxxxxxxxxxxxxxx/sites/SPTesting/"
  143. $SourceLibrary ="Source Library"
  144. $TargetLibrary = "Destination Library"
  145. #Get Objects
  146. $web = Get-SPWeb $WebURL
  147. $SourceFolder = $web.GetFolder($SourceLibrary)
  148. $TargetFolder = $web.GetFolder($TargetLibrary)
  149. #Call the Function to Copy All Files
  150. Copy-Files $SourceFolder $TargetFolder