Site collection provisioning and customisation scenarios for SharePoint online

Site collection provisioning and customisation scenarios for SharePoint Online

I’ve worked with a few customers recently, whom are either starting a deployment project in SharePoint Online, or some way into one, and one of the challenges they had to deal with is how best to provision customised site collections.

This article covers site collection provisioning and customisation for the following scenarios:

1/ Bulk site collection provisioning and customisation

2/ Ongoing/ requested site collection provisioning and customisation.

Scenario 1 – Bulk provisioning of site collections.

Some customers must deploy large numbers of customised site collections, which means that provisioning site collections manually is not really an option.

To provide some real world context, I worked with a customer a few months ago that was facing exactly this challenge.  They had to provision ~250 site collections (one for each branch office); each site collection had several sub-sites and was relatively customised (custom master page, lists/libraries, content types etc).  Manually it was going to take about 3-4 hours per site collection to apply the customisations. This, for obvious reasons, this option could not seriously be considered due to resource requirements.

A solution that I worked with the customer to develop, was to automate the site collection provisioning process using PowerShell. We agreed that a CSV file would act as a work list containing the information required to provision site collections. The process would take each entry in the CSV file, provision a site collection, and apply customisations to it depending on the type of site collection required.  The flow/ process looked something like this:



PowerShell has been around for a long time now, and most customers that I work with are very experienced with PowerShell, but often haven’t had to use anything outside of the Cmdlets that are provided with the on-premise SharePoint Snap-in.

A brief tangent from the story here, if you haven’t had to write any PowerShell for SharePoint online so far, then there are a few things that you should be aware of:

  1. SharePoint Online management shell (introduction & download) – is a really useful tool if you are a SharePoint Online administrator.  It contains approx. 42 Cmdlets that enable to you to perform basic administration tasks; however, you should understand a few things:
    1. The smallest entity that you can work with is a Site Collection; therefore, you will not be able to access a sub-site, list/ library, etc.
    2. To use the SharePoint Online management shell, you must be a SharePoint Online global administrator.


  1. SharePoint Online objects – are different from their on-premise cousins.  Try comparing the results from returning a SharePoint Online site collection (Get-SPOSite) and the On-Premise equivalent (Get-SPSite).  You’ll notice if you run a Get-Member (e.g. Get-SPSite -Identity | Get-Member) on both, that the SharePoint Online site collection object is actually a Microsoft.Online.SharePoint.PowerShell.SPOSite.  It has no real methods of use, and some properties are read-only; it also has substantially less properties than the on-premise equivalent.


  1. CSOM – If you have been scripting with PowerShell for SharePoint (on-premise) for a few years, then there is every chance that you haven’t had to deal with the CSOM. The Client Side Object Model offers an extensive number of SharePoint objects that you can work with, from your client PC/ any server that has CSOM available.  It does however, require you to really think about how you are going to approach your script as you should understand ‘request batching’.

Back to the scenario!

PowerShell was the preferred choice for this customer scenario; because using a CSV input file it meant that the customer was in control over the provisioning process; and PowerShell is (debatably) easier to read. There is no reason you couldn’t take another approach.

However, as I will iterate several times, there are a few differences to the approach you must take developing a PowerShell script for SPO as opposed to On-premise installations of SharePoint.


– whether you are going to run Cmdlets from the SharePoint Online management shell, use the CSOM in your PowerShell script or the PnP PowerShell Module, you are not running your code directly on the SharePoint server. This means that you must establish a connection with your SPO tenant from your local system, or the system running the code, before you attempt to do anything else.

This is achieved by running the Connect-SPOService Cmdlet, providing the Url of your admin tenant, and the username of your SharePoint Online global administrator account:

$adminCenterUrl = "https://<tenant>" $adminAcct = "admin@<tenant>" Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking Connect-SPOService -Url $adminCenterUrl -Credential $adminAcct


Also, please note that in the code above, I have imported the SharePoint Online management shell module prior to running the Connect-SPOService Cmdlet.

A few things to note here… The script is going to prompt you for the password of the account (credential) that you use.  If you want to run the script unattended (i.e. you won’t be around to type the password in), then I invite you to look into using Windows Credential Manager:

Store credentials using Windows Credential Manager:

  1. Open the control panel (from run: control panel).
  2. Click on User Accounts
  3. Click on Credential Manager
  4. Click on Windows Credentials
  5. Click Add a generic credential
  6. Enter the following information:
  7. Internet or network address – think of this as a reference or alias
  8. User name
  9. Password

You should end up with something like this:


You can now make an adjustment to your script:

Connect-SPOService -Url $adminCenterUrl -Credential SPOAdmin

The script will now refer to the credential that you just created; meaning you can run the script with a scheduled task if needed (please ensure that you have logged on with the account that you intend on using to ensure that a local profile exists).

Input file…

The script that we developed took a CSV file (see below) as its input with the intention of iterating through each line and provisioning a site collection using the OOTB team site.  We achieved this using the Import-Csv Cmdlet:

$build = Import-Csv -Path "C:\temp\SiteCollectionBuild.csv"


Back in the day, customers would often create a site, configure it for a purpose through the user interface, save it as a template, and then make it available to end users. This is fine, however, it does present a few administration challenges.  Nowadays I always recommend to customers that they first define what a site should look like (e.g. document any sub-sites, lists, libraries, content types, web parts etc) and provision them with code; either CSOM or PowerShell. This does mean that you must have the skillset to write the code/ script but in my opinion provides a more controlled method for deploying site collections.  We’ll be talking a bit more about this in the next scenario; however if this approach to site collection ‘templating’ makes you feel nervous, then perhaps have a watch of this channel 9 session where Vesa Juvonen explains it in far more detail than what I am going into here.

