Wednesday, 8 May 2019

Speaking at the European Collaboration Summit 2019 and SharePoint Saturday London!


In a few short weeks I'll be speaking at the European Collaboration Summit in Germany. This is a fantastic event with stellar speakers and quite a few folks from Microsoft. The event team go out of their way to make the show a fantastic learning event for attendees, and I highly encourage Office 365/SharePoint/Azure folks based in Europe to try and get there. Topics covered in depth will include Teams, Azure, SharePoint, Yammer and more - covered from business and technical viewpoints.

My session is:

Top Office 365 Development techniques to master - the hitlist


Things move fast in Office 365 development, and as Microsoft evolve the platform and APIs, new techniques and approaches become available all the time. As the head of a talented dev team, I regularly update my list of techniques that I believe are essential to have good capability building Office 365 solutions. Between SPFx, the Graph, Teams development, coding in Azure Functions and building solutions in PowerApps and Flow, let's walk through some high-value scenarios in mid-2019 that should be in every experienced coder's toolbox, with demos and code sample for each. This session will help you close any skills gaps, and should be a great conversation with some bright minds in the room. 

Some of the techniques I consider to be on the list include:
  • Working effectively with the Microsoft Graph from Postman (and coding against the JSON returned)
  • Calling a back-end API (e.g. an Azure Function) securely from SharePoint, with SPFx isolated web parts and AAD auth
  • Templating SharePoint sites effectively with Site Designs and PnP templates
  • Rich PowerApps which can capture images or signatures 
Of course, there are a *million and one* scenarios you could consider for such a list! However, I think any developer with those in the toolbox is quite well-equipped across some important building blocks. I'll also talk about some other techniques such as templating Teams, calling APIs from Flow, offline support in PowerApps and more.

Overall, I think it's important to be quite well-rounded these days - if you're purely a code-oriented developer with little knowledge of PowerApps and Flow, then frankly you (and your clients) are missing out. As ever, being able to select the right architecture and solution approach is vital, and knowing how the technologies fit together (in some detail) is important here.

More details on the European Collaboration Summit 2019:
ECS 2019 is being held in Wiesbaden, Germany (near Frankfurt) between May 27-29. Ticket prices are *extremely* reasonable for an event of this level! Read more at: www.collabsummit.eu

Also available in London!


If you can't make it to ECS, another great event where I'm giving the same talk is SharePoint Saturday London 2019! This is my home turf, and just like past occasions, there are lots of top-ranked speakers from around the world presenting.

For more details on SharePoint Saturday London:

The event is being held on June 1st in central London - and it's free of course! Read more at www.spsevents.org/city/London/home

Hope to see you at one of the events!

Tuesday, 23 April 2019

SPFx isolated web parts – the right way to connect to your back-end API

It’s now possible for SharePoint/Office 365 developers to create *isolated* web parts, thanks to the recent release of SPFx 1.8. If your web part needs permission to talk to a back-end API or the Graph, you should strongly consider making your web part isolated. Simply having the Azure Function or other API secured with AAD authentication isn’t enough. In this post, I’ll talk through some of the details of an SPFx web part which can perform a privileged operation in your Office 365 environment (creating a Microsoft Team from a template in this case) – and therefore is something we should take steps to secure. Specifically, we want to protect the access token which is used behind the scenes, and ensure no other web parts can “piggy-back” onto the permissions we are using. Without isolated web parts:

  • Any other code on the page (perhaps from a 3rd party supplier) can sniff the access token, and potentially use it maliciously, depending on what permissions it has
  • Any standard SPFx web part can use the permissions from any other – meaning it’s a “highest common denominator” situation, where all standard SPFx web parts in the environment have the same permissions i.e. the highest that have ever been granted
These can be very valid security concerns – you’d want to be very sure about which permission levels have been granted to SPFx otherwise, and exactly what code you have in your environment. Isolated web parts can often be part of the answer in ensuring your Office 365 environment is not inadvertently insecure.

But how exactly do isolated web parts help?

Isolated web parts explainer

