Earlier I introduced the Office Dev PnP Program and Office Dev PnP Provisioning. I mentioned the great functionality to define a template of a site or site collection in XML. In this blog post I will explain how to extract and apply XML templates with Office Dev PnP Provisioning using the Office 365 Developer Patterns and Practices PowerShell Cmdlets, from now on referred to as PnP Provisioning cmdlets.
PnP Provisioning cmdlets?
Basically the PnP Provisioning cmdlets are an extension to the standard CSOM functionality Microsoft offers. PnP Provisioning cmdlets are specifically designed to provision and modify artifacts in SharePoint Online using CSOM.
Preparing you environment
Of course, you first need to prepare your environment before you are able to use the PnP Provisioning cmdlets. Although the cmdlets are designed for SharePoint Online, it is also possible to use the cmdlets on an on-premises environment. The on-premises variant of the cmdlets is another build, because SharePoint 2013 uses an older version (15) of CSOM whereas SharePoint Online uses the newest version (16) of CSOM. Therefore you first need to determine the right build of the PnP Provisioning cmdlets:
- msi for SharePoint 2013
- msi for SharePoint Online
Next download the latest release of the right build from the release page and run the install. Erwin van Hunen created a blog post about running the install and connecting to the SharePoint environment with Connect-SPOnline. Complete the installation as described in his blog post.
Connect and get the context
As mentioned earlier you can use Connect-SPOnline to connect to SharePoint. Connect-SPOnline creates the context you need to acquire or apply the XML template.
To ease your life, use the Windows Credential Manager to store your credentials. This way you don’t have to fill in your credentials each time you connect to SharePoint with Connect-SPOnline without having to hardcode your credentials in the script.
Almost ready to extract
Once you have the necessary context you are almost ready to extract a template. One thing is missing: the source to extract from. The source is a SharePoint site which is designed as the blueprint of to be provisioned sites. Create this source site exactly as you want this blueprint to be. Do this in a root site (of a separate site collection) for best results. In a subsite it is possible that some artifacts are not extracted properly. Things like site columns are only obtained correctly when the source is a root site. Once you created the source site, you are ready to extract.
Extract a XML template with Get-SPOProvisioningTemplate
Now you have a source site as blueprint, you need the context of the source site. So if /sites/MySourceSite is the source site your code should look like something like this:
# Define variables $tenant = "tenantName"; $sourceSite = "/sites/MySourceSite"; $path = "C:\MyPnPTemplate.xml"; # Get context $webUrl = "https://{0}.sharepoint.com{1}/" -f $tenant, $sourceSite; Write-Output $("Connecting to {0}..." -f $webUrl); Connect-SPOnline -Url $webUrl -Credentials WCMStoredCredentials; Write-Output "Context obtained";
To make the script easier to use with different environments, I used a $tenant and a $sourceSite variable to define the name of the SharePoint tenant and the source site respectively. Later these variables are used in $webUrl to define the complete URL of the source site. The $path variable is to define the location where the XML template should be saved. Last thing to do is the actual extraction with Get-SPOProvisioningTemplate and save the XML template to the given path:
# Extract template Write-Output "Creating PnP template..."; Get-SPOProvisioningTemplate -Out $path; Write-Output $("Template saved to {0}" –f $path); Combined the code looks like this: # Define variables $tenant = "tenantName"; $sourceSite = "/sites/MySourceSite"; $path = "C:\MyPnPTemplate.xml"; # Get context $webUrl = "https://{0}.sharepoint.com{1}/" -f $tenant, $sourceSite; Write-Output $("Connecting to {0}..." -f $webUrl); Connect-SPOnline -Url $webUrl -Credentials WCMStoredCredentials; Write-Output "Context obtained"; # Extract template Write-Output "Creating PnP template..."; Get-SPOProvisioningTemplate -Out $path; Write-Output $("Template saved to {0}" –f $path);
Apply a XML template with Apply-SPOProvisioningTemplate
Applying a XML template is as easy as extracting a XML template. Obtaining the context works the same, but instead of a defining source site, you define a target site. With Get-SPOWeb you get the context of the subsite. Now it’s time to apply the XML template with Apply-SPOProvisioningTemplate:
# Define variables $tenant = "tenantName"; $targetSite = "/sites/MyTargetSite"; $path = "C:\MyPnPTemplate.xml"; # Get context $webUrl = "https://{0}.sharepoint.com{1}" -f $tenant, $ targetSite; Write-Output $("Connecting to {0}..." -f $webUrl); Connect-SPOnline -Url $webUrl -Credentials WCMStoredCredentials; Write-Output "Context obtained"; # Get web object $web = Get-Web; # Apply template Write-Output $("Applying PnP template [{0}] to site [{1} ({2})]..." -f $path, $web.Title, $web.Url); Apply-SPOProvisioningTemplate -Web $web -Path $path; Write-Output "Template created";
After some time (seconds or minutes, depending on the size of the template and the connection speed) your template will be successfully applied to the site.
In the sample a $web context is used as input for Apply-SPOProvisioningTemplate, but when no web context is given, Apply-SPOProvisioningTemplate will use the context of Connect-SPOnline (which in this sample is indeed the same context as $web). The code will then look like:
Apply-SPOProvisioningTemplate -Path $path;
The XML template is now applied on an existing site. It could also be applied to a new site by creating the new site first with New-SPOWeb using the standard blank (STS#1) template.
# Define variables $tenant = "tenantName"; $targetSite = "/sites/MyTargetSite"; $path = "C:\MyPnPTemplate.xml"; $siteTitle = "My Target Site"; $siteDescription = "My Target Site Description"; $siteUrl = "MyTargetSite"; # Get context $webUrl = "https://{0}.sharepoint.com/{1}" -f $tenant, $targetSite; Write-Output $("Connecting to {0}..." -f $webUrl); Connect-SPOnline -Url $webUrl -Credentials WCMStoredCredentials; Write-Output "Done"; # Create new subsite $web = New-SPOWeb -Title "$siteTitle" -Url "$siteUrl" -Description "$siteDescription" -Locale 1043 -Template "STS#1" # Apply template Write-Output $("Applying PnP template [{0}] to site [{1} ({2})]..." -f $path, $web.Title, $web.Url); Apply-SPOProvisioningTemplate -Web $web -Path $path; Write-Output "Done";
This is also a good example of a situation when you actually need the $web context. In the coming blog posts I will explain how to create a XML template yourself.