How we managed the type of site in the customer scenario that I am walking you through was the addition of a ‘Site template’ column in the CSV file:


Now, in the provisioning code, we can detect the type of site collection that should be provisioned (if $siteCollection.Type -eq “ProjectSite”):

foreach ($siteCollection in $buildList) { $site = $siteCollection.Url Write-Host "Provisioning $site" -ForegroundColor Yellow New-SPOSite -Url $siteCollection.Url -Owner $siteCollection. Owner -Title $siteCollection.Title -StorageQuota 1000 -Template STS#0 -LocaleId 1033 if ($siteCollection.SiteType -eq "ProjectSite") { New-SPOList -Title "Project Risks" -Template GenericList -Url Lists/ProjectRisks -OnQuickLaunch New-SPOList -Title "Project Issues" -Template GenericList -Url Lists/ProjectIssues -OnQuickLaunch New-SPOList -Title "Project Documents" -Template DocumentLibrary -Url Lists/ProjectDocuments -OnQuickLaunch New-SPOList -Title "Project Design" -Template DocumentLibrary -Url Lists/ProjectDesign -OnQuickLaunch }if ($siteCollection.SiteType -eq "TeamSite") { New-SPOList -Title "Team Social" -Template GenericList -Url Lists/TeamSocial -OnQuickLaunch Add-SPOField -List "Team Social" -DisplayName "Event Name" -InternalName "EventName" -Type Text -AddToDefaultView } }


A quick walkthrough of the code above.

We’ve imported the contents of the CSV file into a variable called $buildList. We then iterate through each line of the $buildList, and provision a new site collection using the OOTB team site template (STS#0).

At this point, we check to see what type of customisations we must apply to the site collection. This is managed by the conditional ‘if’ statement:

If ($siteCollection.SiteType -eq “ProjectSite”) { <Apply customisations> }

The code between the curly braces is where we start to provision the relevant artefacts that make up the type of site; e.g. ‘ProjectSite’. In the example that I am using here, you can see that I am provisioning new custom lists and fields. In your scenario you might also be deploying branding, content types, etc.  The SharePoint Online management shell doesn’t have any Cmdlets that provide this functionality, so how is this working?

Office Dev Patterns and Practices…

The script that the customer and I wrote heavily used an amazing community collaboration program called the Office Dev Patterns and Practices.  This is a collection of source code projects that address common challenges/ requirements, and in addition to this, an extremely comprehensive collection of PowerShell Cmdlets designed to help customers be incredibly efficient.

This PowerShell module is how we apply the customisations to our site collection.

The PowerShell Cmdlets are available at GitHub. Here is how to install and start using the module (download it before proceeding J):

Install PnP-PowerShell-master binaries

  1. Download and extract PnP-PowerShell-master from the GitHub repository.
  2. Navigate to the Binaries folder.
  3. Run SharePointPnPPowerShellOnline.msi
  4. Choose (or not) to accept the terms in the license agreement.
  5. Click Install.

Alternatively you could use the Install-Module Cmdlet:

Install-Module SharePointPnPPowerShellOnline

Now you are good to start using the Cmdlets. If you head over to the GitHub repository you’ll be able to review the Cmdlet documentation, which is very thorough and get an idea of what you can now do with your SPO tenant!

The complete code now looks like this:

$adminUrl = "https://<tenant>" $spoAdmin = "admin@<tenant>" $buildList = Import-Csv -Path C:\temp\SPOSiteCollectionBuildList.csv Connect-SPOnline -Url $adminUrl -Credentials $spoAdminforeach ($site in $buildList) { New-SPOSite -Url $site.Url -Owner $site.Owner -Title $site.Title -Template STS#0 -StorageQuota 2000 -LocaleId 1033If ($site.Type -eq 'ProjectSite') { <#Apply customisations, e.g. branding, content types, lists & libraries, etc #> } }

That wraps up the first scenario; I hope that you find it useful.

Scenario two – ongoing provisioning and customisation of site collections


The second scenario that I want to talk about is managing the ongoing requests for site collections.

In the first scenario we discussed a fantastic community program (Office Dev Patterns and Practices). We’re going right back to this now as there is a fantastic code sample that provides us with a solution to provisioning site collections. Please visit this URL.

This is a great example of asynchronous site collection provisioning using a provider-hosted SharePoint add-in. Vesa Juvonen has a very detailed walk through of the code and flow in a channel 9 video.

The flow is remarkably like what we covered in the bulk site collection provisioning scenario:


The process starts off with the user completing a custom site collection request form, like this example (note: the screenshot was taken from a high-trust add-in implementation, so ignore the managed path selection box):


Once the user has submitted the request, the user receives confirmation:


And at this point a list item is created in a site provisioning request list.

That is the first phase of the provisioning process completed.  The second phase is to provision the site collection.

Much like the bulk site collection creation scenario that we covered earlier, we have a couple of options available to us:

  1. A console application
  2. A PowerShell script

Either of the above would be able to build a site collection and apply the customisations depending on the type of site required.

If you are new to provider-hosted add-ins, then here are some useful resources:

Introduction to SharePoint add-ins:

Hands on lab: getting started with SharePoint Add-ins -