Web parts from an isolated SPFx package run on a unique domain, hosted within an iFrame - the permissions granted apply only to code hosted on that domain. Since regular SPFx web parts run on your *.sharepoint.com domain, the granted permissions do not apply there. And since any other SPFx isolated web parts run on a different unique domain, they don't apply there either. Essentially, the shared application principal for SPFx is not used – instead, an AAD app registration dedicated to this SPFx solution is created and used for authentication. Note this scope isn’t the individual web part, but the containing solution package. This is fine however - if you have an untrusted source contributing code to the very same solution/codebase, then you probably have bigger security and governance challenges to deal with quite frankly.

So when an isolated web part is added to your pages, you’ll see the containing iFrame – notice the source:

The source is a dynamically-created domain to represent this solution package – similar to how the old “SharePoint-hosted apps” model used to provide a separate domain for code-hosting for those who remember that. In the AD portal, you’ll also see the app registration that has been created on your behalf for this SPFx solution package:


It has a bunch of redirect URIs automatically configured, to support SPFx calling from the domain your iFramed web part code will use:

The combination of the unique domain/iFrame and dedicated AAD app registration gets around the previous trade-offs that came with SPFx and AAD integration, where a permission request for a given security scope (say, Group.ReadWrite.All – which would allow new Office 365 Groups or Microsoft Teams to be created or existing ones updated, as well as a bunch of other operations) would apply to *all* SPFx web parts and extensions in the tenant, not just the one that needed it.

So, you can see that any web part that performs a highly-privileged operation (e.g. creating a Team in my case, to continue that example) really should be isolated – especially if there’s a chance that your tenant could host web parts from different teams or providers. In this way. I am guaranteed that the only thing that can call my API is the web part(s) that are intended to - no other code in my Office 365 tenant will be able to.

Of course, without the iFrame that comes with isolated web parts, the auth token is right there in the page to be sniffed by anything else on the page:

So, isolated web parts are a good thing.

Before we talk about what configuration is needed where, let’s consider some user interface things for a second.

UI considerations with isolated web parts

Imagine you want to use some Office UI Fabric (OUIF) components within an isolated web part. That’s fine, but you need to consider the fact that your content is displayed within an iFrame which has certain dimensions – and certain UI components don’t play well with that. Let’s say we want to use a Dialog from OUIF React. In the example below, I have a button to pop the dialog, and for illustration I’ve also added a black border to my web part so you can see how big it is in the page:


When the button is pressed we get this:


Whoah – doesn’t look right. Of course, that’s because the Dialog is appearing within the iFrame only. If I extend the web part dimensions, the Dialog can be fully shown – effectively I almost need to “reserve” space on the page for any elements which are initially not visible:


And it’s the same with a Fabric React Panel. With a small web part, it’s not clear what’s going on at all:


But in this case, even using a taller web part doesn’t really help – you can see a bit more of the Panel, but since a Panel uses the full height of the screen you still won't see it all:


So, perhaps isolated web parts work better when the content is right there in the page, rather than with any elements that appear on user interaction. You’ll need to design the UI of isolated web parts accordingly.

Creating an isolated web part

Isolated web parts are created by specifying “isDomainIsolated” is true in the package-solution.json file in your SPFx project. This tells SPFx that all web parts in this package should be isolated from other web parts (but not from each other – you’d need separate projects for that):


You can specify this at any time, but the Yeoman Generator helps you out by asking this question when you’re creating a new SPFx project. A “yes” to the following question will result in the config above:


Key elements

I was slightly confused as what values I need in certain config values at first. Knowing that a new AAD app registration is created for me in AAD, is it THAT client ID that I need to use in my code? Or is it the client ID of the AAD app registration that my Azure Function uses internally to actually make calls against the Graph (since the pattern in my case is SPFx web part -> Azure Function -> Graph calls)?

The documentation essentially says that, “everything is done as normal”, but I was still a bit confused.

Here’s a summary of what you need to do:
  • Create your Azure Function app and secure with AAD authentication
  • Create your SPFx project and answer “yes” to the question about isolated web parts (or add “isDomainIsolated” : true in your existing package-solution.json file)
  • Add an appropriate “webApiPemissionRequests” section to your package-solution.json file (more on this next)
  • Write code in your SPFx web part using AadHttpClientFactory to perform the authentication against your API
  • Deploy the package to the app catalog (even if only debugging at this stage)
  • Approve the permission requests on the API management page in tenant administration
