SharePoint Online – Inquisitive M365 https://thomasdaly.net Yet another SharePoint / Office 365 blog Wed, 25 Mar 2026 03:39:13 +0000 en-US hourly 1 116451836 Managing Document Library Versioning and Expiration Across a SharePoint Tenant https://thomasdaly.net/2025/06/14/managing-document-library-versioning-tenant/ https://thomasdaly.net/2025/06/14/managing-document-library-versioning-tenant/#respond Sun, 15 Jun 2025 00:00:00 +0000 https://thomasdaly.net/?p=3434 Steampunk furnace with a robotic arm sorting holographic document versions on a conveyor belt, a glowing 60 DAYS display overhead

If you've looked at your SharePoint storage report lately and wondered where all the space went, check version history. Depending on your tenant's configuration — up to 500 major versions, or Microsoft's newer "automatic" model with no fixed cap — there's no expiration by default. Every save, every autosave from co-authoring, every edit creates a version that sticks around forever.

We found libraries where version history was consuming 3-4x the space of the current files. Co-authoring makes it worse — a one-hour session with multiple editors can generate dozens of versions. Multiply that across hundreds of sites and it adds up fast.

Microsoft added tenant-level version controls in the SharePoint Admin Center (Settings > Version history limits), which works for broad policy. But we needed per-library control baked into our site provisioning pipeline — applied consistently whether a site was created today or two years ago, without relying on someone remembering to toggle an admin setting.

We needed a consistent policy: 100 major versions, minor versions enabled, and automatic expiration after 60 days. Applied to every site in the tenant — both existing sites and every new site as it's provisioned. Here's how we did it.


The Versioning Policy

We reviewed storage reports and asked the business how far back they'd ever actually needed to roll back. The answer was almost always days, not months. We landed on:

SettingValueRationale
Major versions100Covers months of active editing, even on busy documents
Minor versionsEnabledSupports draft/publish workflows
Version expiration60 daysAuto-trims anything older than two months

The 60-day expiration is the key lever. It bounds version history regardless of edit frequency. Both major and minor versions are subject to the policy — anything older than 60 days is eligible for cleanup.


Applying Versioning at Provisioning Time

Our sites are provisioned via an Azure Function queue trigger that creates the site, applies a Patterns and Practices (PnP) template, copies template folders, and configures versioning. Here's the relevant section:

# Enable versioning on the Documents library
Write-Host "Enabling versioning on 'Documents' library."
Set-PnPList -Identity "Documents" `
    -EnableVersioning $true `
    -MajorVersions 100 `
    -EnableMinorVersions $true `
    -Connection $newSiteConnection

Write-Host "Setting expiration for versions in 'Documents' library to 60 days."
Set-PnPList -Identity "Documents" `
    -ExpireVersionsAfterDays 60 `
    -Connection $newSiteConnection

Note the two separate Set-PnPList calls. Combining -ExpireVersionsAfterDays with the other versioning parameters in a single call can produce inconsistent results depending on your PnP PowerShell version. We learned that the hard way — split them and it's reliable.


Remediating Existing Sites

New sites are handled, but existing sites still had default settings and months of accumulated version history. We built a bulk remediation script that reads a site inventory CSV and applies the same policy:

Import-Module PnP.PowerShell

# Path to the CSV file containing site inventory
$csvFilePath = "sites.csv"

# Read the CSV file
$sites = Import-Csv -Path $csvFilePath

# Iterate through each active site
foreach ($site in $sites) {
    if ($site.Status -eq 'C' -and -not [string]::IsNullOrWhiteSpace($site.SiteUrl)) {
        try {
            $siteUrl = $site.SiteUrl
            Connect-PnPOnline -Url $siteUrl -ClientId "your-app-registration-client-id"

            # Apply versioning policy
            Set-PnPList -Identity "Documents" `
                -EnableVersioning $true `
                -MajorVersions 100 `
                -EnableMinorVersions $true

            Set-PnPList -Identity "Documents" `
                -ExpireVersionsAfterDays 60

            Write-Host "Successfully updated site: $siteUrl" -ForegroundColor Green
        }
        catch {
            Write-Host "Failed to update site: $siteUrl. Error: $_" -ForegroundColor Red
        }
        finally {
            Disconnect-PnPOnline
        }
    }
}

The CSV tracks every site with a status column — C for active, R for retired. The script skips retired sites and empty URLs, so it's safe to run against the full inventory.


What Happens When Expiration Kicks In

-ExpireVersionsAfterDays 60 doesn't delete old versions immediately — SharePoint handles it as a background job. A few things to know:

  • Background timer job. Versions older than 60 days become eligible for deletion, but actual cleanup can take days on large libraries.
  • Current version is never expired. Only historical versions are affected.
  • Recycle bin delay. Deleted versions go to the recycle bin (93 days total across first and second stage). True storage recovery happens after the recycle bin clears.

If you need to reclaim storage immediately:

Clear-PnPRecycleBinItem -All -Force -Connection $siteConnection

Not reversible. We ran this selectively on sites with the highest storage pressure, not tenant-wide.


