SharePoint · Storage audit

Where your Microsoft 365 storage actually goes: a read-only audit in four layers

Published 22 September 2026 · 9 min read · All figures from Microsoft Learn, linked at the end

The storage bar in the SharePoint admin center gives you one number: used versus total. The renewal conversation needs four: how much of that is live files, how much is version history, how much is deleted-but-not-purged, and how much is compliance copies you cannot touch. None of the four is on the bar. This is how to get all of them without changing anything in the tenant, with the exact commands and reports, and what each bucket is worth once you have it.

Layer 0: the number that bills

Start with the pool, because every other number is only interesting relative to it. The tenant's SharePoint quota is 1 TB plus 10 GB per qualifying licence, plus any Extra File Storage add-on. Microsoft calculates it in binary gigabytes (1 GB = 230 bytes), which matters when you compare against a vendor invoice in decimal. Three things are not in the pool, and people routinely add them in by mistake:

Read it from the SharePoint Online Management Shell, which needs SharePoint Administrator and changes nothing:

Connect-SPOService -Url https://TENANT-admin.sharepoint.com
Get-SPOTenant | Select-Object StorageQuota, StorageQuotaAllocated   # MB

The same figures are on the Active sites page (top right) and under Reports → Usage → SharePoint → Storage in the Microsoft 365 admin center. Two caveats from Microsoft's own docs: the admin center bar lags real usage by 24–48 hours, and the Storage report refreshes every 48–72 hours. If you cleaned something up yesterday and the bar has not moved, that is why. The report also puts a banner up at 80% of quota, which is the point at which most people start this exercise.

Layer 1: which sites

Storage follows a Pareto curve in almost every tenant: a handful of sites hold most of it. Get the per-site list with sizes, quotas, last change, template and archive state in one call:

Get-SPOSite -Limit All -Detailed |
  Select-Object Url, Template, StorageUsageCurrent, StorageQuota,
                LastContentModifiedDate, ArchiveState |
  Sort-Object StorageUsageCurrent -Descending |
  Export-Csv .\sites.csv -NoTypeInformation

StorageUsageCurrent and StorageQuota are in MB. Sites in the recycle bin are not returned, which is correct for this purpose because they are not billed. If you also want OneDrives in the same file, add -IncludePersonalSite $true, but keep them in a separate column in your analysis; they are not in the pool.

The Graph usage report gives you the same list with two columns PowerShell does not: Last Activity Date and Active File Count. Pull reports/getSharePointSiteUsageDetail(period='D180') with Reports.Read.All; it redirects to a CSV with Site URL, Owner, Is Deleted, Last Activity Date, File Count, Active File Count, Storage Used (Byte), Storage Allocated (Byte) and Root Web Template. Note that names are anonymised by default in usage reports; a global or reports admin has to untick Conceal user, group and site names under Org settings → Reports before the CSV shows real URLs.

What you are looking for at this layer:

PatternWhat it usually isLayer 2 check
Top 10 sites hold >60% of the poolNormal. These are the only sites worth auditing in depth.Version report on each
Large site, Last Activity Date > 12 months agoCold departmental data, migrated project, or a departed team's TeamArchive candidate; confirm no retention policy blocks it
Storage used far above what the file count suggestsVersion history or a Preservation Hold libraryStorage metrics page
Template = GROUP#0 or TEAMCHANNEL#1 with recordingsChannel meeting recordings in Documents/RecordingsCheck the expiry policy

Layer 2: inside a site, five buckets

A site's storage figure is the sum of five things. Only the first is what users think of as "our files".

BucketWhat it isCounts toward site storage?
Current filesThe latest version of every file in every libraryYes
Version historyEvery previous version. Each one is a full copy of the file, not a deltaYes
First-stage recycle binWhat users deleted in the last 93 daysYes
Second-stage recycle binWhat was purged from the first stage, until day 93Not in the storage-used metric (subsites are the exception). Capped at 200% of the site quota
Preservation Hold libraryHidden library holding copies of edited or deleted files that a retention policy or hold coversYes

Plus site metadata (file properties, list data, version records), which counts and has its own 1,000 GB per-site limit, though it rarely gets there.

Measuring each bucket, read-only

Storage metrics page. On any site, /_layouts/15/storman.aspx (Site settings → Storage metrics). It lists every library including the hidden Preservation Hold Library with its size, and warns when the site nears the metadata limit. This is the fastest way to see whether a 3 TB site is 3 TB of documents or 800 GB of documents plus 2.2 TB of retained copies. Site collection admin permission is enough.

Version history. Microsoft ships a report job that writes a CSV of every version with its size to a location on the site. It runs asynchronously and deletes nothing:

New-SPOSiteFileVersionExpirationReportJob -Identity https://TENANT.sharepoint.com/sites/finance `
  -ReportUrl "https://TENANT.sharepoint.com/sites/finance/Shared Documents/VersionReport.csv"