Let’s go into a bit more detail:
In package-solution.json
Add an entry into the “webApiPemissionRequests” section which corresponds to your server-side API/Function, with a scope of “user_impersonation”. IMPORTANT:
  • The AAD app reg/API to list is the one for your function app, NOT:
    • The dynamically-created AAD app for your isolated web part (e.g. “cob-teamcreatorwp” in my case)
    • Some other AAD app you have which you may be using inside your Function, but has no bearing on communication from the web part to the API (e.g. “COB Graph Access” in my case)
Your package-solution.json should therefore look something like this:

In your SPFx code
In your code, you’ll have something like this – notice that the Client ID to pass to AadHttpClientFactory is (again) the one for the Function app:

Approving the permissions:
The solution package then needs to be deployed to your tenant, and consent granted.
  • Add the package to the app catalog – notice the message that further action is needed on the Permissions Management Page, with a note about the specific permission to approve:

  • If you then head to that page, you’ll see the permission to approve:  

  • Hit the approve button if you’re satisfied with the permissions being granted. In this case, the permission will be scoped only to web parts within this SPFx package – other web parts in the tenant will not be able to use it.

Summary

There are lots of ways you can stay assured of what custom code can do in your Office 365/SharePoint Online environment, but isolated web parts can be really helpful in minimising the potential for exploits. Without them, maybe something else could call your back-end API without you realizing it. Notably, Microsoft still have some work to do in lowering the code permissions required for certain operations (e.g. posting a message in a Teams channel requires Group.ReadWrite.All, and certain Planner actions are similar), but hopefully that will come soon.

It’s also worth considering exactly what permissions are required where. If you make calls to the Graph via a back-end API, then maybe SPFx only needs permissions to call *your* API, and the separate AAD app registration used by your back-end has the permissions to take real action. Obviously that can reduce the surface area considerably.

Either way, isolated web parts can play an important role in balancing security with functionality in Office 365. I'll publish the full source code for my Teams Creator web part and Azure Function API in a future article.

Further reading:
https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/isolated-web-parts

Friday, 8 March 2019

Create Microsoft Teams from a template

One thing we’ve been waiting for is the ability to create many Teams from a template, in the same way that many organisations do with SharePoint sites. Microsoft have now released this (in preview at the time of writing), and we can define a template in JSON defining exactly what the Team should look like, including the channels, tabs, installed apps, owners and various configuration settings. This is great, because we can now work on scenarios such as a project team, which might have channels for “Technical”, “Account management”, “Project delivery”, “Client success” and so on. You can imagine various tabs being defined in the different channels - perhaps the Account Management channel would have a tab with a widget to bring in summary data from CRM. Maybe the Technical channel would have a tab displaying current work items from Azure Dev Ops too. Apps being made available across many Teams could be 3rd party apps available in the Teams store, or something custom that has been developed in-house.

The things you need to work with templated teams can be summarised as:



So this is all quite developer-led. It isn’t as though the template is being stored in the Teams service somewhere for example - ultimately a dev is writing code to pass some JSON to a call to the Graph. And this JSON contains all details for team creation – the name, the description, the channel settings, installed apps and so on. As I’ve been working with the API, I’m finding that some code which splits out building the JSON somewhat is useful. In particular, it seems useful to split it into two parts:

  • Things that change for every team being created (name, description, owners)

    ..and..

  • Things that stay the same and are considered part of the template (channel settings, installed apps and so on)
So this post is to provide some simple code around that in case others find it useful. There’s nothing too complex here, but I’m trying to get more in the habit of sharing little bits of code via Github.

For details on the JSON structure and the Graph call, see https://docs.microsoft.com/en-us/graph/api/team-post?view=graph-rest-beta. As the documentation shows, the sample JSON to create a team might look like this (this is the very sample from docs):

So, although we’re constructing this JSON and passing it to the Graph, a developer working with this might choose to:

  • Create a static JSON file with the non-changing parts, and treat this as the “template”
  • Write some code to append JSON representing the team name, description and owner(s)

You might notice from the extract above that the owner needs to be specified in the form of a GUID, rather than what you most likely have (the user’s account name/e-mail address). This GUID is the user identifier in AAD. Consequently, we’ll also need a method in our code to lookup a user GUID from an account name.

What exactly can we define in a Teams template?

Here’s a summary:

