How much storage can I save by limiting versioning in SharePoint?

Today is a really short blogpost just so I can publish a script I have created that makes a report of alle files in SharePoint that has versioning, to show how much storage the use, and how much storage you can save by limiting the number of major versions. If you still allow 500 major versions, you can in the script set 20 as the new limit, to see how much you save. The script is only for reporting purposes, and I will most likely at a later time create a script for purging/removing old versions.

To run the script, you will need an app registration with the following application rights:
Directory.Read.All, Files.Read.All and Sites.Read.All


If you want more in dept info around SharePoint versioning, take a look at Nikki Chapple´s great blogpost on the topic.

# Parameters for the app registration
$ClientId = "xxxxx"
$TenantId = "xxxxx"
$ClientSecret = "xxxxx"
$NumberOfMajorVersionsToKeep = 20
$TotalSizeAllVersions = 0
$TotalSizeReducedVersions = 0
# Convert the Client Secret to a SecureString
$SecureClientSecret = ConvertTo-SecureString -String $ClientSecret -AsPlainText -Force
# Create a PSCredential object with the Client ID and Secure Client Secret
$ClientSecretCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ClientId, $SecureClientSecret
# Connect to Microsoft Graph using the Tenant ID and Client Secret Credential
Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $ClientSecretCredential
# Initialize the output array
$OutputData = @()
function Get-AllDriveItems {
param (
[Parameter(Mandatory)]
[string]$DriveId,
[Parameter()]
[string]$ParentId,
[Parameter()]
[string]$CurrentPath = ""
)
$Items = @()
if ($ParentId) {
Write-Host "Processing folder with ParentId: $ParentId" -ForegroundColor Cyan
try {
$ParentItem = Get-MgDriveItem -DriveId $DriveId -DriveItemId $ParentId -ExpandProperty 'children' -ErrorAction Stop
$DriveItems = $ParentItem.Children
if($DriveItems) {
Write-Host "Found $($DriveItems.Count) child items in folder '$($ParentItem.Name)' (ParentId: $ParentId)" -ForegroundColor Green
} else {
Write-Host "No child items found in folder '$($ParentItem.Name)' (ParentId: $ParentId)" -ForegroundColor Yellow
}
} catch {
Write-Warning "Failed to get children for item ID '$ParentId'. Error: $_"
return $Items
}
} else {
Write-Host "Processing root folder" -ForegroundColor Cyan
try {
$RootItem = Get-MgDriveRoot -DriveId $DriveId -ExpandProperty 'children' -ErrorAction Stop
$DriveItems = $RootItem.Children
if($DriveItems) {
Write-Host "Found $($DriveItems.Count) items in root folder" -ForegroundColor Green
} else {
Write-Host "No items found in root folder" -ForegroundColor Yellow
}
} catch {
Write-Error "Failed to get root item and its children. Error: $_"
return $Items
}
}
if (-not $DriveItems) {
Write-Verbose "No items found at this level."
return $Items
}
foreach ($Item in $DriveItems) {
# Update the file path
if ($CurrentPath -eq "") {
$ItemPath = "/$($Item.Name)"
} else {
$ItemPath = "$CurrentPath/$($Item.Name)"
}
# Add the ItemPath property to the item
$Item | Add-Member -NotePropertyName 'ItemPath' -NotePropertyValue $ItemPath
$Items += $Item
Write-Host "Found item: $($Item.Name) (Id: $($Item.Id))" -ForegroundColor Green
if ($Item.Folder) {
Write-Host "Recursing into folder: $($Item.Name) (Id: $($Item.Id))" -ForegroundColor Cyan
if ($Item.Id) {
$Items += Get-AllDriveItems -DriveId $DriveId -ParentId $Item.Id -CurrentPath $ItemPath
} else {
Write-Warning "Item '$($Item.Name)' has a null ID and cannot be processed."
}
}
}
return $Items
}
# Now, process all SharePoint sites and their document libraries
Write-Host "Starting to process all SharePoint sites and their document libraries..." -ForegroundColor Magenta
try {
# Retrieve all SharePoint sites
$sites = Get-MgSite -All | Where-Object { $_.WebUrl -notlike "*personal*" }
} catch {
Write-Error "Failed to retrieve SharePoint sites. Error: $_"
exit
}
foreach ($site in $sites) {
try {
Write-Host "Processing site: $($site.DisplayName) <$($site.WebUrl)>" -ForegroundColor Magenta
# Get all document libraries (drives) in the site
$drives = Get-MgSiteDrive -SiteId $site.Id -ErrorAction Stop
foreach ($drive in $drives) {
Write-Host "Processing document library: $($drive.Name)" -ForegroundColor Cyan
$driveId = $drive.Id
# Get all items in the document library starting from the root
$AllItems = Get-AllDriveItems -DriveId $driveId
Write-Host "Total items retrieved in document library '$($drive.Name)': $($AllItems.Count)" -ForegroundColor Green
foreach ($Item in $AllItems) {
Write-Host "Processing item: $($Item.Name) (Id: $($Item.Id))" -ForegroundColor Gray
# Check if item is a file
if ($Item.File) {
try {
# Get versions for the item
$Versions = @()
$Versions = Get-MgDriveItemVersion -DriveId $driveId -DriveItemId $Item.Id -All -ErrorAction Stop
} catch {
Write-Warning "Failed to get versions for item '$($Item.Name)'. Error: $_"
continue
}
if (!$Versions) {
Write-Host "No versions found for item '$($Item.Name)'" -ForegroundColor Yellow
$MajorVersionCount = 0
$MinorVersionCount = 0
} else {
Write-Host "Found $($Versions.Count) versions for item '$($Item.Name)'" -ForegroundColor Green
$MajorVersionCount = 0
$MinorVersionCount = 0
$TotalVersionSize = 0
$LastversionSize = 0
$LastversionSize = ($Versions | Sort-Object -Descending -Property TotalSizeReduced)[0].Size
If($Versions){
foreach ($Version in $Versions) {
$TotalVersionSize += $Version.Size
if ($Version.id -like "*.0") {
$MajorVersionCount++
}
else {
$MinorVersionCount++
}
}
}
$TotalSizeReduced = 0
$ReducedMajorVersionCount = 0
$ReducedMinorVersionCount = 0
$ReducedMajorVersions = $Versions | Where-Object {$_.id -like "*.0"} | Sort-Object -Property LastModifiedDateTime -Descending | Select-Object -First $NumberOfMajorVersionsToKeep
foreach ($ReducedMajorVersion in $ReducedMajorVersions){
$VersionNumber = @()
$VersionNumber = ($ReducedMajorVersion.id).split(".")[0]
$Versions = $Versions | Where-Object {$_.id -like "$VersionNumber.*"}
foreach ($Version in $Versions) {
$TotalSizeReduced += $Version.Size
if ($Version.id -like "*.0") {
$ReducedMajorVersionCount++
}
else {
$ReducedMinorVersionCount++
}
}
}
# Create a custom object with the desired properties
$OutputObject = [PSCustomObject]@{
SiteUrl = $site.WebUrl
SiteName = $site.DisplayName
DocumentLibrary = $drive.Name
ItemName = $Item.Name
ItemUrl = $Item.WebUrl
FilePath = $Item.ItemPath
LastVersionSizeMB = $LastversionSize/1MB
TotalSizeMB = $TotalVersionSize/1MB
TotalSizeReducedMB = $TotalSizeReduced/1MB
MajorVersionCount = $MajorVersionCount
MinorVersionCount = $MinorVersionCount
ReducedMajorVersionCount = $ReducedMajorVersionCount
ReducedMinorVersionCount = $ReducedMinorVersionCount
}
$TotalSizeAllVersions += $TotalVersionSize
$TotalSizeReducedVersions += $TotalSizeReduced
# Add the object to the output array
$OutputData += $OutputObject
}
}
}
}
} catch {
Write-Warning "Failed to process site $($site.DisplayName). Error: $_"
continue
}
}
# Output or process the collected data as needed
# For example, output to console
#$OutputData
"Before: " + $TotalSizeAllVersions/1GB
"After: " + $TotalSizeReducedVersions/1GB
# Optionally, export to CSV
# $OutputData | Export-Csv -Path 'C:\Path\To\Output.csv' -NoTypeInformation

Leave a comment