Get-SPOSiteFileVersionExpirationReportJobProgress -Identity https://TENANT.sharepoint.com/sites/finance `
  -ReportUrl "https://TENANT.sharepoint.com/sites/finance/Shared Documents/VersionReport.csv"

There is a library-scoped variant (New-SPOListFileVersionExpirationReportJob -Site … -List …) for when one library is the obvious culprit. Sum the size column by library and you know exactly what a trim would reclaim before you queue one. Microsoft's own tutorial pairs this with a "what-if" analysis of different version limits.

Recycle bins. The first-stage bin is visible to any site member; the second-stage bin to site collection admins. Both are on the site's Recycle bin page. For sizes across many sites, the PnP PowerShell community module's Get-PnPRecycleBinItem returns items with sizes per stage; it is not a Microsoft-supported module, so treat it as a convenience, not the system of record.

Preservation Hold library. Its size is on the storage metrics page. Whether it is growing is a Purview question: which retention policies target this site. Get-RetentionCompliancePolicy | Where-Object { $_.SharePointLocation -or $_.OneDriveLocation } in Security & Compliance PowerShell lists them.

Layer 3: what each bucket is worth

This is the part the audit exists for. The same gigabyte means something different depending on which bucket it sits in, because the mechanism that reclaims it is different for each.

BucketReclaim mechanismBlocked byTiming
Version historyVersion-history limits for new versions; a trim job (New-SPOSiteFileVersionBatchDeleteJob) for existing onesRetention policy or eDiscovery hold: the trim stamps an expiration date instead of deleting, and the version stays until the hold liftsTrim runs asynchronously; purge of expired versions can take a couple of days
First-stage recycle binNothing, if you can wait: items are gone at day 93. Emptying it is instant and irreversibleRetention: deleted items under policy went to the Preservation Hold library firstImmediate on empty; storage bar updates in 24–48 h
Preservation Hold libraryOnly a change to the retention policy that fills it. The cleanup job runs every 7 days and skips anything under 30 days old, so up to 37 days after expiryThe policy itself. Version trimming never touches itWeeks
Cold sites (no activity 12+ months)Microsoft 365 Archive: the site leaves the active pool and bills at $0.05/GB/month list instead of $0.20/GB/month for add-on storage above the poolHolds still apply; readers can reactivateArchived storage stops counting toward the active quota; bar updates in up to 48 h
Channel meeting recordingsTeams recording expiry policy (default 120 days, then recycle bin). Applies to new recordings onlyRecordings moved out of their original folder lose the expiry stampPer policy

Two things people expect to be on this list are not. Meeting recordings for ordinary (non-channel) meetings land in the organiser's OneDrive, which is outside the pool; they are a OneDrive quota problem, not a SharePoint one. And departed users' OneDrives are on the unlicensed-account lifecycle and its own $0.05/GB meter, which we covered separately. Both belong in the same audit, but in a different column.

Worked example

Hypothetical tenant, 300 qualifying licences. Pool = 1 TB + 300 × 10 GB ≈ 3.9 TB. Active sites bar shows 5.3 TB used, so roughly 1.4 TB above the pool, which on the pay-as-you-go SharePoint Storage meter at $0.20/GB list is about $280/month if nothing changes. The four layers turn that into a decision:

Layer 3 then says: archive the three cold sites (1.6 TB off the active pool, about $80/month on the archive meter instead of counting against it), trim versions on the two design libraries after confirming no hold covers them (700 GB back), and leave the bins and the PHL alone. That takes the tenant from 1.4 TB over to roughly 1 TB under the pool, and the add-on purchase that was on the renewal agenda comes off it. The 400 GB of retained copies stays, but now it is a known, defensible number rather than a mystery inside "finance is 1.8 TB".

Checklist

  1. Get-SPOTenant: quota and allocated. Write both down with the date; the bar lags.
  2. Get-SPOSite -Limit All -Detailed to CSV; sort by StorageUsageCurrent. Take the top ten.
  3. Graph getSharePointSiteUsageDetail('D180') for Last Activity Date on the same sites. Anything over 12 months with no hold is an archive candidate.
  4. Storage metrics page on each of the top ten: split into files, Preservation Hold library, recycle bin.
  5. Version expiration report job on each of the top ten. Sum by library.
  6. Get-RetentionCompliancePolicy so you know which sites are hold-bound before proposing any trim.
  7. Present four numbers, not one: live, versions, bins, retained. Each has a different owner and a different lever.

Free: pool position, top sites and departed-user OneDrives in one run

StorageScout Lite is a read-only PowerShell audit that does Layer 0 and Layer 1 for you and exports every departed-user OneDrive with its size. No server, nothing leaves your tenant. The paid tiers add the Layer 2 breakdown per site, dollar-quantified against the meters above.

Download StorageScout Lite — free See what Solo adds

Disclosure: StorageScout is our product. Prices are Microsoft's public US list prices as documented on Microsoft Learn at the time of writing; your agreement, region and currency may differ. The worked example is hypothetical. StorageScout is independent and not affiliated with or endorsed by Microsoft.

Sources