Monitoring the Results

After rolling this out, we tracked storage in SharePoint Admin Center. Within a few weeks, total tenant storage dropped as background expiration worked through the backlog. The bigger win was that storage growth flattened — no more unbounded accumulation.


Lessons Learned

Split the Set-PnPList calls. Versioning and expiration in separate calls avoids parameter combination edge cases.

Run remediation quarterly. Settings can drift — someone changes a library manually, or a new library gets created outside the pipeline. Re-running the bulk script catches it.

Watch the recycle bin. Expired versions go to the recycle bin, not into thin air. If you're trying to reclaim storage urgently, clear the recycle bins too.

Communicate before you enforce. We notified users that versions older than 60 days would be automatically cleaned up. Nobody complained — most didn't know versioning existed. But it's good governance to communicate before changing retention behavior.


Wrapping Up

SharePoint versioning is one of those features that works against you when left on autopilot. The defaults are safe but wasteful. By enforcing a consistent policy — 100 major versions with 60-day expiration — across every site in the tenant, we reduced storage consumption significantly and eliminated a growing cost problem.

The approach is two-pronged: apply the policy automatically when new sites are provisioned, and run a bulk remediation script to bring existing sites in line. Both use PnP PowerShell's Set-PnPList, and both can run unattended.

If your tenant storage report has been creeping upward and you're not sure why, check your version history. Chances are that's where the space is going. And if you're managing versioning across a tenant differently — or have hit edge cases with ExpireVersionsAfterDays — I'd like to hear about it in the comments.

]]>
https://thomasdaly.net/2025/06/14/managing-document-library-versioning-tenant/feed/ 0 3434
Sort Your SharePoint Site Directory Alphabetically https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/ https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/#comments Sun, 02 Feb 2025 21:53:07 +0000 https://thomasdaly.net/?p=3339 In my previous article, Build a Site Directory with PnP Search Web Parts, I walked through how to create a dynamic site directory using PnP Modern Search. While that setup provides a powerful and flexible way to display SharePoint sites, you may have noticed a limitation—SharePoint doesn’t allow sorting by the Site Title property out of the box.

This article covers the extra step needed to sort your site directory alphabetically by title. The trick? Leveraging RefinableString fields to make the Site Title sortable. It’s a simple process with just a few tweaks, and by the end of this guide, you’ll have a properly sorted site directory in no time. Let’s dive in.

Updating the Search Schema

Navigate to the SharePoint Admin Center

Expand ‘Advanced’ then click ‘More Features’ and finally click ‘Open’ under the ‘Search’ group

Next click ‘Manage Search Schema’

Next enter ‘RefinableString’ in the search box and click the green button

Hover over any of the available properties and find the drop down, then click ‘Edit Map Property’

It’s not critical on what number refinable string you choose

Scroll all the way to the bottom and click ‘Add a Mapping’

Enter ‘display’ and click ‘Find’, then select Basic:displaytitle and click O

Verify the mapped managed property and click ‘OK’

This completed the Search Schema changes. These can take quite some time to take effect so be patient. It could be a day before you see it working.

Next navigate to the SharePoint page with the PnP Search Web Part configured as a Site Directory

NOTE: The following steps are only necessary if you have customized the Custom template.

  1. Edit the page and open the web part properties of the Search Results web part
  2. On the second page, click on the curly braces { }
  3. Take a copy of the entire

Change the template to Debug. This is so that you can visually see the property to ensure that the search property has taken effect.

Go back to the first page of the web part properties, enter the name of the RefinableString## you modified and hit Enter.

The result should appear on the left hand site – most likely it will read null to begin with. It will eventually populate. It can appear at any time but at least wait 8 hours or a full day. Recheck the steps in the search config but at this point there is not much more to do but wait.

What to do if the site title will no show up?

If it’s just not showing for a few sites

  • Update the Site Title of the site. Change it temporarily and then change it back
  • Trigger a reindex on the 1 site

If it’s not showing up for many sites

Recrawling puts strain on the service as a whole so it’s not meant to be run over and over as it can take weeks to finish on very large sites.

After the crawl property appears move on to the next step.

Apply the Sort

Navigate back to the Search web part page and edit the web part properties

Click ‘Edit sort settings’

Type in your RefinableString## into the Field name box, click Default Sort and then click ‘Add and save’

The sorting is now set to alphabetical order from A-Z by default.

Next go to the second page of the web part properties

Set the template back to what it previously was. In our case Custom and then click on the { } to edit the custom template

Copy / Paste in the template, Save and Republish.

The final result should be in order by site title.

Wrap Up

Sorting your SharePoint site directory by title might not be possible out of the box, but with a little creativity—leveraging RefinableString fields—it becomes a straightforward solution. By following these steps, you can ensure your directory is organized in a way that makes finding sites easier for users.

This small but impactful tweak enhances usability and keeps your directory structured exactly how you need it. If you’re already using PnP Search Web Parts, this is a great optimization to implement. Have questions or run into issues? Drop a comment—I’d love to hear how this worked for you!

]]>
https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/feed/ 2 3339