Free script · PowerShell

SharePoint site storage and library version settings report

List every SharePoint site with its storage used, plus each document library's versioning settings and major version limit, in one CSV. Use it to decide how many versions to migrate and which libraries will take longest.

PowerShellRead-onlyUpdated
Read-only: makes no changes
Before you run it

What you need

Admin roles

  • SharePoint Administrator (to list all sites from the admin URL)
  • Read access to each site you want to report on (a SharePoint Administrator is not automatically a member of every site)

Runs on

  • PowerShell 7.4 or later on Windows, macOS or Linux (PnP.PowerShell 3.x requirement)
Parameters

Options you can set

ParameterWhat it does
-AdminUrlRequired. Your SharePoint admin URL, for example https://contoso-admin.sharepoint.com.
-ClientIdRequired. The Application (client) ID of your PnP app registration in Entra ID.
-SiteUrlFilterOptional. Only report sites whose URL contains this text, for example /sites/finance. Default: all sites.
-IncludeHiddenListsOptional switch. Also report hidden document libraries.
-OutputPathOptional. Where to save the CSV. Default: SharePointVersionReport_yyyyMMdd_HHmm.csv in the current folder.
How to run it

Step by step

  1. 1

    Step 1

    Install PowerShell 7.4 or later, then open it and run Install-Module PnP.PowerShell -Scope CurrentUser.

  2. 2

    Step 2

    If your organisation does not already have a PnP app registration, have an admin who can register apps and grant admin consent in Entra ID run Register-PnPEntraIDAppForInteractiveLogin -ApplicationName "PnP PowerShell" -Tenant contoso.onmicrosoft.com and note the client ID it returns.

  3. 3

    Step 3

    Save the script as Get-CMSharePointVersionReport.ps1 in a working folder.

  4. 4

    Step 4

    Run ./Get-CMSharePointVersionReport.ps1 -AdminUrl https://contoso-admin.sharepoint.com -ClientId 00000000-0000-0000-0000-000000000000 and sign in. You may be asked to sign in again for some sites.

  5. 5

    Step 5

    Open the CSV. Sort by MajorVersionLimit and SiteStorageUsageCurrent to find the libraries that will carry the most version history.

What you get: A UTF-8 CSV with one row per document library: SiteUrl, SiteTitle, SiteTemplate, SiteStorageUsageCurrent, SiteStorageQuota, LibraryTitle, LibraryUrl, ItemCount, EnableVersioning, MajorVersionLimit, EnableMinorVersions, MajorWithMinorVersionsLimit and Error. A site that cannot be opened gets one row with the Error column filled.

The script

Get-CMSharePointVersionReport.ps1

<#
.SYNOPSIS
    Get-CMSharePointVersionReport.ps1

.DESCRIPTION
    Reports storage used per SharePoint site and the versioning settings of every
    document library (versioning on or off, major version limit, minor versions).
    Read-only: it changes nothing in your tenant.

    Why PnP.PowerShell: SharePoint Online Management Shell (Get-SPOSite) reports site
    storage, but it has no cmdlet that lists the document libraries in a site.
    PnP.PowerShell's Get-PnPList does, so this script uses PnP for both parts.

    Provided by cloud-migrations.au as is; test before use.
    Read the script before you run it and try it in a test tenant first.

.NOTES
    Requirements
      - PowerShell 7.4 or later (required by PnP.PowerShell 3.x)
      - Install-Module PnP.PowerShell -Scope CurrentUser
      - An Entra ID app registration for PnP (Register-PnPEntraIDAppForInteractiveLogin)
      - SharePoint Administrator, plus read access to the sites you report on
    Commands used (documented by the PnP PowerShell project):
      Connect-PnPOnline -Url -Interactive -ClientId, Get-PnPTenantSite, Get-PnPList -Includes
    List properties (EnableVersioning, MajorVersionLimit, EnableMinorVersions,
    MajorWithMinorVersionsLimit, BaseTemplate, Hidden) are SharePoint List properties
    documented by Microsoft. BaseTemplate 101 is a document library.

.EXAMPLE
    ./Get-CMSharePointVersionReport.ps1 -AdminUrl https://contoso-admin.sharepoint.com -ClientId 00000000-0000-0000-0000-000000000000

