In Memory PnP Provisioning Templates in PowerShell

Last month we released some new cmdlets really useful to play with the PnP Provisioning Templates in memory. In this post I want to share with you how to leverage them in your everyday life, as well as while creating new PnP Provisioning Templates that you want to submit into the new PnP Templates Gallery.

Load-PnPProvisioningTemplate and Save-PnPProvisioningTemplate

First of all, we released the new Load-PnPProvisioningTemplate cmdlet, which allows you to load in memory a template from a .PNP file (or from an .XML file). Using this cmdlet you can have a in memory object that is an instance of the ProvisioningTemplate type, which we have in the PnP Core library. Here you can see a sample about how to use the Load-PnPProvisioningTemplate cmdlet to load a .PNP file.


$template = Load-PnPProvisioningTemplate -Path .\MyCustomTemplate.pnp

Once you have the in memory object, you can play with it using all of the domain model capabilities that you would have in C#, too. For example, if you are creating a new template that you want to submit into the new PnP Templates Gallery, you can do something like the following sample.


Connect-PnPOnline "https://[yourtenant].sharepoint.com/sites/[YourTemplateSite]"

Get-PnPProvisioningTemplate -Out .\MyTemplate.pnp -IncludeAllTermGroups -IncludeSiteGroups -PersistBrandingFiles -IncludeSiteCollectionTermGroup
$template = Load-PnPProvisioningTemplate -Path .\MyTemplate.pnp

$template.DisplayName = "The name of your custom template"
$template.ImagePreviewUrl = "https://raw.githubusercontent.com/OfficeDev/PnP-Provisioning-Templates/master/RootFolder/Others/YourTemplate/TemplatePreview.png"
$template.Properties["PnP_Supports_SPO_Platform"] = "true"
$template.Properties["PnP_Supports_SP2016_Platform"] = "false"
$template.Properties["PnP_Supports_SP2013_Platform"] = "false"

$template.Security.AdditionalAdministrators.Clear()
$template.Security.AdditionalMembers.Clear()
$template.Security.AdditionalOwners.Clear()
$template.Security.AdditionalVisitors.Clear()

Save-PnPProvisioningTemplate -Out .\MyTemplate.pnp -InputInstance $template

As you can see in the code sample above, first of all I get a template from a site, using the well-known Get-PnPProvisioningTemplate. Afterwards, I load the resulting file into memory, by using the Load-PnPProvisioningTemplate cmdlet. Once I have the template in memory, I set the DisplayName and the ImagePreviewUrl properties. Moreover, I configure three custom properties, in order to define what are the target platforms of my template. Lastly, I clear the collections of Administrators, Members, Owners, and Visitors of the template. This way, I will export the security settings, like custom groups or roles, but I will remove any explicit reference to users of my tenant, in order to keep the template clean and re-usable in any other tenant.
Last but not least, I use the new Save-PnPProvisioningTemplate cmdlet to save the template file back to my file system.
Now the template is ready to be published into the PnP Templates Gallery.

Some of the above properties, can also be configured using the Set-PnPProvisioningTemplateMetadata cmdlet, which simply targets the use case of setting the DisplayName, the ImagePreviewUrl, and the custom properties.

It is interesting to notice that another suitable alternative to get an in memory template object from a live site is to use the following syntax for the Get-PnPProvisioningTemplate cmdlet.


$template = Get-PnPProvisioningTemplate -OutputInstance -IncludeAllTermGroups -IncludeSiteGroups -PersistBrandingFiles -IncludeSiteCollectionTermGroup

Notice the -OutputInstance parameter, which is alternative to the -Out parameter, and it simply instructs the cmdlet to return the template as an in memory object, instead of creating a file in the file system.

New-PnPProvisioningTemplate

If you want to start from scratch with a fresh new and empty template, you can use the New-PnPProvisioningTemplate cmdlet, instead. This cmdlet will create an in memory new and empty ProvisioningTemplate object for you. Here you can see a sample syntax to use it.


$template = New-PnPProvisioningTemplate

Once you have the in memory template, you can play with it, as like as we did in the previous section, and when you will be ready you will be able to save it, still using the Save-PnPProvisioningTemplate.

Add-PnPFileToProvisioningTemplate and Remove-PnPFileFromProvisioningTemplate

Often, when you create a custom template, you also need to handle files like images, JavaScript, CSS, etc. within the target template. If the template is stored as a .PNP file, it is not that easy for you to manually add or remove files to the OpenXML archive. That’s why we provide also the two Add-PnPFileToProvisioningTemplate and Remove-PnPFileFromProvisioningTemplate cmdlets. As their names imply, the former adds a new file to the .PNP file, while the latter removes an already existing file.
The interesting part of the story about these two cmdlets is that they not only handle the physical file from an OpenXML archive perspective, but they also add/remove the file to/from the collection of files of the related Provisioning Template. Thus, let’s assume that you want to add a CSS file to a .PNP template, in order to copy it into the SiteAssets folder of any target site. In the following code sample you can see how to achieve this result.


Add-PnPFileToProvisioningTemplate -Path .\MyTemplate.pnp -Source .\custom-style.css -Folder "SiteAssets"

And here you can see how to remove a file from a .PNP template OpenXML archive.


Remove-PnPFileFromProvisioningTemplate -Path .\MyTemplate.pnp -FilePath "custom-style.css"

Wrap Up

Using PowerShell and the cmdlets that we just saw, you can greatly play in memory with the PnP Provisioning Templates, and you can use PowerShell as a very flexible “development tool” for provisioning sites and content.
Thus, have fun and let us (http://aka.ms/SharePointPnP) know what you think about these new capabilities.