SharePoint Site Designs and Site Scripts are changing the way end-users interact with SharePoint. These relatively new SharePoint features let users create and deploy a site based on a customized template in just a few clicks. They reduce the time spent on site creation by introducing automation but also help standardize sites based on department or purpose use. If you’re curious about SharePoint Site Designs and Site Scripts and want to get started, read on!
But before we dive in let me take you back a couple of weeks.
It was a hot sunny afternoon and I was enjoying grilling burgers for a family gathering, when a thought came to mind: making SharePoint sites (my day job) isn’t all that different from making burgers. Weird, right?
Well, a burger typically contains two base ingredients: a patty and a bun. Past that, it’s all about customization and adding your personalized flavour: condiments, veggies, cheese and additional meat. This is in fact a lot like SharePoint. SharePoint’s base is made up of the Site and its Security Groups, while the individual flavours come from customizable elements like custom content types, custom columns, custom libraries, or custom lists.
As I continued to think about the similarities between making a burger and creating a SharePoint site, I recalled a capability that I used a lot back in SharePoint Server 2007 – SharePoint Server 2010. Those older SharePoint versions allowed you to save a site as a template. It was a relatively straightforward approach that helped jumpstart the site creation process and reduced the redundant configuration tasks of setting up a site. It was like picking up the perfect, customized straight from a production line.
In SharePoint 2007, when you navigated to Site Settings, and clicked the Save Site as a Template an exportable SharePoint Template (STP) file would be available. Whereas in SharePoint 2010, this approach created an exportable Windows SharePoint (WSP) file. Both methods were helpful in deploying packaged functionality to SharePoint. The difference between the two file formats was that Microsoft was moving towards a solution framework for SharePoint 2010 where were kept within a Site Collection gallery rather than in a Farm gallery. But there was a caveat to this templating approach. SharePoint Site Collection required the Publishing site feature to remain deactivated.
Fast forward to SharePoint Online with its Site Designs and Site Scripts. I like to think of them as an alternative to provisioning site artifacts to Modern SharePoint sites. Site Designsare a template of sorts. As of August 2019, you can create a maximum of a 100 Site Designs and 100 Site Scripts in an Office 365 tenant.
A Site Design is created in PowerShell format. It can store multiple Site Scripts that contain sets of configuration actions. Actions or sub actions can involve operations such as creating lists, creating libraries, creating content types, creating columns, calling a flow, joining site to a hub site, and granting users to a security role. They can be selected and applied to a site by a Site Owner. When creating a Site Design, you’ll specify the Title, Description, Thumbnail Picture, and Web template (Team Site or Communication Site).
A Site Script is created in a JSON format. JSON stands for JavaScript Object Notation structures information in a way that’s easy to read at a glance. There are good examples of SharePoint Site Scripts on GitHub. You can review examples and combine them to create your own Site Script. You can also use third party tools such as Site Designs Studio or SharePoint Site Designer to reduce the complex task to construct a JSON object.
Creating a Site Design and Site Script can be a bit complex as it requires some upfront time to determine what configurable actions you want to perform. Actions are specified by the use of “verb” value. The JSON schema for Site Script is as follows:
{ "$schema": "schema.json", "actions": [ ... <one or more verb actions> ... ], "bindata": { }, "version": 1 };
{ "$schema": "schema.json", "actions": [ ... <one or more verb actions> ... ], "bindata": { }, "version": 1 };
Below is a list of the actions that can be performed:
If your requirements are complex, you can use Microsoft Flow to expand the capabilities of Site Designs and Site Scripts. You can learn more about the syntax on how to apply these actions to your Site Script, by reading the JSON schema reference.
I’ve created a sample below to demonstrate how to construct a Site Script. In my example, this Site Script will contain the following actions and for my use case scenario will be applicable for new sites created for the Information Services department.
{ "$schema": "schema.json", "actions": [ { "verb": "createSiteColumn", "fieldType": "User", "internalName": "PolicyOwner", "displayName": "Policy Owner", "isRequired": false, "group": "DevFacto IS Custom Columns", "enforceUnique": false }, { "verb": "createSiteColumnXml", "schemaXml": "<Field Type=\"Choice\" DisplayName=\"Policy Type\" Required=\"FALSE\" Format=\"Dropdown\" StaticName=\"PolicyType\" Name=\"PolicyType\"><Default></Default><CHOICES><CHOICE>Policy</CHOICE><CHOICE>Procedure</CHOICE></CHOICES></Field>" }, { "verb": "createSiteColumn", "fieldType": "DateTime", "internalName": "PolicyExpiryDate", "displayName": "Policy Expiry Date", "isRequired": false, "group": "DevFacto IS Custom Columns" }, { "verb": "createContentType", "name": "Policy", "description": "Policy Document", "parentName": "Document", "hidden": false, "subactions": [ { "verb": "addSiteColumn", "internalName": "PolicyOwner" }, { "verb": "addSiteColumn", "internalName": "PolicyType" }, { "verb": "addSiteColumn", "internalName": "PolicyExpiryDate" } ] }, { "verb": "createSPList", "listName": "Deliverable Documents", "templateType": 101, "subactions": [ { "verb": "setDescription", "description": "Project team can use this Deliverable Documents Library to store deliverable documents." } ] }, { "verb": "createSPList", "listName": "Tasks", "templateType": 107, "subactions": [ { "verb": "setDescription", "description": "Use the Tasks list to monitor and manage tasks within the Project." } ] }, { "verb": "createSPList", "listName": "Calendar", "templateType": 106, "subactions": [ { "verb": "setDescription", "description": "Use the Calendar list to track upcoming events and deadlines relevant to the Project." } ] }, { "verb": "createSPList", "listName": "Documents", "templateType": 101, "subactions": [ { "verb": "addContentType", "name": "Policy" }, { "verb": "addSPView", "name": "By Policies", "viewFields": [ "Name", "PolicyOwner", "PolicyType", "PolicyExpiryDate", "Modified", "Editor", "Version" ], "query": "<OrderBy><FieldRef Name=\"Name\" Ascending=\"FALSE\" /></OrderBy><GroupBy Collapse =\"TRUE\"><FieldRef Name =\"PolicyType\"/></GroupBy><Where><Eq><FieldRef Name=\"ContentType\"/><Value Type=\"Computed\">Policy</Value></Eq></Where>", "rowLimit": 100, "isPaged": true, "makeDefault": false } ] }, { "verb": "addNavLink", "url": "/Deliverable%20Documents", "displayName": "Deliverable Documents", "isWebRelative": true }, { "verb": "addNavLink", "url": "/Lists/Tasks", "displayName": "Tasks", "isWebRelative": true }, { "verb": "addNavLink", "url": "/Lists/Calendar", "displayName": "Calendar", "isWebRelative": true }, { "verb": "joinHubSite", "hubSiteId": "18414d04-6d98-4295-a3e7-b92528130e5b", "name": "Information Services" }, { "verb": "addPrincipalToSPGroup", "principal": "adam.tobias@devfacto.com", "group": "Owners" }, { "verb": "addPrincipalToSPGroup", "principal": "nameofsecuritygroup@devfacto.com", "group": "Owners" }, { "verb": "addPrincipalToSPGroup", "principal": "nameofuser@devfacto.onmicrosoft.com", "group": "Members" } ], "bindata": { }, "version": 1 }
{ "$schema": "schema.json", "actions": [ { "verb": "createSiteColumn", "fieldType": "User", "internalName": "PolicyOwner", "displayName": "Policy Owner", "isRequired": false, "group": "DevFacto IS Custom Columns", "enforceUnique": false }, { "verb": "createSiteColumnXml", "schemaXml": "<Field Type=\"Choice\" DisplayName=\"Policy Type\" Required=\"FALSE\" Format=\"Dropdown\" StaticName=\"PolicyType\" Name=\"PolicyType\"><Default></Default><CHOICES><CHOICE>Policy</CHOICE><CHOICE>Procedure</CHOICE></CHOICES></Field>" }, { "verb": "createSiteColumn", "fieldType": "DateTime", "internalName": "PolicyExpiryDate", "displayName": "Policy Expiry Date", "isRequired": false, "group": "DevFacto IS Custom Columns" }, { "verb": "createContentType", "name": "Policy", "description": "Policy Document", "parentName": "Document", "hidden": false, "subactions": [ { "verb": "addSiteColumn", "internalName": "PolicyOwner" }, { "verb": "addSiteColumn", "internalName": "PolicyType" }, { "verb": "addSiteColumn", "internalName": "PolicyExpiryDate" } ] }, { "verb": "createSPList", "listName": "Deliverable Documents", "templateType": 101, "subactions": [ { "verb": "setDescription", "description": "Project team can use this Deliverable Documents Library to store deliverable documents." } ] }, { "verb": "createSPList", "listName": "Tasks", "templateType": 107, "subactions": [ { "verb": "setDescription", "description": "Use the Tasks list to monitor and manage tasks within the Project." } ] }, { "verb": "createSPList", "listName": "Calendar", "templateType": 106, "subactions": [ { "verb": "setDescription", "description": "Use the Calendar list to track upcoming events and deadlines relevant to the Project." } ] }, { "verb": "createSPList", "listName": "Documents", "templateType": 101, "subactions": [ { "verb": "addContentType", "name": "Policy" }, { "verb": "addSPView", "name": "By Policies", "viewFields": [ "Name", "PolicyOwner", "PolicyType", "PolicyExpiryDate", "Modified", "Editor", "Version" ], "query": "<OrderBy><FieldRef Name=\"Name\" Ascending=\"FALSE\" /></OrderBy><GroupBy Collapse =\"TRUE\"><FieldRef Name =\"PolicyType\"/></GroupBy><Where><Eq><FieldRef Name=\"ContentType\"/><Value Type=\"Computed\">Policy</Value></Eq></Where>", "rowLimit": 100, "isPaged": true, "makeDefault": false } ] }, { "verb": "addNavLink", "url": "/Deliverable%20Documents", "displayName": "Deliverable Documents", "isWebRelative": true }, { "verb": "addNavLink", "url": "/Lists/Tasks", "displayName": "Tasks", "isWebRelative": true }, { "verb": "addNavLink", "url": "/Lists/Calendar", "displayName": "Calendar", "isWebRelative": true }, { "verb": "joinHubSite", "hubSiteId": "18414d04-6d98-4295-a3e7-b92528130e5b", "name": "Information Services" }, { "verb": "addPrincipalToSPGroup", "principal": "adam.tobias@devfacto.com", "group": "Owners" }, { "verb": "addPrincipalToSPGroup", "principal": "nameofsecuritygroup@devfacto.com", "group": "Owners" }, { "verb": "addPrincipalToSPGroup", "principal": "nameofuser@devfacto.onmicrosoft.com", "group": "Members" } ], "bindata": { }, "version": 1 }
Next, we’ll need to then associate this to a Site Design. To do so, we can create Site Design and associate the Site Script by executing the PowerShell below:
$siteScriptFile = "\SiteScripts\IS-SiteScript.json" # Source path where you stored your Site Scripts $webTemplate = "64" #64 = Team Site, 68 = Communication Site, 1 = Groupless Team Site $siteScriptTitle = "IS Project Site Script" $siteDesignTitle = "IS Project Site Design" $siteDesignDescription = "IS project site design with Content Types, Site Columns, additional libraries, lists, and creation of folders." $previewImageUrl = "" # can be left blank or you can add a custom image. $siteScript = (Get-Content $siteScriptFile -Raw | Add-SPOSiteScript -Title $siteScriptTitle) | Select -First 1 Id Add-SPOSiteDesign -SiteScripts $siteScript.Id -Title $siteDesignTitle -WebTemplate $webTemplate -Description $siteDesignDescription
$siteScriptFile = "\SiteScripts\IS-SiteScript.json" # Source path where you stored your Site Scripts $webTemplate = "64" #64 = Team Site, 68 = Communication Site, 1 = Groupless Team Site $siteScriptTitle = "IS Project Site Script" $siteDesignTitle = "IS Project Site Design" $siteDesignDescription = "IS project site design with Content Types, Site Columns, additional libraries, lists, and creation of folders." $previewImageUrl = "" # can be left blank or you can add a custom image. $siteScript = (Get-Content $siteScriptFile -Raw | Add-SPOSiteScript -Title $siteScriptTitle) | Select -First 1 Id Add-SPOSiteDesign -SiteScripts $siteScript.Id -Title $siteDesignTitle -WebTemplate $webTemplate -Description $siteDesignDescription
If successful, the console will return the following result:
Now that we have our Site Design and Site Script deployed in our Office 365 tenant, it can be programmatically executed by a user through PowerShell or REST. Users can create a new site by clicking Create Site and then selecting the right design.
Users can also apply the newly built site design to an existing site. To do so, the user would navigate to the site, click on the Settings icon on the top right corner, and click Site Designs.
A Site Design pane will appear on the right side of the screen showing you all the available site designs. Select a Site Design you want to apply to the existing site.
Then, click the Apply to Site button.
After clicking the Apply to site button, a progress bar will appear letting the user know what action was completed, is pending, or in the queue to perform.
When all the actions are completed, the end user can click View updated site.
The user will be directed to the updated site with configured actions applied from the Site Script that is associated to the chosen Site Design.
Another option mentioned earlier would be calling the Site Design programmatically through REST. Below is an example in Microsoft Flow using the Send an HTTP request to SharePoint action.
This approach also makes it possible to restrict the users that can select and apply site designs to a site. Whether it’s a governance requirement or a security concern, whatever the reason may be, you can scope the Site Design to include defined users or security groups.
$adminSiteUrl = "https://tenant-admin.sharepoint.com" $siteDesignId = " 8245449c-9d0f-4311-b2dc-8dcb2483cb01" $principals = "Security Group Name", "user@mytenant.onmicrosoft.com" $cred = Get-Credential Connect-SPOService $adminSiteUrl -Credential $cred Grant-SPOSiteDesignRights -Identity $siteDesignId -Principals $principals -Rights View Get-SPOSiteDesignRights -Identity $siteDesignId
$adminSiteUrl = "https://tenant-admin.sharepoint.com" $siteDesignId = " 8245449c-9d0f-4311-b2dc-8dcb2483cb01" $principals = "Security Group Name", "user@mytenant.onmicrosoft.com" $cred = Get-Credential Connect-SPOService $adminSiteUrl -Credential $cred Grant-SPOSiteDesignRights -Identity $siteDesignId -Principals $principals -Rights View Get-SPOSiteDesignRights -Identity $siteDesignId
So, you’re probably asking yourself what are the advantages and disadvantages of Site Designs/Site Scripts? Let’s take a look below.
In conclusion, Site Designs/Site Scripts don’t replace SharePoint CSOM or PowerShell PnP, but rather bring another option to the table. You’ll need to determine if Site Designs and Site Scripts are right for your organization based on your requirements and how your organization addresses creating and applying changes to a site.
Personally, I think Site Designs and Site Scripts are quite powerful and love how the wizard-like interface makes it easy for users to apply to a new or existing site for easier adoption. The only thing that would make it better is a similar wizard-like experience for the creating Site Designs and Site Scripts. That way, users wouldn’t need to create JSON schema files for the Site Script and use PowerShell for the deploying of the Site Design.
I hope this post provided you with insights about the value of Site Designs and Site Scripts. If you would want to learn more about this topic, I’d love to chat over a perfect burger. Cheers!