SharePoint : Your storage is almost full - one approach

Steel Contributor

I've been looking for low impact ways to minimize our storage usage across our SharePoint tenant.

This post outlines the approach I took and the outcome, and who it might work for.


My environment:

Only 350GB remaining in Tenancy 8.7 TB used.
265 sharepoint sites in total (teams / communication etc)


I decided to focus on sites with more than 100Gb of storage used. In my case this turned up 
16 sites. Of these I had to exclude 2 sites.
This left 14 sites using 5.194553 TB


My goal was to have low/no impact on users while reducing the volume of content in our M365 tenant SharePoint environment.

My approach was to do the following:
- Get list of all SharePoint site collections, find out Size of each
Those larger than 100Gb do the following:
- delete all items in recycle bin deleted more than 30 days ago (current setting 93 days, unchanged)
- delete all items from 2nd stage recycle bin (current setting 30 days, unchanged)
- change all user libraries from 500 to 100 major versions


In my environment the recycle bins are rarely used and when I ran a script to work out the average number of versions it was in the 10s at most and for most sites it was 3 or 4.

NOTE no sites have minor versioning turned on.


I wanted to measure the change so I exported a usage report pre and post doing the above. To achieve all this I used the following code, then the following day checked the SharePoint admin centre reported the same "Storage used" numbers.


BE AWARE the code below DELETES data you cannot get back (file versions, and files in the recycle bin). DO NOT RUN THIS to try it out. Test it on one or two sites first. Even if you have backups getting version history back would be very challenging.



<# goal is to reduce size sites take up

1 change version from 500 to 100

2 recycle bin deleted more than 30 days ago, move to 2nd stage recycling

3 empty second stage recycling


#Get current stats

#Connect to Admin Center   

$AdminCenterURL = ""

Connect-PnPOnline -Url $AdminCenterURL -Interactive 


function reportTenantSiteCollectioninfo 
		Try {
			#export file path 
			$dateStamp = get-date -format "yyyyMMdd-hhmm"

			$CSVPath = "c:\Temp\SiteUsageRpt-"+$dateStamp+".csv"

			#Get all site usage details
			$Sites = Get-PnPTenantSite  -Detailed | Select *
			$SiteUsageData = @()
			ForEach ($Site in $Sites)
				#Collect site data
				$SiteUsageData += New-Object PSObject -Property ([ordered]@{               
						'Title'                    = $Site.Title
						'URL'                      = $Site.Url
						'Description'              = $Site.Description                    
						'Owner'                    = $Site.OwnerName
						'Storage Quota'            = $Site.StorageQuota
						'Storage MaximumLevel'     = $Site.StorageMaximumLevel 
						'Storage Usage Current'    = $Site.StorageUsageCurrent
						'Resource Quota'           = $Site.ResourceQuota
						'Resource Quota Warning'   = $Site.ResourceQuotaWarningLevel
						'Resource Usage Average'   = $Site.ResourceUsageAverage
						'Resource Usage Current'   = $Site.ResourceUsageCurrent
						'Template'                 = $Site.Template
						'Sharing Capability'       = $Site.SharingCapability
						'Lock Status'              = $Site.LockState
						'Last Modified Date'       = $Site.LastContentModifiedDate
						'Subsites Count'           = $Site.WebsCount
			#Export Site Usage Data to CSV
			$SiteUsageData | Export-Csv $CSVPath -NoTypeInformation
			Write-Host "Site Usage Report Generated Successfully!" -ForegroundColor Green
		Catch {
			Write-Host -ForegroundColor Red "Error generating site usage report:" $_.Exception.Message

Function Set-PnPVersionHistoryLimit
        [Parameter(Mandatory=$true)] $Web,
        [parameter(Mandatory=$false)][int]$VersioningLimit = 100
    Try {
        Write-host "Processing Web:"$Web.URL -f Yellow
        Connect-PnPOnline -Url $Web.URL -Interactive
        #Array to exclude system libraries
        $SystemLibraries = @("Form Templates", "Pages", "Preservation Hold Library","Site Assets", "Site Pages", "Images",
                            "Site Collection Documents", "Site Collection Images","Style Library","Teams Wiki Data")
        $Lists = Get-PnPList -Includes BaseType, Hidden, EnableVersioning
        #Get All document libraries
        $DocumentLibraries = $Lists | Where {$_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $False -and $_.Title -notin $SystemLibraries}
        #Set Versioning Limits
        ForEach($Library in $DocumentLibraries)
            #powershell to set limit on version history
                #Set versioning limit
                Set-PnPList -Identity $Library -MajorVersions $VersioningLimit
                Write-host -f Green "`tVersion History Settings has been Updated on '$($Library.Title)'"
                Write-host -f Yellow "`tVersion History is turned-off at '$($Library.Title)'"
    Catch {
        Write-host -f Red "Error:" $_.Exception.Message


Get a list of big sites 

$bigSites = $SiteUsageData | where "Storage Usage Current" -gt 100000

$bigSites = $bigSites | where title -notin ("excluded site 1","excluded site 2")

#loop through the big sites

foreach($bigsite in $bigSites) {

	connect-pnponline -url $bigSite.URL -interactive
	## get the deleted items that were deleteed more than 30 days ago

	$date30daysago = (get-date).adddays(-30)

	$DeletedItemsOlder = Get-PnPRecycleBinItem | Where { $_.DeletedDate -le $date30daysago} | Sort-Object -Property DeletedDate -Descending

	#move all these to 2nd stage recycle bin
	$DeletedItemsOlder | Move-PnPRecycleBinItem -force

	#empty the second stage recycle bin
	Clear-PnPRecycleBinItem -SecondStageOnly -force
	#get all the libraries
	$Webs = Get-PnPSubWeb -Recurse -IncludeRootWeb
		ForEach($Web in $Webs)
			Set-PnPVersionHistoryLimit -Web $Web


#get site info again





[Updated 7 Aug 2023] On the day the outcome was spectacularly unsuccessful.

I saved 24GB by doing this across 5.194553 Terra bytes or less than 0.5 %
So worth trying, but not valuable in my environment, I thought.

But when I looked at the SharePoint admin screen, Storage used, in August there is a big drop two days after running this script. From 8.8TB down to 8.6TB so approx 200GB saving. Unfortunately this may not have been all to do with this script (other things going on in my tenant) but a lot of it is, again not massive at 2% but useful.


When would this be valuable for reducing storage volume ? I think the key thing isn't the removal of files from the recycle bins, but the removal of older versions of files. SO if you have an environment with most files having 100's of versions , and those versions are large changes to the file each time. (e.g. a daily report that has new images replace existing ones each day) then this could save a lot of space.


What about you?

How do you reduce SharePoint storage? What have you found that works?


0 Replies