Setting Example
Visibility Public/Private
Installed apps [Any app from app catalog]
Owners [List of users]
Channel details Tabs, favourite by default
Member settings Allow create channels, allow add apps etc.
Guest settings Allow create channels, allow delete channels
Fun settings Allow giphys, stickers and memes, content rating
Messaging settings Allow edit/delete of messages, allow team and channel mentions

The code

The main helper code I wanted was a method I could call which would accept parameters for the team name, description, and owner(s) so I could call it many times. Perhaps it could become the core code behind something that reads from an Excel file to create many Teams in bulk. Or perhaps it would be behind a custom form in a nice end-user self-service request process. In terms of authentication, this code uses app-only auth to create the Team (using an AAD client ID and client secret), rather than delegated auth (in the context of the user). But, you can take either approach depending on your needs.

So, the core code I came out with is (shown here in the context of a simple console app - but you can drop the core method into whatever you need):


You might notice that I have a “TeamDetails” class which is also doing some of the work. This is where the code to manipulate the JSON is, providing methods to append the team name, description, and owner(s) to the other details being specified:


Of course, the full code is available in Github – it’s at the following address: https://github.com/chrisobriensp/TeamsProvisioning

The result

We can now create as many teams as we like wih the CreateTeam() method shown above. Each one will be created with the channels, tabs and other properties specified in the template. For example, here are the channels and tabs as defined in the sample JSON shown above:



Summary

Creating many Microsoft Teams in a consistent way with the right set of tools is now possible, and we can do it with app-only permissions too (so no need to do anything dodgy around storing details of a high-privilege account). You might find the code in this article useful if you start working with the Graph API methods to do this. In addition to creating Teams with the 'standard' template, note that Microsoft themselves are also providing some specific base templates baked-in to the service - and these might suit your needs out-of-the-box. For now, these base templates are targeted at education, retail and healthcare scenarios - but more will come in the future no doubt.

Either way, we have some new options for rolling out Teams with specific functionality. Hopefully the Graph methods which underpins this will come out of preview very soon, so this approach can be used in production solutions.

Wednesday, 27 February 2019

SharePoint Conference 2019 sessions from me – Enterprise PowerApps, and Azure Functions for Microsoft 365 scenarios

This year’s SharePoint Conference 2019 in Las Vegas in May is will be a great opportunity to learn about the latest developments from Microsoft in the world of SharePoint, Teams, PowerApps, Yammer, Flow and more. As you’d expect from one of the year’s biggest events, Microsoft are there in force and I hear there will be some interesting announcements in terms of new capabilities within Office 365 and SharePoint. Speakers from Microsoft include Jeff Teper, Bill Baer, Dan Holme, Chris McNulty, Mark Kashman, Vesa Juvonen, Naomi Moneypenny, Adam Harmetz, Omar Shahine, Sean Squires, Mike Ammerlaan and many more. But of course, the other speakers are a huge draw too – it’s an amazing list of people who are known for sharing great knowledge, and somehow I sneaked in there too 😉 Other folks include Andrew Connell, Wictor Wilen, Benjamin Niaulin, Chris Givens, Christian Buckley, Eric Shupps, Erwin van Hunen, Paolo Pialorsi, Sebastien Levert, Vlad Catrinescu and more. In short, a group of people who have deep expertise and who love to get into those conversations about challenges and solutions.

For me, I’ll be talking about two of my favourite subjects – both are topics that I think are really important in being able to build effective solutions on Office 365 and SharePoint: PowerApps and Azure Functions. The details of my sessions are below.

Reasons why I think SPC will be a great event

  • The show will be a “moment” for Microsoft, with lots of innovations and developments announced. To hear this first-hand and in detail from Microsoft themselves will put you in a great position.
  • Conferences are a great way of doing condensed learning these days. You can learn in a few days what would otherwise take many weeks or months to pick up – and in my experience, you get to trade off that knowledge for a long time.
  • There are some great full-day workshops to really get to grips with a topic from all angles – whether it’s modern SharePoint, developing with SPFx, Power BI, PowerApps and Flow, Office 365 security or how to build an I.T. strategy around Office 365, chances are there is a workshop for you. See https://sharepointna.com/#!/workshops for the full list.
  • An amazing few days of sessions, led by people with huge passion and knowledge for the topic – see https://sharepointna.com/#!/sessions for the list
  • Lots of opportunities to chat with speakers and ask questions
  • Vegas – if you don’t find the answer you’re looking for in a session, you’ll probably get chance to talk about it in the bar afterwards

