Skip to content

Commit 2a580fb

Browse files
authored
Merge pull request #797 from reshmee011/deletedexpiredsl
New sample script to remove expired or older sharing links
2 parents 262885b + 7d9fcfa commit 2a580fb

File tree

3 files changed

+251
-0
lines changed

3 files changed

+251
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
plugin: add-to-gallery
3+
---
4+
5+
# Deletes expired and older sharing links for folder, file and item
6+
7+
## Summary
8+
9+
Currently, there is no default expiry time for "people you choose" or "people in your organization" links, and expired links are not automatically deleted. Using this script can help clean up your environment by removing expired or older sharing links, thereby enhancing security and governance.
10+
11+
![Example Screenshot](assets/preview.png)
12+
13+
### Prerequisites
14+
15+
- The user account that runs the script must have access to the SharePoint Online site.
16+
17+
# [PnP PowerShell](#tab/pnpps)
18+
19+
```powershell
20+
param(
21+
[Parameter(Mandatory)]
22+
[string]$daysToKeepSharingLinkAfterCreationIfNoExpiryDateSpecified,
23+
[Parameter(Mandatory)]
24+
[ValidateSet('Yes','No')]
25+
[string]$DeleteSharingink,
26+
[Parameter(Mandatory)]
27+
[string]$siteUrl
28+
)
29+
30+
31+
#$daysToKeep = Read-Host -Prompt "Enter the number of days to keep sharinglinks if no expired date is set";
32+
$dateTime = (Get-Date).toString("dd-MM-yyyy-hh-ss")
33+
$invocation = (Get-Variable MyInvocation).Value
34+
$directorypath = Split-Path $invocation.MyCommand.Path
35+
$fileName = "DeletedExpiredSharedLinks-PnP" + $dateTime + ".csv"
36+
$logDirectory = $directorypath + "\Log1s"
37+
if (-not (Test-Path -Path $logDirectory)) {
38+
New-Item -ItemType Directory -Path $logDirectory
39+
}
40+
$ReportOutput = $directorypath + "\Log1s\"+ $fileName
41+
42+
#Connect to PnP Online
43+
Connect-PnPOnline -Url $siteUrl
44+
write-host $("Start time " + (Get-Date))
45+
$global:Results = @();
46+
47+
function Get-ListItems_WithUniquePermissions{
48+
param(
49+
[Parameter(Mandatory)]
50+
[Microsoft.SharePoint.Client.List]$List
51+
)
52+
$selectFields = "ID,HasUniqueRoleAssignments,FileRef,FileLeafRef,FileSystemObjectType"
53+
54+
$Url = $siteUrl + '/_api/web/lists/getbytitle(''' + $($list.Title) + ''')/items?$select=' + $($selectFields)
55+
$nextLink = $Url
56+
$listItems = @()
57+
$Stoploop =$true
58+
while($nextLink){
59+
do{
60+
try {
61+
$response = invoke-pnpsprestmethod -Url $nextLink -Method Get
62+
$Stoploop =$true
63+
64+
}
65+
catch {
66+
write-host "An error occured: $_ : Retrying" -ForegroundColor Red
67+
$Stoploop =$true
68+
Start-Sleep -Seconds 30
69+
}
70+
}
71+
While ($Stoploop -eq $false)
72+
73+
$listItems += $response.value | where-object{$_.HasUniqueRoleAssignments -eq $true}
74+
if($response.'odata.nextlink'){
75+
$nextLink = $response.'odata.nextlink'
76+
} else{
77+
$nextLink = $null
78+
}
79+
}
80+
81+
return $listItems
82+
}
83+
84+
function getSharingLink($_object,$_type,$_siteUrl,$_listUrl,$_listid)
85+
{
86+
$sharingSettings = Invoke-PnPSPRestMethod -Method Post -Url "$($siteUrl)/_api/web/Lists(@a1)/GetItemById(@a2)/GetSharingInformation?@a1='{$($_listId)}'&@a2='$($_object.Id)'&`$Expand=permissionsInformation,pickerSettings" -ContentType "application/json;odata=verbose" -Content "{}"
87+
ForEach ($ShareLink in $sharingSettings.permissionsInformation.links)
88+
{
89+
$linkDetails = $shareLink.linkDetails
90+
if($linkDetails.ShareTokenString){
91+
$action = $null
92+
93+
#update expiration date to be created date + x days if created date + 180 days is less than today otherwise delete the sharing link
94+
$CurrentDateTime = Get-Date
95+
$createdDate = Get-Date -Date $linkDetails.Created
96+
# delete any sharing links created more than x days ago
97+
$expirationDate = $createdDate.AddDays($daysToKeepSharingLinkAfterCreationIfNoExpiryDateSpecified)
98+
99+
if($expirationDate -lt $CurrentDateTime -or ($linkDetails.Expiration -ne "" -and (Get-Date -Date $linkDetails.Expiration) -lt $CurrentDateTime))
100+
{
101+
if($DeleteSharingink -eq 'Yes'){
102+
#Instead using the rest api call, use the Remove-PnPFileSharingLink or Remove-PnPFolderSharingLink
103+
$url = "$siteUrl/_api/web/Lists('$_listid')/GetItemById($($_object.Id))/UnshareLink"
104+
$varBody = '{"linkKind":'+ $linkDetails.LinkKind +',"shareId":"'+ $linkDetails.ShareId +'"}'
105+
$action = "Deleted"
106+
$sharingInfo = invoke-pnpsprestmethod -Url $url -Method Post -Content $varBody
107+
}
108+
109+
$invitees = (
110+
$linkDetails.Invitations |
111+
ForEach-Object { $_.Invitee.email }
112+
) -join '|'
113+
114+
$result = New-Object PSObject -property $([ordered]@{
115+
ItemID = $item.Id
116+
ShareId = $linkDetails.ShareId
117+
ShareLink = $linkDetails.Url
118+
Invitees = $invitees
119+
Name = $_object.FileLeafRef ?? $_object.Title
120+
Type = $_type -eq 1 ? "Folder" : "File"
121+
RelativeURL = $_object.FileRef ?? ""
122+
LinkAccess = "ViewOnly"
123+
Created = Get-Date -Date $linkDetails.Created
124+
CreatedBy = $linkDetails.CreatedBy.email
125+
LastModifiedBy = $linkDetails.LastModifiedBy.email
126+
LastModified = $LastModified
127+
ShareLinkType = $linkDetails.LinkKind
128+
Expiration = $linkDetails.Expiration
129+
BlocksDownload = $linkDetails.BlocksDownload
130+
RequiresPassword = $linkDetails.RequiresPassword
131+
PasswordLastModified = $linkDetails.PasswordLastModified
132+
PassLastModifiedBy = $linkDetails.PasswordLastModifiedBy.email
133+
HasExternalGuestInvitees = $linkDetails.HasExternalGuestInvitees
134+
HasAnonymousLink = $linkDetails.HasAnonymousLink
135+
AllowsAnonymousAccess = $linkDetails.AllowsAnonymousAccess
136+
ShareTokenString = $linkDetails.ShareTokenString
137+
Action = $action
138+
})
139+
$global:Results +=$result;
140+
}
141+
}
142+
}
143+
}
144+
145+
#Exclude certain libraries
146+
$ExcludedLists = @("Access Requests", "App Packages", "appdata", "appfiles", "Apps in Testing", "Cache Profiles", "Composed Looks", "Content and Structure Reports", "Content type publishing error log", "Converted Forms",
147+
"Device Channels", "Form Templates", "fpdatasources", "Get started with Apps for Office and SharePoint", "List Template Gallery", "Long Running Operation Status", "Maintenance Log Library", "Images", "site collection images"
148+
, "Master Docs", "Master Page Gallery", "MicroFeed", "NintexFormXml", "Quick Deploy Items", "Relationships List", "Reusable Content", "Reporting Metadata", "Reporting Templates", "Search Config List", "Site Assets", "Preservation Hold Library",
149+
"Site Pages", "Solution Gallery", "Style Library", "Suggested Content Browser Locations", "Theme Gallery", "TaxonomyHiddenList", "User Information List", "Web Part Gallery", "wfpub", "wfsvc", "Workflow History", "Workflow Tasks", "Pages")
150+
151+
152+
Write-Host "Processing site $siteUrl" -Foregroundcolor "Red";
153+
154+
$ll = Get-PnPList -Includes BaseType, Hidden, Title,HasUniqueRoleAssignments,RootFolder | Where-Object {$_.Hidden -eq $False -and $_.Title -notin $ExcludedLists } #$_.BaseType -eq "DocumentLibrary"
155+
Write-Host "Number of lists $($ll.Count)";
156+
157+
foreach($list in $ll)
158+
{
159+
$listUrl = $list.RootFolder.ServerRelativeUrl;
160+
161+
#Get all list items in batches
162+
$ListItems = Get-ListItems_WithUniquePermissions -List $list
163+
164+
ForEach($item in $ListItems)
165+
{
166+
$type= $item.FileSystemObjectType;
167+
getSharingLink $item $type $siteUrl $listUrl $list.Id;
168+
}
169+
}
170+
171+
$global:Results | Export-CSV $ReportOutput -NoTypeInformation
172+
Write-host -f Green "Deletion of expired Sharing Links Report Generated Successfully! at $ReportOutput"
173+
write-host $("End time " + (Get-Date))
174+
```
175+
176+
[!INCLUDE [More about PnP PowerShell](../../docfx/includes/MORE-PNPPS.md)]
177+
178+
***
179+
180+
## Source Credit
181+
182+
Sample first appeared on [Automate the Removal of Expired Sharing Links in SharePoint with PowerShell](https://reshmeeauckloo.com/posts/powershell-sharinglink-remove-expiredlinks/)
183+
184+
## Contributors
185+
186+
| Author(s) |
187+
|-----------|
188+
| [Reshmee Auckloo](https://github.com/reshmee011) |
189+
190+
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
191+
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-delete-expired-sharingLink-folder-file-item" aria-hidden="true">
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
[
2+
{
3+
"name": "spo-delete-expired-sharing-link-folder-file-item",
4+
"source": "pnp",
5+
"title": "Deletes expired and older sharing links for folder, file and item in SharePoint",
6+
"shortDescription": "Deletes expired and older sharing links for folder, file, and item. Currently expired or older sharing links are not automatically deleted",
7+
"url": "https://pnp.github.io/script-samples/spo-delete-expired-sharing-link-folder-file-item/README.html",
8+
"longDescription": [
9+
"Currently, there is no default expiry time for 'people you choose' or 'people in your organization' links, and expired links are not automatically deleted. Using this script can help clean up your environment by removing expired or older sharing links, thereby enhancing security and governance."
10+
],
11+
"creationDateTime": "2025-01-13",
12+
"updateDateTime": "2025-01-13",
13+
"products": [
14+
"SharePoint",
15+
"Sharing Links",
16+
"Microsoft 365 Copilot"
17+
],
18+
"metadata": [
19+
{
20+
"key": "PNP-POWERSHELL",
21+
"value": "2.99.0"
22+
}
23+
],
24+
"categories": [
25+
"Report",
26+
"Microsoft 365 Copilot"
27+
],
28+
"tags": [
29+
"modern",
30+
"Connect-PnPOnline",
31+
"Get-PnPProperty",
32+
"Remove-PnPgroup",
33+
"Get-PnPList",
34+
"Get-PnPListItem"
35+
],
36+
"thumbnails": [
37+
{
38+
"type": "image",
39+
"order": 100,
40+
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/spo-delete-expired-sharing-link-folder-file-item/assets/preview.png",
41+
"alt": ""
42+
}
43+
],
44+
"authors": [
45+
{
46+
"gitHubAccount": "reshmee011",
47+
"company": "",
48+
"pictureUrl": "https://avatars.githubusercontent.com/u/7693852?v=4",
49+
"name": "Reshmee Auckloo"
50+
}
51+
],
52+
"references": [
53+
{
54+
"name": "Want to learn more about PnP PowerShell and the cmdlets",
55+
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
56+
"url": "https://aka.ms/pnp/powershell"
57+
}
58+
]
59+
}
60+
]

0 commit comments

Comments
 (0)