My Most Used PowerShell Scripts for Managing SharePoint Online

Last updated on October 16, 2021
Working with Office 365, you too might have already started building up a collection of useful PowerShell scripts; the ones you always keep on going back to when you need to perform certain operations for a tenant. If you haven’t yet, consider doing so — the earlier, the better!
This month I’m sharing with you some of my toolkit; a collection of PowerShell scripts that are suitable for many purposes, and which I currently find myself using the most while working with SharePoint Online. If you like, you can use them as a base for your collection, or add them to your existing script library. I hope these simple scripts will help you in your day-to-day work with SharePoint Online. Sharing is caring!
Table of Contents
1 Preparations
2 Working with Sites
2.1 Get Site Properties
2.2 Get All Sites (By Type)
2.3 Hub Site Creation
3 Upload Files to a Library
4 Managing Permissions
4.1 Set a Site Collection Administrator
4.2 Remove a Site Collection Administrator
4.3 Set a Site Collection Administrator for All Sites (of Type)
4.4 Add a User to a Site Permission Group
4.5 Add a User to an Office 365 Group
4.6 Setting List Permissions for All Sites
5 Site Customizations
5.1 Hide Default Themes
5.2 Remove All Custom Themes
5.3 Site Designs
5.4 PnP Templates
Preparations
To run these scripts, you need to install the SharePoint Online Management Shell and PnP PowerShell modules if you have not yet done so.
- SharePoint Online Management Shell
- For PowerShell 5.0 or newer, run this command
Install-Module Microsoft.Online.SharePoint.PowerShell
- For older versions, download and run the SharePoint Online Management Shell installation package.
After that, run this command in PowerShell as administrator:Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
- For PowerShell 5.0 or newer, run this command
- To install PnP PowerShell, run this command as administrator:
Install-Module SharePointPnPPowerShellOnline -AllowClobber
It’s good to update both of the modules regularly to get the latest changes and possible new commandlets.
If you want to run the scripts by executing .ps1 files, you also need to run this command as administrator: Set-ExecutionPolicy Unrestricted
And a quick note in case you are using multifactor authentication (MFA): you need to change the authentication in the scripts slightly.
- In the
Connect-SPOService
commandlet, remove the -Credential parameter and its value. Doing so brings up the web login instead, which will prompt you for the authentication code. - For
Connect-PnPOnline
, omit the -Credentials parameter and its value, and replace it with -UseWebLogin.
I chose not to use web login by default, because not everyone uses MFA yet, and it is just so handy to be able to Ctrl + V a set of credentials from KeePass!
Working with Sites
Get Site Properties
Let’s start off with the very basics. Use this script when you want to view all property values for a specific site collection or to get a list of all the available properties for site collections.
param( [Parameter(Mandatory)] [String]$siteUrl ) Connect-SPOService ("{0}-admin.sharepoint.com" -f ($siteUrl.Substring(0, $siteUrl.IndexOf(".sharepoint.com")))) -Credential (Get-Credential) Get-SPOSite $siteUrl | select * Read-Host -Prompt "Press Enter to exit"
Get All Sites (By Type)
There are many situations where you need to get a list of all the site collections in your tenant. PowerShell comes especially handy if you want to get a list of communication sites because there is no such list in the graphical user interface at the moment. To list all site collections in your tenant (and their types), run the script below. You can choose to display more properties (the ones you viewed with the previous script) by adding them to the select statement. I often find myself checking the SharingCapability. You can also optionally filter the results by providing a template code when prompted. The most common ones are the following:
Site type | Template |
---|---|
Communication Site | SITEPAGEPUBLISHING#0 |
Modern Team Site | GROUP#0 |
Classic Team Site | STS#0 |
param( [Parameter(Mandatory)] [String]$tenant ) Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential (Get-Credential) Get-SPOSite -Limit All | select Template -unique | out-host $siteType = Read-Host "Optional template to filter by (or just hit Enter to get all sites)" $sites = Get-SPOSite -Limit All if ($siteType -ne "") { $sites = $sites | where { $_.Template -eq $siteType } } $sites | select Url, Template | Sort-Object Template, Url Read-Host -Prompt "Press Enter to exit"
Hub Site Creation
If you want to create a hub site, you first need to create a regular site and then convert it into a hub. Here we’ll first create a communication site and then register it as a hub site.
param( [Parameter(Mandatory)] [String]$tenant, [Parameter(Mandatory)] [String]$siteTitle, [Parameter(Mandatory)] [String]$siteUrlName, [Parameter(Mandatory)] [String]$siteDescription, [Parameter(Mandatory)] [String]$siteDesign, # Possible values: Topic, Showcase, Blank [Parameter(Mandatory)] [String[]]$principals ) Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential (Get-Credential) $siteUrl = "https://{0}.sharepoint.com/sites/{1}" -f $tenant, $siteUrlName New-PnPSite -Type CommunicationSite -Title $siteTitle -Url $siteUrl -Description $siteDescription -SiteDesign $siteDesign Register-SPOHubSite $siteUrl -Principals $principals Read-Host -Prompt "Press Enter to exit"
You can also revert the operation, and convert a hub site back into a regular communication site.
param( [Parameter(Mandatory)] [String]$siteUrl ) Connect-SPOService ("{0}-admin.sharepoint.com" -f ($siteUrl.Substring(0, $siteUrl.IndexOf(".sharepoint.com")))) -Credential (Get-Credential) Unregister-SPOHubSite $siteUrl Read-Host -Prompt "Press Enter to exit"
Upload Files to a Library
This script uploads all files from a specified folder to a library and updates their metadata. You can add more properties to update after the title if you like.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$libraryInternalName, [Parameter(Mandatory)] [String]$drivePath ) $connection = Connect-PnPOnline $siteUrl -Credentials (Get-Credential) -ReturnConnection $files = Get-ChildItem $drivePath Write-Host ("Uploading {0} files" -f $files.Length) foreach ($file in $files) { Add-PnPFile -Path $file.FullName -Folder $libraryInternalName -Values @{ "Title" = $file.Name; } -Connection $connection } Read-Host -Prompt "Press Enter to exit"
Managing Permissions
Even though you are an administrator in a tenant, you don’t automatically have access to all of the sites. To be able to browse sites, you need to give permissions to yourself. For modern team sites, you can do this via Groups in the Admin center, but for communication sites, you always need to give yourself permissions via PowerShell.
Set a Site Collection Administrator
With the script below, you can add yourself or some other user as the site collection administrator.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$loginName ) Connect-SPOService ("{0}-admin.sharepoint.com" -f ($siteUrl.Substring(0, $siteUrl.IndexOf(".sharepoint.com")))) -Credential (Get-Credential) $supress = Set-SPOUser -Site $siteUrl -LoginName $loginName -IsSiteCollectionAdmin $true $obj = New-Object PSObject $obj | Add-Member "SiteUrl" $siteUrl $obj | Add-Member "LoginName" $loginName $obj | Add-Member "IsSiteAdmin" (Get-SPOUser -Site $siteUrl -LoginName $loginName | select IsSiteAdmin).IsSiteAdmin $obj | out-host Read-Host -Prompt "Press Enter to exit"
Remove a Site Collection Administrator
There may also be a time when you need to remove those permissions. For example, you might want to give yourself site collection administrator permissions only temporarily for performing some specific operation on a site.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$loginName ) Remove-PnPSiteCollectionAdmin -Owners $loginName -Connection (Connect-PnPOnline $siteUrl -Credentials (Get-Credential) -ReturnConnection) $obj = New-Object PSObject $obj | Add-Member "SiteUrl" $siteUrl $obj | Add-Member "LoginName" $loginName $obj | Add-Member "IsSiteAdmin" (Get-SPOUser -Site $siteUrl -LoginName $loginName | select IsSiteAdmin).IsSiteAdmin $obj | out-host Read-Host -Prompt "Press Enter to exit"
Set a Site Collection Administrator for All Sites (of Type)
When we want to make a user a site collection admin on all sites, we need to get all of the sites and loop through them. You can filter the sites by a template if you want to grant permissions only on, e.g., communication sites.
param( [Parameter(Mandatory)] [String]$tenant, [Parameter(Mandatory)] [String]$loginName ) Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential (Get-Credential) Get-SPOSite -Limit All | select Template -unique | out-host $siteType = Read-Host "Optional template to filter by (or just hit Enter to get all sites)" $sites = Get-SPOSite -Limit All if ($siteType -ne "") { $sites = $sites | where { $_.Template -eq $siteType } } foreach ($site in $sites) { $supress = Set-SPOUser -Site $site.Url -LoginName $loginName -IsSiteCollectionAdmin $true $obj = New-Object PSObject $obj | Add-Member "SiteUrl" $site.Url $obj | Add-Member "LoginName" $loginName $obj | Add-Member "IsSiteAdmin" (Get-SPOUser -Site $site.Url -LoginName $loginName | select IsSiteAdmin).IsSiteAdmin $obj } Read-Host -Prompt "Press Enter to exit"
Add a User to a Site Permission Group
Now, what about other permissions? With the script below, you can add a user to a site permission group on a site. If you add a loop around the script, it becomes even more useful.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$loginName, [Parameter(Mandatory)] [String]$siteGroupName # e.g. Owners, Members, Visitors ) Connect-SPOService ("{0}-admin.sharepoint.com" -f ($siteUrl.Substring(0, $siteUrl.IndexOf(".sharepoint.com")))) -Credential (Get-Credential) $group = Get-SPOSiteGroup -Site $siteUrl | where {$_.Title -like ("*{0}" -f $siteGroupName) } Add-SPOUser -Site $siteUrl -LoginName $loginName -Group $group.Title Read-Host -Prompt "Press Enter to exit"
I’d like to remind you that when you are granting permissions to guests, you might also need to adjust the SharingCapability setting of the site before guests can access. I’ve previously written a blog post about disabling guest access, but you can use those same scripts for enabling access too if it is not more restrictive on tenant level. Also remember that if your site is a modern team site, you most likely also want to adjust the external sharing setting for its Office 365 group, too.
Add a User to an Office 365 Group
Now, I know that the scope of this article is managing SharePoint, but because modern team sites are so tightly connected to their Office 365 groups, I can not just pass them by here. With this script, you can add a user to an Office 365 group with the specified role (e.g., owner or member). This script becomes even handier if you are setting group memberships for several groups and users, e.g., based on a CSV file.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$loginName, [Parameter(Mandatory)] [String]$membershipType #e.g. Owner or Member ) $cred = Get-Credential $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection Import-PSSession $session Connect-PnPOnline $siteUrl -Credentials $cred $groupId = (Get-PnPSite -Includes GroupId).GroupId.ToString() # Owners also need to be members if ($membershipType.ToLower() -eq "owner" -or $membershipType.ToLower() -eq "owners") { Add-UnifiedGroupLinks -Identity $groupId -LinkType "Member" -Links $loginName -Confirm:$false } Add-UnifiedGroupLinks -Identity $groupId -LinkType $membershipType -Links $loginName Remove-PSSession $session Read-Host -Prompt "Press Enter to exit"
Setting List Permissions for All Sites
Here is a bit longer script. It allows you to change the permission level of a site permission group for specified document libraries or lists on all sites. The script has come in handy in those cases where we have systematically provisioned sites with the same library structure, and later on, there has arisen a need to alter their permissions. You can provide a full group name or just Visitor, Member or Owner for the siteGroupName parameter. You can specify multiple lists/libraries and roles to add and remove. Typical roles to assign are “Read”, “Edit” and “Full control”.
param( [Parameter(Mandatory)] [String]$tenant, [Parameter(Mandatory)] [String[]]$listTitles, [Parameter(Mandatory)] [String]$siteGroupName, [Parameter(Mandatory)] [String[]]$rolesToAdd, [Parameter(Mandatory)] [String[]]$rolesToRemove ) $cred = Get-Credential Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential $cred $sites = Get-SPOSite -Limit All foreach ($site in $sites) { Write-Host $site.Url $web = Get-PnPWeb -Connection (Connect-PnPOnline $site.Url -Credentials $cred -ReturnConnection) foreach ($listTitle in $listTitles) { $list = Get-PnPList $listTitle -Web $web if ($list -eq $null) { Write-Host "There is no library called" $listTitle continue } Write-Host "Setting permissions for" $listTitle $list.BreakRoleInheritance($true, $true) $list.Update() $list.Context.Load($list) $list.Context.ExecuteQuery() $group = Get-SPOSiteGroup -Site $site | where {$_.Title -like ("*{0}" -f $siteGroupName) } foreach ($roleToAdd in $rolesToAdd) { Set-PnPGroupPermissions -Identity $group.Title -List $listTitle -AddRole $roleToAdd } foreach ($roleToRemove in $rolesToRemove) { Set-PnPGroupPermissions -Identity $group.Title -List $listTitle -RemoveRole $roleToRemove } } } Read-Host -Prompt "Press Enter to exit"
Site Customizations
For adding a new custom color theme to your tenant, please check my viral blog post about creating multicolored themes; it contains the script and instructions for creating color palettes. What I haven’t included in that blog post is removing custom themes and hiding the default themes, and I’ll share those with you here.
Hide Default Themes
By hiding the default themes, you can ensure the site owners always use company branded themes on their sites.
param( [Parameter(Mandatory)] [String]$tenant, [Parameter(Mandatory)] [String]$hideThemes ) switch ($hideThemes) { "true" { $hide = $true } "false" { $hide = $false } } Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential (Get-Credential) Set-SPOHideDefaultThemes -HideDefaultThemes:$hide if (Get-SPOHideDefaultThemes) { Write-Host "Default themes are now hidden." } else { Write-Host "Default themes are now visible." } Read-Host -Prompt "Press Enter to exit"
Remove All Custom Themes
I mostly run this script in my development tenant to clean up after testing.
param( [Parameter(Mandatory)] [String]$tenant ) Connect-SPOService ("https://{0}-admin.sharepoint.com" -f $tenant) -Credential (Get-Credential) $themes = Get-SPOTheme foreach ($theme in $themes) { Remove-SPOTheme -name $theme.Name } Read-Host -Prompt "Press Enter to exit"
Site Designs
For PowerShell scripts related to site designs, I’m again going to direct you to another one of my blog posts: The Ultimate Guide to Site Designs and Site Scripts. See how I’m a good little dev here by not duplicating the code? 😉
PnP Templates
If you are not yet familiar with PnP provisioning, I much recommend you do so here.
This script saves an existing site configuration as a template. There is a list of parameters you can use for defining the template contents in more detail.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$fileName ) Connect-PnPOnline -Url $siteUrl -Credentials (Get-Credential) Get-PnPProvisioningTemplate -Out ("{0}\{1}.xml"-f $PSScriptRoot, $fileName) Read-Host -Prompt "Press Enter to exit"
And with this script, you can apply the template configurations to an existing site.
param( [Parameter(Mandatory)] [String]$siteUrl, [Parameter(Mandatory)] [String]$fileName ) Connect-PnPOnline -Url $siteUrl -Credentials (Get-Credential) Apply-PnPProvisioningTemplate -Path ("{0}\{1}.xml"-f $PSScriptRoot, $fileName) Read-Host -Prompt "Press Enter to exit"
Now that you’ve browsed through all these scripts, do tell, would you like to see more of this kind of posts, or did you not find it that useful? I’d also be interested to know if you have assembled your toolkit and shared it somewhere online? Let me and your fellow developers know in the comments!
And speaking about sharing, in addition to these blog posts, I’m also sharing some tips on Twitter which are too small for a blog post. Follow me on Twitter if you are interested in reading the those or getting notifications when I publish new articles. Thank you very much for taking the time to read this article, I hugely appreciate it as always, and until next time!
Laura
Hi This is Great Place I found.
Do you have any script to get onedrive for business site collection administrator. I have different Global Admin Showing up with Access to few Users OneDrive for Business i need to list users having admin account as site collection admin for OD4B
Regards
Hi, here is a script that returns all the collection administrators for a specified users onedrive.
Sorry for the formatting.
You need to run this as a global administrator and pass along the credentials
The script will add that user as a collection administrator (so you will have the permission to retrieve information about the site).
Then it will use PnP-cmdlets to retreive the list of Collection Admins.
Finally it will remove the collection administrator specified in the beginning.
You specifiy the userPrincipalname for the user you want to check.
#
param([string] $User = $(throw “Missing userPrincipalName”), [System.Management.Automation.PSCredential] $Credential = $(Get-Credential));
Connect-MsolService -Credential $Credential
# Setup some handy variables.
$InitialDomain = Get-MsolDomain | Where-Object {$_.IsInitial -eq $true} # Name of our domain/tenant
$SharePointAdminURL = “https://$($InitialDomain.Name.Split(“.”)[0])-admin.sharepoint.com” # URL to the sharepoint admin site
$personalname = $user -replace “[^a-zA-Z0-9]”, “_” # e.g fridden@contoso.com -> fridden_contoso_com
$OneDriveSite = “https://$($InitialDomain.Name.Split(“.”)[0])-my.sharepoint.com/personal/$personalname” # Url to the onedrive
# connect to our Admin site
Connect-SPOService -Url $SharePointAdminURL -Credential $Credential
# Set ourself as collection administrators
Set-SPOUser -Site $OneDriveSite -LoginName $Credential.UserName -IsSiteCollectionAdmin $true | Out-Null;
# Connect to the onedrive site
Connect-PnPOnline -Url $OneDriveSite -Credentials $Credential
# Retrieve all collection admins. Note,
Get-PnPSiteCollectionAdmin
# Remove ourself from the collection administrator list.
Set-SPOUser -Site $OneDriveSite -LoginName $Credential.UserName -IsSiteCollectionAdmin $false | Out-Null
# done.
Thank you
Thank you for helping, Fredrik! 🙂
Laura
It’s working for One user , how can I get it for all users in the tenant. I think I have to run a loop by getting all the one drive site. I am new to PS scrips if you have any Scrip pls help.
Thx Laura
It’s very helpfull
Ralf
Hi Ralf!
I’m glad you found this post useful. 🙂
Laura
Hi, this site is amazing. Great scripts it appears, but then if you have two-factor login turned on, it doesn’t seem to recognize the username and password. It looks like we need to have token authentication, so it’s back to the drawing board.
Hi Patrick,
If you check the “Preparations” section at the beginning of this blog post, there are instructions what you need to do in case you are using multifactor authentication.
Laura
Laura,
Your posts are both beautiful and informative. Kudos to you!
I ‘d like to ask if you have any scripts for creating the pnp Template.xml files with the content of Events lists and Document libraries? I’d like to be able to run Get-PnPProvisioningTemplate to generate a Template.xml file that contains all the pages
and news (which this page tells us how to do http://sharepoint.handsontek.net/2018/02/04/create-a-modern-sharepoint-site-template-with-multiple-pages-using-the-pnp-provisioning-engine/#comment-2924) and all the events and documents and all the image assets etc used in the given site.
Any pointers gladly received – and some links to download scripts that wopuld do so would be greeted with adoration and mucho respect!
Kindest regards from sunny Wales, UK
Sam
Hi Sam,
Looks like you already got your question answered on that other site. 🙂
Laura
Hello Laura!
Your blog is one of the most organized, easy-to-read resources I’ve found in the past 3 weeks of research I’ve been doing. We’re in the process of moving from SharePoint on-prem 2013 to online and we’re starting over from scratch, so your blogs are incredibly helpful.
–Can the PNP Template export/import be done at the Site Collection level? We have about 25 site collections and don’t really use sub-sites.
–Do you have a script that can export/import Managed (metadata) Navigation across multiple site collections (export from one and import to all of the others)?
—-Or if you can’t export, is there a way to import using XML or CSV?
I’ve been researching this for the past 2 weeks and have yet to find anything to accomplish this. I have tried “pinning”, however when I make a change to a term it doesn’t push the changes to the pinned items, which defeats the purpose in my opinion.
All I want to do is have a consistent global navigation across all site collections without having to manually update each and every site collection. You would think this would be easy to accomplish without a ton of code or customizing master pages.
I tried using a Hub site to push the navigation, however using managed navigation requires publishing features which aren’t compatible with “Modern” pages.
-Thank you so much for these resources and time.
Hi Joe,
Wow, that’s a very nice compliment, thank you! 🙂
– Yes, PnP templates can be exported and imported on site collection level. They work on both modern and classic sites.
– No, unfortunately, I don’t have a script ready for what you ask. However, term sets can be imported using a CSV file just like on on-premises SharePoint. You need to go to Admin -> the SharePoint Admin Center -> Termstore, and add yourself as one of the term store administrators. After that, you are able to add a new group to term store and import a term set into the group using a CSV file. There is a link to a sample file on the term store front page.
Now that you are moving from SharePoint 2013 to a brand new SharePoint Online, are you really sure you want to use the classic sites? Those are considered old, and while they continue to be supported, modern sites will have all the new cool stuff. When you group sites together using a hub site, they will share the navigation. If you want to have several hubs, perhaps you can think of a structure in which you don’t need to have the exact same navigation everywhere?
Laura
Thanks for the info Laura!
– I had looked into importing the CSV file for terms…. That only works with term sets, not managed navigation term sets. (as far as I’m aware) There’s no columns to add the link address, as I would for managed global navigation.
– Unfortunately, one of the requirements is to have consistent global navigation on all of the pages. I experimented around with using a HUB site, but the moment you hit a classic page or a list flips to classic view, you lose the HUB navigation. This is why I was hoping to find a script that can push the managed navigation term set to ALL of our site collections so I don’t have to manually update 20+ site collections when something gets changed.
– As far as moving to Modern sites… I plan on creating all of the site collections using STS#3, the Modern Site not associated with an Office 365 Group. This will allow us to still use our current active directory security groups for access and later associate Office 365 groups if the need arises. We can then enable the Publishing features required for manage navigation. I don’t know of any other way to manage navigation except for the oob Structured navigation, which they don’t recommend or a custom solution, which is what was used in our current 2013 environment (developed by the person before me).
I have been working with SharePoint since the “MOSS” days, but I’m not adept enough to create the customizations needed for navigation nor do I know enough about Visual Studio. I also don’t want to customize to much so future Microsoft updates don’t kill us.
If I could accomplish managed navigation without the publishing feature, or modern pages were compatible with the “pages” publishing folder, my life would be complete.
If you have any other suggestions or tips regarding Navigation, I’m always open to hear it!