Use code “OBRIEN” for a $50 discount

If you sign-up and use my surname as the discount code, you’ll get $50 off the ticket price - and of course, the organizers get to know which speakers attendees are interested in. Since this is Las Vegas we’re talking about here, so I’ll be amazed if you can’t find a good use for that $50 😉

 
To see pricing/register for the conference:
To conference website has all the details - head to:

https://sharepointna.com/#!/register


My sessions

I’ll be delivering the following breakout sessions:

Azure Functions for Microsoft 365 developer scenarios

Azure Functions are the "get out of jail card" for the architect/developer implementing Microsoft 365 solutions. Can't do exactly what you need in a Flow? Need to look-up some data when your PowerApp loads? Implementing custom team sites using Site Designs? Need to run a process on a schedule? Chances are that an Azure Function is the answer - so you need a thorough understanding of this building block to weave it into your solutions effectively. We'll look at authentication, scaling, coding styles, Microsoft Graph bindings and other advanced features, so that you can always call out to some custom behaviour whatever your scenario is.

Enterprise PowerApps - Rich Apps with Offline Support and On-Premises Data

PowerApps can address many business scenarios with ease, but some learning is needed to include advanced functionality such as offline support and connections to on-premises data. Using a series of demos, this talk will walk through these elements - we'll show a PowerApp designed for airline pilots which has these capabilities and see things from both the user and maker perspectives, meaning you go away understanding how to build them into your apps. We'll also consider practical tips of PowerApps - from use across devices, techniques for improving performance, and common headaches when building applications.


Conference details

The conference will be held at the MGM Grand hotel in Las Vegas. The dates are 21-23 May 2019, with workshops being held on the day before and the day after those dates. There are over 200 sessions in total, so whether you’re a business-focused person considering how to get the most out of Office 365 for your organisation, or you’re a highly-technical practitioner wanting to keep up with the latest techniques, the SharePoint Conference will be a great place to do it. Hopefully see you there!


https://sharepointna.com/#!/register

Wednesday, 30 January 2019

End-to-end guide to SharePoint Site Designs and PnP templates using a C# Azure Function - part 2

This article is the continuation of my mini-series on creating a custom template for a SharePoint site or Microsoft Team using Site Designs and a PnP template. The focus is on use of a C# function, since Microsoft's documentation shows use of PowerShell which is unlikely to be an option in future since it is not supported by Azure Functions v2. In this series:

  1. Part 1 - Azure queue, app registration, Flow, Site Design and Site Script
  2. Part 2 - the Azure Function, Key Vault, enabling Managed Service Identity, and the PnP template [this article]
Configuring the Azure Function for authentication
So we created the Function app in the previous article, but there is no code there yet - and we still have some config to do. It's still in preview here in early 2019, but I'm choosing to use the integration between Azure Key Vault and Azure Functions app settings for storing credentials (the app ID and app secret in this case). This is the thing where the credentials are stored in Key Vault, but you don't need to write any special code to fetch them (or indeed, modify any Azure Function code you already have) - instead, you use tokens in app settings which point over to the items in key vault. See the "Key Vault references for Application Settings" section of Simplifying security for serverless and web apps with Azure Functions and App Service. In general, this is a far better way of dealing with credentials than storing them in App Settings, because you can control exactly who can access them – in terms of users working with Azure and THINGS in Azure (e.g. particular App Services, or anything else with a Managed Service Identity).

Step 1 – enable Managed Service Identity for your Function app
  1. In the Azure Portal, go to the “Platform features” area for your Function app and find the “Identity” item:
  2. Enable the “system assigned” managed identity:
  3. Click “Save” and then acknowledge the message which appears:
  4. Your Function app’s managed identity will now be registered:
