So, few years back I released a proof of concept script to remove all sharing links and permissions for all items in a user’s OneDrive for Business site. Since then, people have been asking me to release a version of the script that does the same for SharePoint sites or process all ODFB sites, without having to list them individually. Back then, there was no endpoint that can enumerate all sites within a tenant, so I put this on hold. And then, when earlier this year I released updated version of my report shared files script, I simply forgot to update the “removal” sibling. Oh well, I’m getting old I suppose.
Better late than never, as the saying goes! I’m happy to present you with an updated version of the script, one that allows you to remove permissions from any shared item, across both SharePoint Online and OneDrive for Business. As the script reuses large parts of the code we used in the report shared files script, I will not go into details on the script’s structure and methods used here. If you are interested in those, make sure to check out the linked article above.
Still, few things need to be mentioned. The script uses application permissions, thus you need to have a service principal to which you’ve granted the Sites.ReadWrite.All permission in order to run the corresponding operations. Make sure to set the authentication variables (lines 191-193), after downloading the script from my GitHub repo. As usual, you should replace the whole authentication block with your preferred solution. And please do not store credentials in plain text, especially credentials for applications with such permission requirements!
To run the script, you have few options. The one I would strongly recommend is to prepare a list of sites and leverage the -Sites parameter, so that only the sites in question are processed. The script does support running against all SPO and ODFB sites, but there are obvious performance and reliability concerns in such scenarios, not to mention the security ones. So I will again remind you that this is a proof of concept, not production ready solution. Error handling is kept to a minimum, and I only tested the script in small tenants (hundred sites and ~50k items or so).
Anyway, here is the list of parameters accepted by the script:
-
Sites – use this parameter to provide a list of sites to run the script against. Valid values include the full site URI, the ID as reported by Graph or a path (see examples below). The parameter is optional, and if you do not provide a value for it, the script will enumerate all sites within the tenant.
- IncludeODFBsites – switch parameter, indicates whether to enumerate and process OneDrive for Business sites. When using the Sites parameter, I’m assuming that you want all the listed sites processed, so this parameter is ignored.
- Verbose – use this parameter to show additional details as the script progresses.
To run the script against a specific site, use the first example below. The second example shows how to run it against all the SharePoint Online sites within the tenant, and the third one includes any OneDrive for Business sites as well. As mentioned above, use the last two examples with care, especially in any organization of size!
#Use the Sites parameter to process specific sites only .\Graph_SPO_remove_all_shared.ps1 -Sites "tenant.sharepoint.com,12345678-1234-1234-1234-cf16a0a8a888,12345678-1234-1234-1234-c3a1f49ff1d4","https://tenant.sharepoint.com/sites/newwwwww","tenant.sharepoint.com/sites/newwwwww" #Run the script without any parameter to process all SPO sites .\Graph_SPO_remove_all_shared.ps1 #If you want to also process OneDrive for Business sites, use the parameter .\Graph_SPO_remove_all_shared.ps1 -IncludeODFBsites
The script will also generate some basic output and dump it to a CSV file within the working directory. Keep in mind that the output only indicates that a given item was processed, it does not include any details on which permissions were removed or the ones for which removal failed. The Graph API will happily reply with an No Content – 204 response even if the permission entry cannot be removed (i.e. owner permission), so if you want to properly report on which permissions did not get removed and which ones did, you have to do a “before and after” comparison… too much overhead for an otherwise quite simple solution.
With the above in mind, I’d strongly recommend that you first run the “report shared files” script in order to generate a CSV file with detailed information on the permission on each item (make sure to leverage the –IncludeOwner switch). You can use said CSV as sort of a “backup” if needed, and reruning the script after the removal will give you a better understanding of which items remain shared. Or you can just update the current script with more robust reporting, it’s up to you.
Lastly, some caveats about checking and removing the permissions entries need to be mentioned. First, the script relies on the shared facet in order to determine whether a given item needs to be processed. The existence of a shared facet however does not mean that the item is shared externally, so effectively, the script processed internally-shared items as well. If you do not want to remove permissions for such items, update the logic of the RemovePermissions function. Sample (and simple) if check is left commented therein, which you can use as a starting point.
Processing an item should remove any added permission entry, effectively rendering the item shared-facet-less. This doesn’t necessarily mean that all permissions on the item were removed though. For example, any (secondary) site collection admin will still have a matching owner permission entry stamped on items held within the site. Such entries cannot be removed via the Graph API, even though the corresponding Delete permission call seemingly succeeds. The point is, there are scenarios where the item might still be accessible by others, so I would again recommend running the report shared items script with the –IncludeOwner switch, if you want the full picture.
As always, feedback and comments are welcomed.