Skip to content

Commit c77b9c5

Browse files
erwinvanhunenVesaJuvonen
authored andcommitted
Sitedesign (SharePoint#1112)
* Initial checkin * Updated image * Updated * Updated * updated * small typo fix * fixed markup * fix * typo * markup fixes * typo
1 parent ed9ec83 commit c77b9c5

9 files changed

+257
-2
lines changed
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

docs/declarative-customization/site-design-pnp-provisioning.md

Lines changed: 257 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,260 @@ description: Build a complete site design using the PnP provisioning engine
55
ms.date: 11/19/2017
66
---
77

8-
# Build a complete site design using the PnP provisioning engine
9-
tbd
8+
# Calling the PnP Provisioning Engine from a Site Script
9+
10+
Site Designs offer a great way to standardize the look and feel of your site collections. But if you want to take this one step further, by for instance adding a footer to every page, you might notice that Site Designs do not offer you that option. With the PnP Provisioning engine you can hover create a template which allows you to provision an application customizer to a site. This application customizer then can register a footer on every page. In this article you will learn how to create a site design that applies a PnP Provisioning Template to a site which in turn will add an application customizer to render a footer.
11+
12+
We use the following components in our setup:
13+
14+
1. A Site Design and a Site Script
15+
1. A Microsoft Flow
16+
1. An Azure Storage Queue
17+
1. An Azure Function
18+
1. An SPFX Solution
19+
1. A PnP Provisioning Template
20+
1. A PnP PowerShell Script
21+
1. An AppId and AppSecret with administration rights on your tenant.
22+
23+
We need all these component so we can trigger the PnP Provisioning code in a controller manner right after the site has been created and the Site Design is being applied.
24+
25+
# Setting up App Only Access to your tenant
26+
This requires that you open 2 different pages on your tenant, one located in a normal site, the other located in your SharePoint Administration site.
27+
28+
1. Navigate to following URL in your tenant: https://[yourtenant].sharepoint.com/_layouts/appregnew.aspx (you can navigate to any site, but for now pick the root site)
29+
1. Click both **Generate** buttons
30+
1. Enter a title for your App, for instance "Site Provisioning"
31+
1. Enter **localhost** as the App Domain
32+
1. Enter **https://localhost** as the Redirect URI
33+
34+
![Create App](images/pnpprovisioning-createapponly.png)
35+
1. Click **Create** and copy the values for **Client Id** and **Client Secret** as you will need them later
36+
37+
Now we will trust this app to have the appropriate access to your tenant:
38+
1. Navigate to https://[yourtenant]-admin.sharepoint.com/_layouts/appinv.aspx (notice the -admin in the URL)
39+
1. Paste in the Client Id you copied above into the **App Id** field and select **Lookup**
40+
1. Paste the following XML in the **Permission Request XML** field:
41+
```xml
42+
<AppPermissionRequests AllowAppOnlyPolicy="true" >
43+
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
44+
</AppPermissionRequests>
45+
```
46+
1. Select **Create**
47+
1. You will receive a question if you want to trust this app. Confirm this by selecting **Trust It**
48+
49+
50+
# Creating the Azure Storage Queue
51+
In this scenario we will use an Azure Storage Queue to receive messages from a Microsoft Flow. Everytime a message shows up in the Storage Queue an Azure Function will get triggered to execute a PowerShell script. But let us set up the Storage Queue first:
52+
53+
1. Navigate to the Azure portal at https://portal.azure.com and log in.
54+
1. Choose **+ New**
55+
1. Select **Storage** from the Azure Marketplace listings and select **Storage account - blob, file, table, queue** in the Featured column
56+
1. Provide values for the required fields as requested. Make sure to select **Pin to dashboard** for easy ___location later and click **Create**. The storage account is being created. This can take a few minutes.
57+
1. Open the Storage Account after it has been created and navigate to **Queues** in the navigation
58+
1. Choose **+ Queue** at the top of the main area of the screen.
59+
1. Enter **pnpprovisioningqueue** as the name or enter your own following the naming standard that is enforced. Make a note of the queue name as you need this value later when creating the Azure Function.
60+
1. Navigate to **Access Keys** and make note of the **Storage Account Name** and the **key1 Key value**, you will need those values in the next step where you create the flow.
61+
62+
63+
# The Flow
64+
In order to put a message on the queue we have to create a flow.
65+
66+
1. Navigate to **https://flow.microsoft.com**, log in and create a new flow by clicking **Create from Blank** at the top.
67+
1. Click **Search hundreds of connectors and triggers** to select your trigger
68+
1. Search for **Request** and select **Request - When a HTTP Request is received**
69+
1. Enter the following JSON as your request body:
70+
```json
71+
{
72+
"type": "object",
73+
"properties": {
74+
"webUrl": {
75+
"type": "string"
76+
},
77+
"parameters": {
78+
"type": "object",
79+
"properties": {
80+
"event": {
81+
"type": "string"
82+
},
83+
"product": {
84+
"type": "string"
85+
}
86+
}
87+
}
88+
}
89+
}
90+
```
91+
1. Select **+ New Step** and select **Add an action**
92+
1. Search for **Azure Queues** and select **Azure Queues - Put a message on a queue**
93+
1. Enter a name for the connection, this can be anything descriptive
94+
1. Enter the storage account name you copied in the previous section
95+
1. Enter the storage shared key, which is the value of the **Key1 key value** of your storage account.
96+
1. Click **Create**
97+
1. Select **pnpprovisioningqueue** as the Queue Name.
98+
1. In the body specified in step 4 we specified an incoming parameter called webUrl. We will put the value of that parameter on the queue. Click in the **message** field and select **webUrl** from the Dynamic Content picker.
99+
1. Click **Save Flow**. This will generate the URL we will copy in the next step.
100+
1. Click on the first step in your flow ('When an HTTP request is received') and copy the URL. We will need that to test and later on in our Site Design.
101+
1. Save your flow.
102+
103+
Your flow should look like this:
104+
105+
![Flow](images/pnpprovisioning-flow-overview.png)
106+
107+
# Testing the flow
108+
In order to test your flow you have will have to make a post request. The easiest for that, if you are on a Windows PC, is to use PowerShell:
109+
110+
```powershell
111+
$uri = "[the URI you copied in step 8 when creating the flow]"
112+
$body = "{siteurl:'somesiteurl'}
113+
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body
114+
```
115+
116+
If you now navigate to the main screen of your flow you will see a run history. If everything went okay it should say 'Succeeded'.
117+
Now navigate to the queue you just created in Azure and click **Refresh**. There should be an entry showing that you correctly invoked the Flow.
118+
119+
# Provision the SPFX Solution
120+
For this walkthrough we are going to use an existing SPFX solution which is available at https://github.com/SharePoint/sp-dev-fx-extensions/tree/master/samples/react-application-regions-footer
121+
122+
Follow the steps as provided in the README.MD available in that repository to build and provision your solution.
123+
124+
# Create a PnP Provisioning Template
125+
126+
Copy the following XML to a new file and save the file as FlowDemoTemplate.xml
127+
128+
```xml
129+
<?xml version="1.0"?>
130+
<pnp:Provisioning xmlns:pnp="http://schemas.dev.office.com/PnP/2017/05/ProvisioningSchema">
131+
<pnp:Preferences Generator="OfficeDevPnP.Core, Version=2.20.1711.0, Culture=neutral, PublicKeyToken=3751622786b357c2" />
132+
<pnp:Templates ID="CONTAINER-FLOWDEMO">
133+
<pnp:ProvisioningTemplate ID="TEMPLATE-FLOWDEMO" Version="1" BaseSiteTemplate="GROUP#0" Scope="RootSite">
134+
<pnp:CustomActions>
135+
<pnp:WebCustomActions>
136+
<pnp:CustomAction Name="spfx-react-app-customizer" Description="Custom action for Application Customizer" Location="ClientSideExtension.ApplicationCustomizer" Title="spfx-react-app-customizer" Sequence="0" Rights="" RegistrationType="None" ClientSideComponentId="67fd1d01-84e8-4fbf-85bd-4b80768c6080" ClientSideComponentProperties="{&quot;SourceTermSetName&quot;:&quot;Regions&quot;}" />
137+
</pnp:WebCustomActions>
138+
</pnp:CustomActions>
139+
</pnp:ProvisioningTemplate>
140+
</pnp:Provisioning>
141+
```
142+
143+
>Notice that the template adds a custom action to the the web it is being applied to. It refers to ClientSideComponentId which is the one coming from the SPFX Solution you provisioned earlier. If you run this demo with your own SPFX Solution you will have to change the ClientSideComponentId and optionally the ClientSideComponentProperties attribute values in the XML.
144+
145+
# Create the Azure Function
146+
147+
1. Navigate to the Azure Poral at https://portal.azure.com.
148+
1. Search for 'Function App' and create a new Function App. In the **Storage** field select **Use existing** and select your previously created storage account. Set the other values as required.
149+
1. After the function app has been created open it and select **Functions**, then select **New function**.
150+
![Create a new function](images/pnpprovisioning-create-function.png)
151+
1. From the Language drop-down, select **PowerShell**.
152+
1. Select **QueueTrigger - PowerShell**.
153+
1. Name the function **ApplyPnPProvisioningTemplate**
154+
1. Enter the name of your queue you created in the previous steps.
155+
1. Select **Create**
156+
1. You will be presented with a Editor where you can enter PowerShell Cmdlets. We will now upload the PnP PowerShell module so we can use it in the Azure function.
157+
158+
## Uploading PnP PowerShell for your Azure Function
159+
We first have to download the PnP PowerShell module so you can easy upload it later.
160+
161+
1. Create a temporary folder somewhere on your computer
162+
1. Launch PowerShell and enter
163+
```powershell
164+
Save-Module -Name SharePointPnPPowerShellOnline -Path [pathtoyourfolder]
165+
```
166+
1. The PowerShell module files will be downloaded to a folder inside the folder you just selected.
167+
168+
Now it is time to upload those files so your Azure Function can make use of the module:
169+
170+
1. Navigate to the main page of your Function App and select **Platform Features**
171+
172+
![Navigate to Platform Features](images/pnpprovisioning-platform-features.png)
173+
1. Select **Advanced tools (Kudu)**
174+
175+
![Select Advanced Tools (Kudu))](images/pnpprovisioning-select-kudu.png)
176+
1. On the main Kudu page, select **Debug Console** and pick either **CMD** or **PowerShell**
177+
1. In the upper part of the page you see a file explorer. Navigate to **site\wwwroot\\[nameofyourazurefunction]**
178+
1. Create a new folder and call that folder **modules**
179+
180+
![Create new folder](images/pnpprovisioning-kudu-create-folder.png)
181+
1. In that folder create another folder called **SharePointPnPPowerShellOnline** and navigate to the folder
182+
1. In your File Explorer on your computer navigate to the folder where you downloaded all the PnP PowerShell Module files. Open the
183+
**SharePointPnPPowerShellOnline\2.20.1711.0** folder (notice that depending on when you follow this walkthrough the version number can be different).
184+
1. Upload all files in that folder by dragging and dropping all the files from this folder into the folder in Kudu.
185+
![Create new folder](images/pnpprovisioning-module-files-uploaded.png)
186+
187+
## Finishing the Azure Function
188+
1. Navigate back to your Azure Function and expand the files tab to the right.
189+
190+
![View Files](images/pnpprovisioning-view-files.png)
191+
192+
1. Select **Upload** and upload your provisioning template file you created earlier.
193+
1. Replace the PowerShell script with the following
194+
195+
```powershell
196+
$in = Get-Content $triggerInput -Raw
197+
Write-Output "Incoming request for '$in'"
198+
Connect-PnPOnline -AppId $env:SPO_AppId -AppSecret $env:SPO_AppSecret -Url $in
199+
Write-Output "Connected to site"
200+
Apply-PnPProvisioningTemplate -Path D:\home\site\wwwroot\ApplyPnPProvisioningTemplate\FlowDemoTemplate.xml
201+
```
202+
203+
Notice that we are using 2 environment variables, one called ```SPO_AppId```, the other ```SPO_AppSecret```. In order to set those variables navigate to your main Function App page in your Azure Portal, select **Application Settings** and add two new Application Settings:
204+
205+
1. ```SPO_AppId```: set the value to the Client Id you copied in the first step when creating your app on your tenant.
206+
2. ```SPO_AppSecret```: set the value to the Client Secret you copied in the first step when creating your app on your tenant.
207+
208+
# Creating the Site Design
209+
Open PowerShell and make sure you either have the Microsoft Office 365 Management Shell or the PnP PowerShell Module installed. Both will work, but the cmdlets are named slightly different. In this walkthrough we will use the [PnP PowerShell Cmdlets](https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/?view=sharepoint-ps).
210+
211+
First connect to your tenant using Connect-PnPOnline:
212+
213+
```powershell
214+
Connect-PnPOnline -Url https://[yourtenant]-admin.sharepoint.com
215+
```
216+
217+
Now you can retrieve the existing Site Designs using
218+
219+
```powershell
220+
Get-PnPSiteDesign
221+
```
222+
In order to create a Site Design you first need to create a Site Script. Think of a Site Design as a container which refers to 1 or more Site Scripts.
223+
1. Copy the following JSON code to your clipboard and modify it. Set the url property to the value you copied when creating the flow. The URL looks alike :
224+
225+
```https://prod-27.westus.logic.azure.com:443/workflows/ef7434cf0d704dd48ef5fb6...oke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun```
226+
227+
```json
228+
{
229+
"$schema": "schema.json",
230+
"actions": [
231+
{
232+
"verb": "triggerFlow",
233+
"url": "[paste the workflow trigger URL here]",
234+
"name": "Apply Template",
235+
"parameters": {
236+
"event":"",
237+
"product":""
238+
}
239+
}
240+
],
241+
"bindata": {},
242+
"version": 1
243+
}
244+
```
245+
1. After modifying the JSON by inserting the correct URL to trigger your flow, select it all and copy it again to your clipboard
246+
1. Open PowerShell and enter the following to copy the script into a variable and create the site script
247+
```powershell
248+
$script = Get-Clipboard -Raw
249+
Add-PnPSiteDesign -Title "Apply PnP Provisioning Template" -Content $script
250+
Get-PnPSiteDesign
251+
```
252+
1. You should be presented with a list of one or more site script, including the site script you just created
253+
1. Select the ID of the Site Script you just created and copy it to the clipboard
254+
1. Create the Site Design:
255+
```powershell
256+
Add-PnPSiteDesign -Title "Site with footer" --SiteScriptIds [Paste the ID of the Site Script here] -WebTemplate TeamSite
257+
```
258+
259+
# Concluding
260+
After you created your Storage Queue, you created the app Id for the app only access, you correctly created the Azure Function, you created the Site Design and triggered the correct Microsoft Flow from the Site Design, you are all good to go.
261+
262+
Try creating a new site by navigating to your SharePoint Tenant. Select **SharePoint**, select **Create Site**, Select **Team Site**. Your newly created Site Design should show up as a possible design option. Create your site and notice the Site Design being applied after the site has been created. If you configured it all correctly you should see your flow being triggered. You can check the Run History of the flow if it was executed correctly. As it can take a bit before the PnP Provisioning Template has been applied, it can be that the footer does not show up immediately. Give it a minute and reload your site to check again.
263+
264+

0 commit comments

Comments
 (0)