.EXAMPLE
    ./Get-CMSharePointVersionReport.ps1 -AdminUrl https://contoso-admin.sharepoint.com -ClientId 00000000-0000-0000-0000-000000000000 -SiteUrlFilter /sites/finance
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)][string]$AdminUrl,
    [Parameter(Mandatory = $true)][string]$ClientId,
    [string]$SiteUrlFilter = '',
    [switch]$IncludeHiddenLists,
    [string]$OutputPath = (Join-Path -Path (Get-Location) -ChildPath ('SharePointVersionReport_{0}.csv' -f (Get-Date -Format 'yyyyMMdd_HHmm')))
)

$ErrorActionPreference = 'Stop'

# Copy the site columns into a new ordered row
function Copy-CMRow {
    param($Source)
    $copy = [ordered]@{}
    foreach ($k in $Source.Keys) { $copy[$k] = $Source[$k] }
    return $copy
}

# 1. Connect to the admin URL and list sites (Get-PnPTenantSite leaves out OneDrive sites by default)
try {
    Write-Host "Connecting to $AdminUrl ..."
    $adminConn = Connect-PnPOnline -Url $AdminUrl -Interactive -ClientId $ClientId -ReturnConnection
    Write-Host 'Reading the list of sites...'
    $sites = @(Get-PnPTenantSite -Connection $adminConn)
}
catch {
    Write-Error "Could not connect or list sites: $($_.Exception.Message)"
    return
}
if ($SiteUrlFilter) { $sites = @($sites | Where-Object { $_.Url -like "*$SiteUrlFilter*" }) }
Write-Host ("Found {0} sites to check." -f $sites.Count)

$results = New-Object System.Collections.Generic.List[object]
$i = 0
foreach ($site in $sites) {
    $i++
    Write-Progress -Activity 'Reading library version settings' -Status ("{0} of {1}: {2}" -f $i, $sites.Count, $site.Url) -PercentComplete (($i / [math]::Max($sites.Count, 1)) * 100)

    $base = [ordered]@{
        SiteUrl                 = $site.Url
        SiteTitle               = $site.Title
        SiteTemplate            = $site.Template
        SiteStorageUsageCurrent = $site.StorageUsageCurrent
        SiteStorageQuota        = $site.StorageQuota
    }

    try {
        $siteConn = Connect-PnPOnline -Url $site.Url -Interactive -ClientId $ClientId -ReturnConnection
        $lists = Get-PnPList -Connection $siteConn -Includes EnableVersioning, MajorVersionLimit, EnableMinorVersions, MajorWithMinorVersionsLimit, BaseTemplate, Hidden, ItemCount, RootFolder
        $libraries = @($lists | Where-Object { $_.BaseTemplate -eq 101 -and ($IncludeHiddenLists -or -not $_.Hidden) })
        foreach ($lib in $libraries) {
            $row = Copy-CMRow $base
            $row.LibraryTitle                = $lib.Title
            $row.LibraryUrl                  = $lib.RootFolder.ServerRelativeUrl
            $row.ItemCount                   = $lib.ItemCount
            $row.EnableVersioning            = $lib.EnableVersioning
            $row.MajorVersionLimit           = $lib.MajorVersionLimit
            $row.EnableMinorVersions         = $lib.EnableMinorVersions
            $row.MajorWithMinorVersionsLimit = $lib.MajorWithMinorVersionsLimit
            $row.Error                       = ''
            $results.Add([pscustomobject]$row)
        }
    }
    catch {
        $row = Copy-CMRow $base
        $row.LibraryTitle = ''; $row.LibraryUrl = ''; $row.ItemCount = ''
        $row.EnableVersioning = ''; $row.MajorVersionLimit = ''; $row.EnableMinorVersions = ''
        $row.MajorWithMinorVersionsLimit = ''
        $row.Error = $_.Exception.Message
        $results.Add([pscustomobject]$row)
    }
}
Write-Progress -Activity 'Reading library version settings' -Completed

# 2. Export
try {
    $results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
    $failed = @($results | Where-Object { $_.Error }).Count
    Write-Host ("Done. {0} rows written, {1} sites could not be read." -f $results.Count, $failed)
    Write-Host "Report saved to: $((Resolve-Path -Path $OutputPath).Path)"
}
catch {
    Write-Error "Could not write the CSV to $OutputPath : $($_.Exception.Message)"
}
Sources

Commands documented here

Every command in the script is documented on these vendor pages. Test in a non-production tenant or environment first.