Step 2 - add credentials to Key Vault and grant access
I’m going to skim over this bit slightly, but the full documentation is at https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references if you need it.
  1. First, add the Client ID and Client Secret for your SharePoint app registration as secrets in the Key Vault. (N.B. If you don’t already have a Key Vault instance in your Azure subscription, you’ll need to create one). Choose any names you like, but mine look like this:
  2.           
  3. For each of these, I need to obtain the full identifier. Do this by clicking into the current version of each secret once you’ve created it, and finding the “Secret Identifier” property:
  4. Copy these URI values as we’ll need them in a second.
  5. Next, grant access to these secrets to your Azure Function. Still in the Key Vault area, go into the “Access policies” area:
  6. Add a new policy:
  7. First, select the principal – here, you are searching for your Azure Function app by name:

    then:
     
  8. Click the “Select” button once you’ve found it.
  9. Now we amend the “Secret permissions”:
  10. Check the “Get” option:
  11. Finally, click “OK” to confirm the permissions:
Step 3 - add App Settings to point to Key Vault entries
In the App Settings for my Function, I need to use the convention of @Microsoft.KeyVault(SecretUri=secret_uri_with_version) to point to my credentials stored securely in Key Vault. So having obtained the URI for each of my secrets in earlier steps, I add entries like these with the App Settings key names used in my code. For each one, value of secret_uri_with_version is the URI for the appropriate secret:



The Azure Function
The final piece is the Azure Function - the core code for this is below, but you can also download the full project from the Github project linked at the end. Some notes about the code:
  • As noted in the previous article, we’re using SharePoint app-only authentication to talk to SharePoint - and the auth code reflects that. You'll need to use alternative PnP AuthenticationManager methods if you choose to use AAD app-only authentication with a certificate
  • I use a separate class to slightly abstract away the Client ID and Client Secret, but it's simply a class with a property for each one. Feel free to create one, or just use local variables instead
Overall there's nothing too complex here, but I find always need a reference for how to pick up the location of the PnP template file when everything is running in Azure. The paths in the code line up with what's in my Visual Studio project that gets published to the Azure Function app:

The PnP template
For completeness, here's a simple PnP template to illustrate the integration - it provisions a modern home page with specific web parts, a content type and a document library, and also adds an entry to the web property bag:

The result

Once everything is in place, you have a great self-service Teams or SharePoint site provisioning process for your organization - you can configure the sites in just about any way possible between Site Designs and PnP templates.
For use with Teams/Office 365 Groups, you can set the default Site Design to be applied for team sites, and your templates will be invoked. For standalone SharePoint sites, users can request a new site from the SharePoint home page:

Your custom Site Design will appear in the list:

..and then the details of the site are collected:

Once the user hits the “Create site” button, the site will be created and Office 365 will indicate that the Site Design and associated templating is taking place:




After a few seconds the site will be available, and both your Site Design and PnP template will have been applied. In my case, I have:
  • From my Site Design:
    • A content type, document library and navigation links
    • Application of my “COB purple” modern theme
  • From my PnP template:
    • A custom modern home page with specific web parts in specific zones
    • Regional settings applied to the site
    • Another custom document library, for good measure
    • A property bag entry
    • Request access settings applied
It’s slightly eye-watering to look at, but that’s great for testing :)

Summary

Integrating PnP templating with a SharePoint site design is slightly involved, but the power it brings in terms of being able to template both sites for Microsoft Teams and standard SharePoint means it's an important technique. Importantly, the use of PnP means that you can configure the sites in ways which aren't currently possible with Site Designs alone. Hopefully this guide is some use towards understanding the mechanisms. As I mentioned previously, all the files used here can be downloaded from:

https://github.com/chrisobriensp/SiteDesignsAndPnPTemplating

End-to-end guide to SharePoint Site Designs and PnP templates using a C# Azure Function - part 1

A pattern that I think will become increasingly useful in 2019 and beyond is creating a custom template for a SharePoint site or Microsoft Team using Site Designs and a PnP template. It’s a topic that I and many others have already covered in some way, but at this time most of the samples (including the official Microsoft documentation) show using PowerShell in an Azure Function – but this now feels strange since Azure Functions V2 has been released and there is no support for PowerShell. As you might know, it was only ever “experimental” in v1, and it remains to be seen whether Microsoft will resolve the blocking issues they’ve cited (related to V2 function bindings and the PowerShell language). So in this mini-series, let’s walk through what an implementation would look like using an Azure Function written in C#:

  1. Part 1 - Azure queue, app registration, Flow, Site Design and Site Script [this article]
  2. Part 2 - the Azure Function, Key Vault, enabling Managed Service Identity, and the PnP template

