How to Remove SharePoint File Shared Links: Approach Overview and Sample Implementations


Shareable links are convenient right up until nobody remembers who they went to. A view-only or edit link created for a one-time external review doesn’t expire on its own unless you set it up that way, and over time a library can accumulate links that are still technically live long after anyone needed them. Removing them — one at a time or in bulk — is what this post covers, across four different approaches depending on scale.


In this post: Prerequisites · Manual removal · PowerShell (bulk removal) · Triaging by link scope, not just age · Microsoft Graph API · Power Automate · Finding oversharing without hand-rolling the sweep · Best practices · When would you actually use this? · Related reading


Prerequisites
  • Full Control on the file/library (manual removal), or SharePoint Administrator / Global Administrator for PowerShell and Graph API approaches.
  • PnP PowerShell installed and connected, if scripting.
  • An Azure AD app registration with the right Graph permissions, if going the Graph API route.

Manual removal

Fine for one file at a time:

  1. Navigate to the file or folder in its library.
  2. Click Share, then open Manage Access.
  3. Find the link in the list and select Remove (or the “X” next to it).
  4. Confirm.

No PowerShell knowledge needed, but it doesn’t scale — fine for a handful of files, painful for a whole library.


PowerShell (bulk removal)

The relevant cmdlets are Get-PnPFileSharingLink and Remove-PnPFileSharingLink — not a parameter on Set-PnPListItemPermission, which doesn’t have a sharing-link option at all. To clear every link off a single file:

Connect-PnPOnline -Url "https://yourtenant.sharepoint.com/sites/yoursite" -Interactive

Remove-PnPFileSharingLink -FileUrl "/sites/yoursite/Shared Documents/sample.docx" -Force

To sweep an entire library:

$siteUrl = "https://yourtenant.sharepoint.com/sites/yoursite"
Connect-PnPOnline -Url $siteUrl -Interactive

$items = Get-PnPListItem -List "Documents" -PageSize 500

foreach ($item in $items) {
    $fileUrl = $item.FieldValues.FileRef
    if (-not $fileUrl) { continue }

    $links = Get-PnPFileSharingLink -FileUrl $fileUrl
    if ($links) {
        Write-Host "Removing $($links.Count) sharing link(s) from: $fileUrl"
        Remove-PnPFileSharingLink -FileUrl $fileUrl -Force
    }
}

Use Remove-PnPFolderSharingLink for links on folders rather than individual files — the cmdlets are separate. Check what’s actually there with Get-PnPFileSharingLink before running the removal in bulk, especially the first time.


The bulk sweep above removes every link it finds, which is fine for a full cleanup but overkill when the actual goal is risk reduction on a deadline — a library with 40 sharing links isn’t equally risky across all 40. Get-PnPFileSharingLink returns each link’s Scope (Anonymous, Organization, or a named-user scope) nested under its Link property, which is what actually separates “anyone with this URL, no sign-in” from “anyone already signed into the tenant”:

$items = Get-PnPListItem -List "Documents" -PageSize 500

foreach ($item in $items) {
    $fileUrl = $item.FieldValues.FileRef
    if (-not $fileUrl) { continue }

    $links = Get-PnPFileSharingLink -FileUrl $fileUrl
    $anonymousLinks = $links | Where-Object { $_.Link.Scope -eq "Anonymous" }

    if ($anonymousLinks) {
        Write-Host "ANYONE link found on: $fileUrl -- removing first"
        $anonymousLinks | ForEach-Object { Remove-PnPFileSharingLink -FileUrl $fileUrl -Force }
    }
}

Running an Anonymous-only pass first, then a full sweep afterward if there’s time, means the highest-exposure links come down before the lower-risk internal ones — worth doing in that order rather than working through a library alphabetically when there’s a real deadline (an offboarding, a compliance finding) driving the cleanup.


Microsoft Graph API

Worth reaching for when you’re building this into a custom app or a service running outside PowerShell entirely. Once you have a drive item’s permission ID (from a GET against its /permissions endpoint), removing it is a single call:

DELETE https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/permissions/{permission-id}

This needs an Azure AD app registration with Files.ReadWrite.All (or a narrower equivalent) and a client ID/secret or certificate for auth — more setup than either option above, but it’s the path that makes sense for integration with something outside the Microsoft 365 admin tooling.


Power Automate

The SharePoint connector’s relevant action is Stop sharing an item or a file — it removes every sharing link on the item and revokes direct access for anyone who isn’t an owner, in one step. Wire it to a trigger like “When a file is created or modified,” gate it with a condition (link age, a specific library), and it runs unattended going forward — no separate script to maintain, though it does need a Power Automate license tier that supports the trigger/condition combination you’re using.


Finding oversharing without hand-rolling the sweep

Worth knowing this exists before scripting a tenant-wide crawl by hand: SharePoint Advanced Management’s Data Access Governance (DAG) reports identify oversharing risk — including exactly the anonymous and organization-wide sharing links this post’s scripts hunt for — across the entire tenant from a single report, not library by library. It’s a licensed add-on rather than something included by default, so it’s not a substitute for the scripts above in every tenant, but worth checking whether it’s already available before building and maintaining a custom sweep script for something a built-in report already does at scale.


Best practices
  • Set expiration dates on external links at creation time — it prevents most of this cleanup from being necessary in the first place.
  • Audit before you bulk-remove. Run Get-PnPFileSharingLink across a library and review the list before pointing a removal script at it.
  • Schedule regular sweeps rather than one-off cleanups — link sprawl accumulates continuously, not in a single event.
  • Pair this with sensitivity labels where the content actually warrants it, so sharing restrictions are enforced by policy, not just periodic cleanup.

An expiration date set when the link is created prevents most of the cleanup this post describes — it’s cheaper than a recurring audit.

When would you actually use this?
  • An employee leaves and you need to be sure links they created with external parties no longer work — run the bulk PowerShell sweep against libraries they owned or edited.
  • A compliance review flags a library with too much external exposure — audit with Get-PnPFileSharingLink, then clean up in bulk.
  • You want this handled automatically going forward, not just fixed once — Power Automate’s “Stop sharing” action on a schedule or file-age trigger.


Hope that saves a headache later. Questions go in the comments.


App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning

Leave a Comment

Your email address will not be published. Required fields are marked *