NOTE: all of the files and code I'm referencing are available for download from this Github repo: https://github.com/chrisobriensp/SiteDesignsAndPnPTemplating

The recipe

Overall the solution elements are:
  • A SharePoint Site Design (and corresponding Site Script)
  • A Flow which adds an item to an Azure Queue
  • A SharePoint app registration which allows the code to authenticate to SharePoint and modify the site
  • An Azure Function (queue-triggered) which authenticates to SharePoint (using the app registration) and applies a PnP template to the site
A simplified representation of this sequence might be:

The implementation

Phase 1 – Azure things and SharePoint app registration

We have some pre-requisites to set up first – the Azure function app, queue and the SharePoint app registration. I recommend creating these first as you’ll need references from these things to put into later steps (your Flow needs details of the queue for example).
So let’s start there..
Creating the queue in Azure
  1. To do this, navigate to the Azure portal, and then go into an appropriate Storage Account that you have. If you don’t have one already, just create one (it’s a container for Azure storage things such as queues, tables and BLOBs ).
  2. Once there, go into the “Queues” area and create a new one:
        
        
  3. Also grab the storage key at this point. Go into the area for the storage account in general (not the specific queue we just created), and go into the “Access keys” area:


You’ll need both the queue name and access key later when we come to configure the flow, so keep these details somewhere handy but secure. Your Flow will need to know them so it can put a message on the queue :)
Creating the Azure function app
I won’t go into detail on this step as I’ve covered it elsewhere (e.g. 3 ways to create and debug Azure Functions) – but fundamentally we want to create the function app upfront to reserve the URL in Azure. We don’t have to do anything else at this stage. But it’s a good idea to do it early, as it would be annoying to specify the URL in one of the steps (e.g. registering the SharePoint app) only to find out that out someone else has taken it and you need to re-do lots of the config.

Of course, creating the function app in the Azure portal is probably the simplest way. I tend to just click the big “Create” button and search for “function app”:



Click the “Create” button when you’ve found the item.

This will then take you to the place where you can supply the details. The important things really are to:
  • Use a URL that makes sense for what you’re doing
  • Ensure you’re on the Consumption Plan
  • Associate the function app with a storage account related to this solution
For example:

You’ll need to decide whether you’re creating a new Resource Group for this stuff, or whether it fits with one you already have. Again, this is just standard Azure app service stuff and there are lots of documentation and articles to help with these decisions if needed.

Click “Create” when you’re ready. Ensure the function app gets created successfully, and make a note of the URL you used – you can get it back from listing the App Services you have in Azure if needed.

Remember! Your Function App should use Azure Functions V1 for now!
As of early 2019, you'll need to switch your Function App to use V1 of the functions runtime for now (due to .NET dependency issues with SharePoint CSOM and PnP). You'll need to do this before any actual functions exist in the app. To make the switch, go into the Function app settings and find the "Runtime version" setting. Change this to "v1" and save the config.







Creating the SharePoint app registration
To do this, we use SharePoint’s AppRegNew.aspx page to register our app. Remember this authentication approach results in a token that can only be used against SharePoint (as opposed to the Graph or other areas of Office 365), but that’s all we need when templating SharePoint sites – even if it happens to be a site which belongs to a Microsoft Team.
  1. Navigate to the AppRegNew.aspx page in the root site collection of your tenant – so https://YOUR_TENANT_HERE.sharepoint.com/_layouts/15/appregnew.aspx
  2. Fill in the details for the app:
    1. Client ID and Client Secret can be new identifiers from the “Generate” button.
    2. The Title should be something you’ll recognise as belonging to this solution e.g. “Site Design Provisioning” or similar.
    3. The App Domain and Redirect URI should reflect the URL you used earlier for the function app – the former has the domain, the latter is qualified with “https://” at the beginning:
    4. Ensure you see the confirmation message – when you do, keep these details safe:

Authentication flavours
The alternative to SharePoint add-in authentication is to use an AAD app registration and AAD auth. However, for app-only auth this approach is more involved as it requires you to create and upload a certificate (possibly self-signed) and select appropriate AAD scopes etc. If your code only needs to talk to SharePoint (e.g. to apply site templates) rather than talk to other Office 365 services via the Graph, then SharePoint add-in authentication is simpler. Just understand that you might need to use the other approach if you also want to configure the Microsoft Team or take some other actions.
Grant admin consent for the app
Anyway, assuming that we'll stick with SharePoint app authentication, the next step is to trust the app, so that it has the appropriate access to your tenant:
  1. Go to https://[yourtenant]-admin.sharepoint.com/_layouts/appinv.aspx (notice the -admin in the URL).
  2. In the App Id field, paste the Client ID that you copied, and choose Lookup.
  3. In the Permission Request XML field, paste the following XML:

    <AppPermissionRequests AllowAppOnlyPolicy="true" >
       <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
    </AppPermissionRequests>


  4. Click Create:


  5. To confirm that you want to trust this app, choose Trust It:

We’re now done with the prerequisites – so we’re ready for the Site Design, Flow and code for the Azure Function.
The Flow
The Flow itself is extremely simple. All you need is:
  • A HTTP trigger
  • A “put a message on a queue” action
The steps are:
  1. Go to the Flow portal in Office 365 and in the “My Flows" are click New > Create from blank:
  2. Add a “When a HTTP request is received” trigger. To do this, search for “http” using the search box:

  3. Find the “When a HTTP request is received” trigger and select it to add it to the Flow:

  4. Enter the following as the request body:

  5. Click “New step”, and type “queue” into the search box. Find and select the “Azure Queues” item:

  6. From there, select the “Put a message on a queue” item:
  7. Assuming you don’t already have a connection to your Azure storage account defined, click the ellipses (…) on the action in the flow and find the “Add new connection” item:
  8. Enter the details of the storage account name and key in the boxes shown (we’ll select the actual queue within this storage account in a second). Note that the connection name can be anything meaningful – but the connection itself is to the overall storage account, so it’s a good idea to include that in the name perhaps:
  9. Click “Create”.
  10. The Flow action should now let you select the specific queue, and also what details to put on it. Select the queue you created from the dropdown, and for the "Message” value, select “webUrl” from the HTTP request action:
  11. You should end up looking something like this:
  12. Click in the Flow name near the top left of the screen, and rename your Flow to something sensible:
  13. Finally, click “Save” to save the Flow:
Obtain the URL for your Flow
You’ll need the URL of your Flow to put into your site script. To obtain it, follow these steps:
  1. Go back in to edit your Flow.
  2. Edit the “when a HTTP request is received” activity, and grab the HTTP POST URL that’s specified (there’s a ‘copy to clipboard’ button to the right):

  3. Store the URL somewhere safe, ready for the next step.
The Site Design and Site Script
As you’ll remember, a Site Design is effectively a “registration” of sorts which is made up of one or more Site Scripts (JSON definitions of what should be provisioning into the site). So you can effectively share site scripts amongst many site designs if needed. Here’s a sample site script which:
  • Applies a theme named ‘COB purple’ which I’ve previously defined in my tenant – see http://aka.ms/spsitetheming for more details on modern SharePoint theming
  • Calls my Flow using it’s URL – I’ve edited the site script to paste in my Flow URL from the previous step
  • Provisions a couple of custom lists (one with a custom column) and adds them to the site navigation
  • Configures JSON column formatting on some columns

So that’s a site script. You’ll need to register both the site script and the site design using some PowerShell like the below.

Step 1 – register the site script:


You'll get an output something like this:

Id          : be7c02a8-9134-4961-921a-cffc4772e97c
Title       : COB project site script
Description :
Content     :
Version     : 0
  

Copy the ID that was returned as we'll need it in the next step. When we register a site design, we need to point to one or more site scripts that comprise the provisioning steps - so paste it into the next bit of PowerShell you need, as I've done below:


You'll now get an output something like this:

Id                  : ef49c695-b5e3-49ef-afba-ef053ca61414
Title               : COB project site
WebTemplate         : 64
SiteScriptIds       : {be7c02a8-9134-4961-921a-cffc4772e97c}
Description         : Creates a COB project site with a theme applied
PreviewImageUrl     :
PreviewImageAltText :
IsDefault           : False
Version             : 1
  

Success! Your site design and site script have now been registered, and it's hooked up to the Flow. However, we're not done yet - we still need our C# Azure Function which will actually do the work of applying the PnP template :) We'll do that in the next post..

Part 2 - the Azure Function, Key Vault, enabling Managed Service Identity, and the PnP template