Thursday, 15 February 2018

PowerApps – implementing offline support in your app

In the previous article I talked about my views on the good, the bad and the ugly of PowerApps at the present time (early 2018), but today I want to focus on a particular scenario – ensuring your app can be used offline. Not all apps will require this capability, but for some scenarios it will be vital. Unfortunately there is no magic button when building the PowerApp which makes it support offline – the implementer has to build it in his/herself, and this can make a simple app quite a bit more complication.

When we talk about an app working when offline, I’d say the general expectation is that:

  • The app is usable (e.g. any dropdowns which pull data from somewhere continue to work)
  • If the app is focused on writing data to somewhere (e.g. a SharePoint list/database/Excel file stored somewhere online etc.), then it should be possible to submit the record whilst offline – even if the connection needs to be resumed for it to actually be saved to the back-end
    • I think lots of PowerApps fall into this category (e.g. log a new incident/I.T. request/holiday request/expense claim etc.), so I’m going to focus on this aspect today
  • If the app reads existing data (e.g. show existing incidents/requests), then it should be possible to access at least some of this data offline (e.g. most recent 20 records, say)

The PowerApps blog has some good info in Build offline apps with new PowerApps capabilities, but I found myself doing some things differently – so thought it worth discussing here.

    Understanding the deal with offline

      A big thing to recognize here is that *the app must be opened for a while once the connection is resumed for data to be submitted*. It’s not like the “fire and forget” experience with the e-mail application on your phone (and one or two other native or “tier 1” applications), where you can hit send and trust the data to be sent even if your phone stays in your pocket. Instead, your users need to have your PowerApp open for a while – and the specifics depend on how you implement offline. In my case I used a timer which checks every 5 seconds if the device is connected to the internet, and then saves the record to SharePoint Online if so – this means the user doesn’t have to DO anything in the app (e.g. press a button), which is something. And, of course, as these things are happening in the background it’s important to communicate the status to the user, so it’s clear when their record has been saved to the back-end.

      By the way, this deal isn’t specific to PowerApps. I’m no expert here, but it seems nearly all 3rd party app (including other apps you might use for such a use case e.g. Nintex Mobile) require this due to constraints on the background processing apps can do when not in use. Even with the right settings in place on your device (e.g. “Background App Refresh” enabled on iOS), this isn’t enough for these apps to push data it seems. So, prepare to coach your users in having the app open for a while once re-connected – and as I show below, you could consider making this really clear in the user experience.

      A sample experience (from my POC app)

      Here’s a video of offline support in an app I built recently, recorded from my iPhone – the holiday/leave requests app I mentioned in the last post. This simulates a user submitting a leave request without a connection (flight mode enabled), and then the record actually being saved to SharePoint Online once the connection is back (flight mode disabled):

      The recipe for offline in PowerApps

      In this section I’ll go through the different bits which are making the offline behaviour work, and provide some starter PowerApps formulas where appropriate (with the important functions highlighted). Remember my case focuses only on adding a new item to a SharePoint list, so it’s the PATCH function which is doing this work. Overall, the recipe I used was:

      • Two info screens within the app:
        • Pending screen
        • Confirmation screen
      • Formula behind submit button:
        • If connected, PATCH record to SharePoint
        • If not connected, CLEARCOLLECT to save record locally
        • RESET form (to clear existing values)
        • NAVIGATE to pending screen

          If(Connection.Connected, Patch('My SharePoint list', Defaults('My SharePoint list'), {Title:Concatenate("Leave Request - ", User().Email, " - ", Text(Now(), "[$-en-GB]dd/mm/yyyy hh:mm:ss" )),SomeField1:SomeControl1.Value, SomeTextField1.SomeTextControl1.Text,SomeChoiceField: {    '@odata.type':"#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference", Value: SomeDropDownListControl.Selected.Value, Id: 1 });
          Navigate(ConfirmationScreen, ScreenTransition.Fade),
          ClearCollect(LocalRecord, {Title:Concatenate("Leave Request - ", User().Email, " - ", Text(Now(), "[$-en-GB]dd/mm/yyyy hh:mm:ss" )),SomeField1:SomeControl1.Value, SomeTextField1.SomeTextControl1.Text,SomeChoiceField: {    '@odata.type':"#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference", Value: SomeDropDownListControl.Selected.Value, Id: 1 });
          Navigate(PendingScreen, ScreenTransition.Fade))
      • Formula for Timer control (implemented on both “start” and “pending” screens – so user can have app open in any logical location, and record will be submitted). In the OnEnd event:
        • If connected and have record(s) in “LocalRecord”, iterate each record with FORALL and then PATCH to SharePoint
        • NAVIGATE to confirmation screen
        • CLEAR “LocalRecord”

          If(Connection.Connected,ForAll(LocalRecord, Patch('My SharePoint list', Defaults('My SharePoint list'), {Title:Concatenate("Leave Request - ", User().Email, " - ", Text(Now(), "[$-en-GB]dd/mm/yyyy hh:mm:ss" )),SomeField1:SomeControl1.Value, SomeTextField1.SomeTextControl1.Text,SomeChoiceField: {    '@odata.type':"#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference", Value: SomeDropDownListControl.Selected.Value, Id: 1 }});
          Navigate(ConfirmationScreen, ScreenTransition.Fade));

      • A “status bar” within the app indicating whether the device is connected or not (as a simple reminder to the user)

      WARNING – those formula extracts are edited/simplified versions of my real ones, and maybe the closing brackets aren’t exactly right. Take care if you try to use them for your formulas – really I’m just trying to convey the concepts!

        Dealing with reading from data sources when offline (e.g. for dropdowns)

        One thing to look out for is if your SharePoint list has choice or lookup fields – you might be presenting the options in a dropdown list or with radio buttons in your app. Since November 2017, you can now have multi-select on such fields, but unfortunately if the user happens to use your app for the first time in offline mode, the dropdown list will not be populated (it will display “Find items”, but no list appears when the user clicks). The user can type in an option, but since they are not selecting from a list of valid choices this will generally go horribly wrong and the item will not be added to SharePoint.

        Also consider that you are most likely not using taxonomy/managed metadata fields, because they are still read-only (as at February 2018).

        So, you need to work around this. One option, especially if you’re already using the PATCH command or similar to update SharePoint, is to bind your control to some static data which can be accessed offline. This is a bit lame, as you’re essentially duplicating the items as hardcoded data within your app – you lose the benefits of your choice/lookup field, i.e. the form dynamically fetching the right options based on what is defined in SharePoint. You could probably do something clever with a formula which refreshes a collection when the app has a connection, but it would be nice if this was handled in a better way by the PowerApps infrastructure. Maybe in the future :)


        PowerApps can work just great offline, but it’s all down to the implementer. The PowerApps framework provides the ability to detect if the device currently has a connection, a timer control (so that actions can be taken automatically), and the various functions for adding/updating data in a data source (e.g. PATCH, UPDATE etc.). These are the ingredients to use when implementing offline support in your app – there’s work to do, but you can control the experience and make sure it makes sense in your context.

        Further reading -

        Tuesday, 6 February 2018

        PowerApps–the good, the bad and the ugly (early 2018)

        I’ve been doing quite a lot of work with PowerApps for clients recently, and it’s been an interesting time. No doubt I’m still not the world’s most capable PowerApps implementer by any stretch of the imagination, but I feel like I’ve been through the usual denial/anger/acceptance phases that often come with a new technology ;) Some of my work has centred on a proof-of-concept application for one of the big airlines – specifically, building an app that pilots should be able to use whilst offline on an iPad. The project was to digitise some forms related to booking leave, which is an important part of flight crew scheduling. We effectively rolled 3 forms into one app:


        I gave a presentation on this recently to my colleagues at Content and Code, but I’ve also genericised some of the information so it can be shared more widely (Contoso Airlines!). The deck shared below is a combination of some typical lessons learnt and tips, but also has my thoughts on where PowerApps is a technology, structured into “the good, the bad and the ugly”.

        Potentially transformative, but with a learning curve..

        My conclusions are that it’s a great technology and although it’s aimed at forms-type applications in general, it really shines for relatively simple mobile apps. The organization just has to deal with getting users to have the PowerApps app installed (either from the app store, via an MDM solution such as Intune or Airwatch, or another approach) and then all the PowerApps forms and applications the organization provides will show up there. This is *far* easier and cheaper than developing individual native apps on iOS and Android, which each need to be distributed to users once the build is complete. In contrast, it’s feasible that you could have your Office 365 users working with a simple PowerApp on their mobile device within hours. Think about that for a moment! Sure, PowerApps doesn’t give you the richness that a high-end native app can have, but the barrier to entry is much lower.

        However, it’s not always the simplest for the app implementer to work with. Frequently, things can get into a territory that I’d argue most power users would struggle with. An example in my case was having to abandon the default SharePoint integration/data-handling, and craft my own formulas which use the Patch() function to add an item to a SharePoint list (necessary because my form used multiple screens). This is fiddly work if you have lots of form fields and columns in the underlying list, even for a developer used to such things.

        Customizing SharePoint lists vs. creating a standalone PowerApp

        The implementer must choose between two approaches – customizing the form of a SharePoint list, or creating a “standalone” PowerApp (which might talk to the very same list). Conceptually these are quite different, and have different behaviours. This decision is expressed in the PowerApps menu on a SharePoint list:


        A key thing here is that customized SharePoint forms do not show up in the PowerApps app:


        If users need to work with a customized SharePoint list on their mobile device, then using the SharePoint mobile app instead provides a reasonable experience – in fact, the SharePoint app should hand-off to the PowerApps app when you go to the list, and the customized PowerApps form should then be loaded. However, this currently seems to be a bit hit and miss – most often, I actually just get a web rendered view of the PowerApp, and here it seems that the experience isn’t as optimized for mobile as a true PowerApp – some pinching/zooming is often necessary.

        I’m sure things will be straightened out here eventually, but I still think I’d prefer a different model – what about if certain customized SharePoint lists could be flagged to appear within the PowerApps app (perhaps by a tenant administrator)? That would seem a better arrangement to me at least.. 

        Other interesting aspects

        The presentation includes some high-level detail on other things I’ve worked with that might be interesting:

        • Installing the on-premises Data Gateway to connect to on-premises data (SQL Server in my case)
        • Implementing offline support in a PowerApp (using a Timer control to submit data once reconnected)
        • Some implementation details around using a Gallery control for navigation, and the 10 PowerApps functions I found most useful from the 150+ functions which are available

        My “good, bad and ugly” summary:

        If you’re not that interested in the presentation and want to skip straight to the summary, here are my conclusion slides:




        By the way, if you’re wondering what I mean by “web experience (upscaled phone/tablet view)”, let me try to explain. Certainly a form/app looks good on a mobile device, and is optimized for that form factor – all the controls are very “thumb-able”, and even typing into a textbox works fine (shown here at tablet/iPad size):

        4 - BA PowerApp - paternity leave screen

        But when a PowerApp is accessed on a PC, there is no responsive design or optimization for the device – the very same rendering for phone/tablet is used, which is just plain weird in my view:

        PowerApps - PC 800 - msg

        And no, I don’t know the Office 365 suite bar displays “Dynamics 365” either (particularly since Dynamics is not even in use in this tenant). But I’d happily live with that if I could have a better experience than the strange “phone screen in a PC browser” deal that we currently get. Nintex Forms does a better job of this, so I’m not sure why PowerApps went down this route. Again, I’m hopeful some enhancements to this will appear at some point.

        So that's some headlines from what I spoke about. I'll most likely publish some other PowerApps articles which dive into more detail on implementing offline/using the on-premises Data Gateway etc., but essentially I just wanted to share the slide deck in case it’s useful to anyone:

        The slide deck:

        Thursday, 4 January 2018

        Using Site Designs or PnP templates for SharePoint site provisioning

        So the new “site designs and site scripts” capability for creating SharePoint sites from a template is starting to become available in Office 365. This provides an alternative approach to using Microsoft’s Patterns and Practices (PnP) provisioning library and XML, which has been the way that most experienced implementers have been creating custom site templates in recent times. For a full “self-service” implementation, it’s typical to provide a custom form for end-users to request sites and provide any required information - the PnP building blocks provide support this, although some tailoring is needed in most cases plus the work to implement in the organization’s Office 365 and Azure environment. Microsoft are introducing site designs/site scripts as an alternative way of templating SharePoint sites, which is more baked-in to Office 365.

        However, it’s not just a simple “either/or” decision between site designs and PnP – both are valid approaches, and there are quite a few considerations which could lead you to use one or the other. In addition, it’s also possible to combine both approaches by calling a PnP template *from* a site design. This is very welcome since:

        • there are lots of tweaks to a SharePoint site that are not possible yet with site designs
        • lots of organizations have an existing investment in custom site templates implemented with PnP

        So, the implementer can choose between site designs, PnP provisioning, or a combination of the two. In this post I’d like to explore some of the factors around your SharePoint site creation/templating strategy.

        Key considerations for Site Designs

        1. End-users create sites directly (with no approval step)

        Site designs that you define become available for selection in the out-of-the-box site creation experience. There is no approval process, and in general you have to be happy with the user experience which is provided. It’s the "SharePoint home" page where the site creation UI is surfaced - accessed from the 'SharePoint' text in the Office 365 header or the 'SharePoint' app in the app launcher. Self-service site creation must be enabled on the tenant for the 'Create site' link to show (SharePoint Admin Center > Settings > Site Creation > “Show the Create site command to users who have permission to create sites”). Note that it is possible to restrict the use of specific site designs to certain groups of people (e.g. if you had a template for an 'executive site' or a 'finance site', and only certain groups of people should see this option) with commands such as Grant-SPOSiteDesignRights or GrantSiteDesignRights (REST), but the top-level switch which enables all users to create sites must be enabled on the tenant – those commands only hide/show specific templates.  

        Here’s what the experience looks like:

        COB site design - create site

        COB site design - site design selection

        COB site design - form 1

        COB site design - form 2 

        2. It’s possible to provide a custom form, but implementation effort is needed (especially to collect custom metadata)

        As users create sites, it’s common to want to collect some custom metadata – things like business unit, purpose, cost centre and so on. Happily, it appears possible to provide a custom form to facilitate this (but it’s not working yet in any of my tenants):

        Custom site creation form

        It’s not yet clear what form (ahem) the form is expected in. It could be that a PowerApp form is expected here, in which case we’d be specifying something like:

        Custom site creation form - PowerApps

        However, in addition to implementation effort required to develop and host the custom form, I envisage that a chunk of work is required for that custom metadata to be applied somewhere. After all, you’ll need to decide whether this gets stored somewhere in the site (e.g. property bag) or in some centralized list or database somewhere. So as an accompanying point, it’s perhaps worth remembering that…

        2.5 There is no site directory “list”, except for your site collection list in the SharePoint Admin Center

        In a typical SharePoint site templating implementation (based on PnP or not), there’s usually a SharePoint list which contains details of all the sites which have been requested and created. Often the implementer will store custom metadata (such as division, cost centre etc.) in this list, particularly if doesn’t need to be updated by the site owner on an ongoing basis. But there’s no such list with the native site creation setup, only your list of site collections in the SharePoint Admin Center - and remember these Group sites will only show in the NEW Admin Center due to be launched in early 2018! It’s not yet clear whether this will support custom metadata and make the whole thing easy, but I doubt it – I’d fully expect there to be work to do to handle your custom metadata, and I think that’s fair..

          3. Cannot block ability to create communication sites

          Some organizations are happy for end-users to create team sites from approved templates, but want communication sites to be a more controlled thing – perhaps because they’re worried some folks will take communication sites too far and create lots of mini-intranets. Unfortunately this isn’t possible currently. If end users can create SharePoint sites (the default), they can create both team sites and communication sites. Certainly, communication sites are a welcome addition to SharePoint Online - but I could believe some organizations will block the out-of-the-box site creation tools and implement their own version with more governance for this reason.

          The first step of creating a site using the out-of-the-box UI is shown below (but not in the series above) – as you can see, both types are available for selection:

          COB site design - site type

          4. Site designs create Office 365 Group sites (unless you have disabled the ability for end-users to create Groups)

          As you might know, when a site is created from the SharePoint home page (as shown above) it’s actually an Office 365 Group which is created – assuming that is, that your Office 365 environment is using the default setting which allows all end users to create Groups. If not, a classic/standalone SharePoint site is created. All this is the case whether a custom site design is applied or not. With a Group of course, a bunch of things are actually being provisioned not just a SharePoint site collection – including a shared mailbox for group conversations, a calendar, a Planner Plan and so on. This is perfect if your collaboration strategy is based on Office 365 Groups – but this requires detailed consideration. Organizations should not wander into this blindly.

          ..but a Team is not automatically created for the Group..

          Notably a Microsoft Team is not provisioned for the Group – similar to if the Group was created from Outlook, Yammer, Power BI or one of the other endpoints. But it is possible to easily add a Team as a separate step if needed. Any user who has permissions to create a Team will see something this option when they go to create a Team:

          COB create new team - 1

          COB create new team - 2

          In all this, you should be considering whether your strategy is based on Office 365 Groups which can be created by any user (the default), or whether you prefer to do something else. This is a fairly big topic, but there are several options here, including:

          • Provide a means for end-users to create (or simply request) SharePoint sites which are not Groups i.e. they are classic standalone SharePoint site collections
          • Restrict who can create Groups in the organization, by using the Set-AzureADDirectorySetting command with the "GroupCreationAllowedGroupId" parameter to restrict Group creation to members of a special group (e.g. I.T. staff) – see Manage who can create Office 365 Groups for more info
            • (N.B. Microsoft recently clarified the licensing requirements around enabling this option – users who ARE able to create Groups must have an Azure AD Premium license, but the rest of the organization does not)
          • Both of the above
          • Don’t use Groups at all
          • Provide a means for end-users to create (or simply request) a site which is an Office 365 Group, but using a custom form as described earlier or an entirely custom interface (e.g. because you have particular requirements not satisfied by the out-of-the-box UI)

          Overall, you can’t really get into site designs for team sites without considering wider aspects of collaboration. Oh and remember, if you provide site designs for communication sites (rather than team sites), those are NOT Group-connected sites. By the way I think Microsoft made the right call there, given the nature of most communication sites..

          5. Using site designs alone does not need Azure

          Most SharePoint site templating implementations which use PnP also use Azure. Certainly if self-service is involved, the typical arrangement is to have users request the site through a form, which adds an item to a list. Because site creation/template application takes some time, it needs to be an async process and so somewhere in there is usually an Azure queue with an Azure web job or Azure Function – this does the heavy lifting, and then e-mails the user and some administrators when the site is available. The PnP provisioning library provides much of these building blocks.

          However, we regularly run into organizations which are using Office 365 and it’s services, but do not use Azure or any competing cloud platform such as AWS yet. Of course, any Office 365 implementer knows that by using Office 365, the org is actually using Azure AD underneath, but really we’re talking about whether it’s possible to deploy remote SharePoint code such as PnP to the cloud. Often the InfoSec or compliance groups have not yet validated whether this is OK for the org, and there might be valid reasons why Office 365 is OK but other cloud services are not (yet).

          So, it might be compelling that site designs themselves bring no requirement for Azure. Sure, you’re limited to the templating options provided by site designs, but the “engine” which is applying the template to the site is Microsoft’s code running within the Office 365 service – no custom code is needed whether PnP or not, and therefore the infrastructure requirements are somewhat simpler.

          6. Site designs cannot be used on-premises, but PnP site templates can..

          Not too much to say here beyond that. Will site designs come to on-premises SharePoint in the future? Difficult to say, but it’s worth remembering that PnP site provisioning can be used in online and on-prem scenarios.

          7. Limitations of site designs

          One big caveat if you’re hoping to use only site designs for your site templates is that you’re currently limited to to what can be accomplished in a site design. The list of things you can add/change in the site is currently:

          • Add list:
            • Set title
            • Set description
            • Add column
            • Add content type (note – it must exist already! Site designs cannot provision new content types yet)
            • Set field custom formatting (with the new JSON-based formatting)
          • Apply theme
          • Join a hub site (although hub sites are not yet launched)
          • Set site logo
          • Add navigation link
          • Trigger a Microsoft Flow

          NOTE – this list will change over time. See the site design JSON schema reference for the latest picture and details of each operation.

          When I think about the other things we often change (using a PnP template) – changing the site locale/region settings, activating features, provisioning a new home page, adding and configuring web parts, setting the site access requests recipient, changing content types/views/applying versioning settings etc. on libraries – it becomes apparent that things are very limited indeed. For us, this is a complete blocker to the idea of using site designs on their own at the moment. Fortunately, the ability to call a Microsoft Flow is intended for you to supplement what the site design/site script is doing – so let’s explore this idea.

          The “site designs + PnP” approach

          In brief, the Flow can trigger some remote code you have to perform other configuration of the newly-created site. This allows you to chain a bunch of other things on to what you were able to do with the site design – for example, actions in my list of things not possible purely in site designs. Of course, the logical thing to do here is actually to apply a PnP template to the site as we would have done before site designs. The pattern is:

          1. Site gets created from site design
          2. Site design steps are applied
          3. Custom Microsoft Flow is called – this puts an item onto an Azure queue with details (e.g. URL) of the new site
          4. The Azure queue uses a QueueTrigger to start an Azure Function (or web job if you prefer)
          5. The function applies a PnP template to the site

          There’s some pretty good early documentation on this approach in Calling the PnP Provisioning Engine from a Site Script. That article shows using a function written in PowerShell which authenticates back to Office 365 using SharePoint Add-in authentication, but you might also choose a C# or node.js code approach which uses Azure AD and ADAL.NET/ADAL.js to authenticate back. Either way, there’s some work to do in Azure to get this running.

          The benefit of course, is that you unlock the ability to do anything you need to meet the requirements of the site, but can take advantage of the out-of-the-box UI for creating sites (and the fact that things are nicely baked-in to Office 365/SharePoint Online). Given that PnP site provisioning continues to expand it’s capabilities and we can now automatically deploy app packages containing SPFx web parts and extensions, or even SharePoint Add-ins, this approach will be common I feel. Indeed, I think we will implement “minimal” site designs which basically only call a Flow, and the entire template implementation is handled in a PnP template.


          It might sound like I’m down on site designs somewhat from the points I’m raising, but I’m not. I think this is a great evolution in SharePoint Online – no longer is all of a site templating solution is left to the implementer, since Microsoft are now taking care of some elements (however small to start with). I love the fact that some thought was given to how to go beyond the capabilities of site designs, and I’m sure the engineering teams were thinking specifically about how PnP templates could be incorporated. If I was king for a day, I would have preferred that the existing PnP template schema was used as the foundation for site designs in the first place (instead of introducing another approach to templating with a new JSON schema) – however, I do understand that the PnP engine is open source/community-driven and is not part of the core Office 365 platform, so perhaps that was part of the reason.

          The introduction of site designs certainly means that there are more options around SharePoint collaboration and site provisioning strategies! Being equipped with as much information as possible is wise – this will help you make the right decisions for you/your organization’s context..

          Also remember that site designs are still in preview (currently being rolled out to Targeted Release tenants) – hopefully it won’t be too long until the initial release hits General Availability, and the capabilities expand along the journey..

          Reference -

          Thursday, 14 December 2017

          Presentation deck – Best bits of Azure for the Office 365/SharePoint developer

          This is post 2 of 2 to publish the slide decks for presentations I’ve given recently, in particular at the European SharePoint Conference 2017 held in Dublin. See also:

          Presentation deck – Pitfalls in SPFx development

          As with my other post, the slide deck is embedded at the bottom of this post. There’s no way for me to convey the demos easily, but the slides themselves hopefully have some good reference information. When you start to consider some of the different scenarios in even lightweight extensions to Office 365/SharePoint, it’s clear how useful Azure is:

          What? How?
          Do something on a schedule Put code in Azure Web Jobs/Functions
          Build apps (Office 365 app/SP provider-hosted add-in) Deploy app files to an Azure app
          SharePoint site provisioning Deploy PnP Partner Pack (or PnP Core with some calling code) to Azure
          Run code on a button click Use Azure Functions + JavaScript
          Store data not suited to SP lists Use Azure SQL Database
          Store files for my app Use Azure BLOB storage (and CDN if appropriate)
          Implement SharePoint web hooks Use Azure Queues and Functions
          Implement authentication on a custom web app Implement Azure Active Directory (AAD) auth

          The highlighted scenarios are ones I demo’d, with the last one actually being a demo of a real-world solution we built which touches on queues, web jobs, BLOB storage, CDN and more.

          Otherwise the main topics are:

          • Azure web apps
            • Lots of cool features you might overlook here, including Deployment Slots and Testing in Production. In other words, it’s much more than simple web-hosting that you might get from the days of hosting IIS yourself..
            • Variety of ways to deploy files there – from the Kudu interface which is similar to dragging/dropping files into a SharePoint document library, to publishing from Visual Studio, to WebDeploy, to auto-sync from your source control (VSTS, GitHub etc.)
          • Azure App Insights
            • Another unsung hero of Azure? I’ve discussed this in a couple of posts recently, including Use Azure App Insights to track events in your app/web part/provisioning code. I love the idea of finding out how often a particular web part is running, or if a particular tab is being clicked in your app – and it’s really simple to put this kind of stuff in place too. App Insights also has great tools for querying your logs in a SQL-like way, and also for configuring alerts (e.g. if the home page takes longer than 5 seconds to load from the client-side). Take a look!
          • Azure Functions
            • If you’re an Office 365 developer and you haven’t implemented some code in an Azure Function yet, I think it’s only a matter of time :) I have a slide which compares to Azure web jobs, but overall Functions can be used in so many more scenarios – including things like a button click in a web part or PowerApp, or perhaps a call out from a Flow or the Site Designs model for site provisioning (via a Queue Trigger)
            • I also talk about how Azure Functions should typically be secured with AAD auth in the real world. I demo’d an SPFx web part which uses SPO cookie auth as an alternative to adal.js or similar – this has some advantages to the current arrangement (of adal.js), including the fact that multiple web parts on the same page don’t need to sign-in separately
            • It’s also worth understanding how far the Visual Studio tooling for Functions has advanced. Sure, VS Code is the cool kid for many coding scenarios these days, but for C# functions, VS 2017 is actually stronger I feel – some info on this:
              COB options for Azure Functions - CSharp
          • Azure SQL Database
            • The main point here is to stop storing things in SharePoint that should be in SQL :) SP devs who haven’t touched SQL for years shouldn’t be scared of Azure SQL – it’s really easy to get started, and you can run databases up to 20GB for free
            • Also, be aware that identity in the SQL world has been updated for the cloud. You can now use Azure Active Directory accounts to authenticate, including from tools such as SQL Management Studio and Visual Studio Server Explorer
          • ARM templates
            • ARM templates offer an alternative to lots of button clicking and manual configuration in the Azure portal – perfect for those things that will be deployed to multiple Office 365 tenancies/Azure subscriptions, where you want repeatability
          • Azure Queues (and triggers)
            • Queues are a great building block to support things you might do in code. Any time you need some separation or some long-running processing, a queue is often a nice pattern to use – one thing puts something on the queue, and something called a QueueTrigger is used to point to some code which does the long-running thing (e.g. create a SharePoint site). As mentioned previously, the new Site Designs model for site provisioning will use this, and so do SharePoint web hooks.
            • In terms of what your code might be, Azure Functions and Azure web jobs are common – both work with QueueTrigger as you might expect

          As before, hopefully there are some useful nuggets in here which are useful to you!

            Slide deck:

            Tuesday, 5 December 2017

            Presentation deck – Pitfalls in SPFx development

            This is post 1 of 2 to publish the slide decks for presentations I’ve given recently, in particular at the European SharePoint Conference 2017 held in Dublin. See also:

            Presentation deck – Best bits of Azure for the Office 365 Developer

            Unfortunately, I never think the slide deck alone conveys all of the information of a conference session, since it’s the demos which are often the most valuable part. Still, I try to assemble slides which have useful reference information, so hopefully this will be useful to someone. The full slide deck is embedded from SlideShare at the bottom of this post. The main topics I discuss here are:

            • Versioning and dependency issues
              • The need to ensure you use --save or --save-exact when adding libraries with npm install (so that they are recorded in your package.json file, and other developers on the team can successfully build from source control)
              • Semantic versioning, including caret and tilde symbols in version numbers
              • The need to run npm shrinkwrap for each release of your code
              • [NOTE – some of this changes in npm 5, which automatically does a --save when doing an install, and also automatically generates a package-lock.json file (similar to npm-shrinkwrap.json. But for now, npm 5 is not officially supported in the SharePoint Framework (SPFx) and so these points remain important)
            • Re-use of existing JavaScript code
              • You might choose to wrap such code in a module if it is not already – this provides a more formal method in TypeScript/JavaScript of sharing code (e.g. library code)
              • Once you have a module, you can look at options such as npm install [filepath], npm link or using a private hosted npm repository provided by npm private packages or Visual Studio Team Services Package Management
            • Office UI Fabric
              • Use of Fabric Core and the Fabric React components – using the Core styles is much simpler in version 1.3.4 onwards of SPFx, where the sp-office-ui-fabric-core package is referenced and the SCSS styles use mixins to reference the styles in your custom styles
              • When using the Fabric React components, you should typically ensure you use static linking in your import statements e.g. import { Button, ButtonType } from 'office-ui-fabric-react/lib/Button';
              • See Using Office UI Fabric Core and Fabric React in SharePoint Framework for more information on this
            • Calling the Microsoft Graph and/or custom APIs (e.g. an Azure Function)
              • All of these resources are likely to be secured with AAD
              • GraphHttpClient is currently of limited use..
              • you will most likely need adal.js if calling from the client side, or ADAL.NET if calling from the server side
              • An alternative to adal.js for a custom web API/Azure Function, is the approach which leverages the SharePoint Online authentication cookie to pass credentials to your API (using the “credentials”: “include” header to pass across domains) – I think this is a useful approach and one of my demos covered this (video at
              • I use this slide to give an overview of the two approaches:

              • Also note that soon, it will be possible to call your custom APIs by specifying additional AAD app registrations that can be called from SPFx without additional consent. This will simplify things significantly, and mean that your SPFx web parts/extensions will no longer need a sign-in button/process just to be able to call downstream resources
            • Deployment
              • Remember that the default SPFx behaviour is for any 3rd party libraries you add to be bundled into your web part – this increases your bundle size, and can be a particular problem when you have multiple web parts/extensions all using the same library (and Office UI Fabric can be a big culprit here!)
              • Another “by default” thing to remember is that each web part/extension you build gets it’s own bundle – the config.json file is what controls this
              • Where possible, 3rd party libraries should be externalised to a CDN..
              • ..and if that isn’t possible, consider SPFx component bundles as a way to avoid having a library duplicated amongst all your web parts. In the case where you have 5 web parts on a page all using the same library, if you don’t externalise or use component bundles performance will suffer for first-time page loads

            Hopefully there’s some useful information in here, and I’ll most likely expand on some of these points in future articles. Here’s the slide deck:

            Slide deck:

            Tuesday, 31 October 2017

            Speaking at the European SharePoint Conference 2017

            ESCP17 logo - 500

            Between November 13-16 is this year’s European SharePoint Conference in Dublin, and I’m looking forward to speaking there. The event looks great, with an amazing list of speakers and great representation from Microsoft. Jeff Teper will be giving the keynote, and other Microsoft speakers include Dan Holme, Mark Kashman, Chris McNulty, Vesa Juvonen, Mike Ammerlaan and others. Effectively, this is the biggest SharePoint thing in Europe this year.

            I’m giving two talks, both of which I’ve given before but have updated content from recent developments. As a speaker, it’s great to speak about a topic which is continually relevant but wow, you certainly have to check that every nugget of information is still valid and that you’re covering latest developments. Speaker rooms these days are full of people cursing Microsoft ;) Anyway, the details of my talks are:

            Azure - the best bits for Office 365/SharePoint developers

            Tuesday 14 November - 15:15-16:15

            Azure – there’s a lot in there considering it’s just a small word! As a skillset, Azure is practically mandatory for most Office 365 developers. Between Azure functions, web apps, Azure AD, BLOB storage, SQL Database, queues and web jobs, there are a lot of useful building blocks – and solutions like OfficeDev PnP use them heavily. Maybe you’re starting out and want to host remote SharePoint code (such as Office 365 apps or provider-hosted SharePoint add-ins), or maybe you’re familiar with many Azure bits but also have a list of “untouched” areas. In this session, Azure for Office 365 and SharePoint developers, we’ll dig into the most relevant Azure capabilities, using real scenarios to show winning combinations such as SharePoint web hooks and Azure functions.

            I’ve also added content around:

            • Graph bindings for Azure Functions
            • App Insights

            Avoiding common pitfalls with the SharePoint Framework (SPFx)

            Thursday 16 November - 15:15-16:15

            This session goes beyond “intro” level SPFx content, to discuss common issues when you start using the SharePoint Framework for real. We’ll cover pitfalls related to TypeScript, npm and dependencies, SPFx security, and also focus on challenges related to team development – including new causes of “it works on my machine!”. Perhaps you have existing JavaScript code you’d like to re-use with SPFx, so we’ll talk about better ways to do that than copy/paste. We’ll also look at traps you can run into when you’re ready to release a version of your SPFx web part – ranging from accidentally bundling JS libraries, to not “shrink-wrapping” your dependencies for a reproducible build.

            I’ve also added content around:

            • Correct use of Office UI Fabric, since this is a common task which is harder than it should be at the moment
            • Component bundles in SPFx – the ability to share common code between your web parts and SPFx customizers

            More info

            If you’re not already going, I’d seriously consider looking at it and asking the boss about the possibility. Previous events have been great, and I think the content is always high-quality. Tickets are still available, and you can get a 10% discount with the following code:


            The link you need is:



            Friday, 6 October 2017

            My Ignite wish list – what got delivered and what didn’t?

            In the week or two before the recent Ignite conference, I published a wish list of things I was hoping Microsoft would announce. As usual for me, this focuses *mainly* on building on and extending Office 365, and SharePoint in particular. I like to publish these lists occasionally - it helps me shape my thoughts, and keep up with “top of mind” developments in Office 365 which would help the organizations I work with. Now that the event has happened, there were a TON of announcements at Ignite – clearly there is HUGE amount of investment and development happening across Office 365 right now, and it’s an awesome time to be working with Microsoft tech. If ever you wondered whether you backed the right horse for your career (or made the right choice for your organization), I think it’s hard to have those doubts these days. But that said, I notice that several items on my wish list did NOT get dealt with, so I thought it would be good to reflect on those somewhat.

            Before we jump into the items, I have two high-level thoughts on Ignite:

            • Hey, I see what you did there!
              • Although there *were* lots of announcements, pay attention to the timeline on each of them. I’ve tried to gather together the most relevant ones to me in my table below – but I note that many are actually quite far away into 2018. Nothing wrong with it, but I feel perhaps there was a Microsoft tactic to provide a “big wave” of announcements to increase the overall effect, even if many are quite far away from launch (or even just “things that might happen”). I guess this fits with today’s “disclosure strategy” of using these 2 or 3 large events through the year to make announcements – and frankly, I much prefer this compared to having less overall visibility of the roadmap. You just need to pay attention to dates and caveats.
            • Office 365 and cloud revenue is powering investment!
              • Remember a couple of years ago people were asking if SharePoint was dead? Feels like a different world now. I think one big factor is that Microsoft are further up the adoption curve of Office 365, and the corresponding revenue and outlook means that big ambitious goals can be set. I can imagine that various product groups are a little larger and have more resources. Another one is that lots of infrastructure/scale/foundational challenges have clearly been dealt with now – leaving an increased focus on providing great tools and a modern development platform to users.

            My original wish list

            Anyway, back to my list – here’s what I said Microsoft should provide. I didn’t blog this, but put it on LinkedIn strangely - maybe it was a prophesy related to the increased integration between LinkedIn and Office 365 ;)


              What got delivered/announced, and what didn’t?

              I initially just had some checks/crosses against each item, but then I added some notes, and then some timelines, and finally I ended up with the table below. This might only be useful to me personally, but hey, if it’s useful to you too, then great. It could have more comprehensive notes/links, but that’s probably a bigger task than I can deal with right now! So:





              Tagging/metadata for modern pages

              Not really

              H1 2018

              “Categorization” mentioned for 2018

              Associate existing SP site with


              Early 2018

              PowerShell will also be possible. See “BRK2434 – No team site left behind”

              Provisioning/templating for
              Communication Sites (ideally PnP)


              Q4 2017

              Site Designs (previously known as “Recipes”).*See special note on Site Designs below

              Page layouts for Communication


              Q1 2018

              Profile page extensibility




              Web hooks on Group creation



              Nothing imminent, but a *custom*
              site design can call out to a Flow

              Provisioning/templating for Teams
              (tabs, connectors, bots)




              More modern web parts (e.g.


              Q4 2017
              • Planner/Forms web parts
              • Enhancements to Highlighted Content web part (provide query)
              • Enhanced web part picker

              SPFx enhancements


              • Site scripts/site designs (Q4 2017)
              • Simplification of calling Graph/custom web APIs secured with AAD
              • Site Collection App Catalog etc. (Q4 2017)

              Some ‘under the radar’ things!


              • Multi-geo (OneDrive/EXO now, SPO in 2018)
              • Hub Sites (early 2018)
              • OneDrive Files on Demand (Q4 2017)
              • Conditional Access per site (early 2018)
              • Simpler sharing e.g. verification code links for external users (Q4 2017)
              • List enhancements e.g. formatting, attention view, indexing and Flow improvements etc. (Q4 2017)
              • Better site/content analytics (early 2018)
              • LinkedIn integration with Office 365 people card (Q4 2017)

              but not yet delivered


              • New Admin Center (First Release Tenants in early CY2018)
              • App Launcher updates
              • PowerApps for SharePoint lists (October 2017 for FR tenants)
              • PowerApps enhancements e.g. upload attachments, simpler conditional views etc. (before end 2017)

              NOTE:– I’d love to hear from anyone who spots an error or something I missed with these details (e.g. a timeline). Please leave a comment if you don’t mind and I’ll update!

              My thoughts – especially on the missing items

              So Microsoft didn’t deliver everything I was hoping for. BUT, they did deliver a whole bunch of things that weren’t in my list! I list most of these in the “under the radar” and and “previously announced, but not yet delivered” categories. Us MVPs are fortunate enough to have something of an inside track on most of them (thanks Microsoft, your work here is MUCH appreciated by the way) so I had familiarity lots of them before the event. It’s great that those categories have so many items, and no doubt many more could be added too. BUT:

              •  Tagging/metadata for modern pages
                • I was disappointed not to hear more on this. It feels like there are still significant gaps when it comes to building solutions around modern pages, especially when it comes to roll-ups and displaying content of different types (e.g. pages tagged with X). Yes, there’s a new PnP re-usable control, but you’d have to do some work to integrate this, and that feels like Microsoft’s job to be honest.
              • Profile page extensibility
                • Still nothing. What’s up with that? This has been talked about for a LONG time, but still we can’t add custom widgets or tailor the Office 365/Delve profile page. I didn’t even hear any mention of it to be honest, yet lots of organizations I work with want to do something there.
              • Web hooks on Group creation (site)
                • Again, nothing here either. Vesa has mentioned some engineering considerations around providing this, but I was hoping for an announcement so that applying a custom PnP templates to self-service created Office 365 Group sites would become easier. Sure, a Flow can be used with the forthcoming Site Designs capability, but that seems to still leave a gap for default sites which don’t use any kind of Site Design, like an out-of-the-box Group site. The info was only released on this yesterday, so I could be missing something though – hope so..
              • Provisioning/templating for Teams (tabs, connectors, bots)
                • Lots of progress on Microsoft Teams, but still no proper templating story. I was *really* surprised not to hear something on this - I definitely have clients who want to use Teams at scale, but with the same set of custom tabs etc. Configuring by hand just isn’t an option, so let’s hope for something soon (again, unless I missed it).

              Of course, let me know if I am missing anything, or you disagree with my interpretation of things.

              * A note on Site Designs

              So, we do have a way of applying templating to Communication Sites (and it goes beyond that – Site Designs can be also applied to Team Sites created from the out-of-the-box UI, so this is a big deal). But, right now I do have some reservations on the model here. Obviously there’s ANOTHER way to define a site template now (the JSON format used by Site Designs, which doesn’t look too easy to work with actually – seems like there are quite a few attributes/actions to understand), and that feels sub-optimal given that the PnP provisioning building blocks have evolved so much. We *can* integrate PnP provisioning (woohoo), but the architecture is Site Design > Flow > Azure queue item > QueueTrigger/Azure Function > my PnP provisioning code. Which is fine and ticks many boxes, but:

              • Frankly I would have preferred some form of Microsoft-hosting my PnP provisioning template and taking care of the execution. The fact that we still need Azure can be a blocker for some organizations, and means there is still a level of complexity, and a chunk of work for us to do. It was pointed out to me that Microsoft may have chosen this approach because they don’t want to host/support PnP provisioning themselves (as a community effort rather than pure Microsoft), and I guess I can understand that actually. But still..
              • Templating Office 365 Group sites still seems to be a gap. Yes, I can call out to my Flow for a site which *does* have a custom Site Design – but what about Group sites which are springing up as users create Groups/Teams/Planner plans/Power BI workspaces etc.? There’s a way in which a default Site Design can be specified at the tenant level, but will this apply to Group Sites? I’m not clear at this stage. But I certainly want the capability of applying a custom template to a Group-connected site in a timely way.
                • UPDATE – just minutes after publishing, I picked up on the detail in the video linked below, that it IS possible to target a Site Design at an out-of-the-box Group Site. This is done by associating your Site Design to WebTemplate=”64” for a Group site, or WebTemplate=”68” for a Communication site etc. Happy days.

              I still think it’s something of a shame to have another templating language/approach though. Which bits of the template will be done in the Site Design and which in a PnP template? I can imagine lots of different approaches being used for this. But of course, the main advantage is that this form of templating integrates with the out-of-the-box UI for creating SharePoint sites, which opens up a lot of possibilities. I just wonder if in the end, we’ll be implementing “shell” Site Designs which call out to a PnP template which does the real work of creating content types/lists/pages/web parts and so on in the site. Let’s see..

              For more on Site Designs, see


                Despite not hitting all items on my list (which are just the views of one guy of course – everyone else has their priorities too), I think Microsoft are actually exceeding what I hoped for. Yes, there will always be gaps and as you can imagine, there are LOTS of things I’m not covering here. Whether it’s general developments such as new Office 365 Plans or Bing for Business, the raft of enhancements to Microsoft Teams (e.g. taking the place of Skype for Business for online), or developer-focused things such as Graph enhancements (e.g. Extensions in Azure Functions, SP list data in the Graph etc.), there’s lots of other things to keep up with. Some good starting points for further reading are:

                Wednesday, 20 September 2017

                Use Azure App Insights to track events in your app/web part/provisioning code

                In my recent post Add Azure App Insights or Google Analytics to your SharePoint pages with an SPFx Application Customizer we focused on the page tracking/analytics capability of App Insights. But what I really think is cool is the ability to track what is happening your code – whether it’s simply that your web part has executed or your app has been launched (so you can get counts), or that you showed an error message to a user (with the details), or maybe to understand where users are navigating in your app or which options they select. As an example, we have a tabbed interface in one particular app, and I’d really love to know how many users are actually navigating to the 2nd and 3rd tabs (my bet is very few). Well, App Insights event tracking is great for these scenarios and more. I finished the last post with this list:

                • Server side applications (Office 365/SharePoint Add-in)
                  • How many app launches are happening? By who/where?
                  • What is happening within the app (e.g. which buttons are being clicked/what functionality is being used)?
                • SPFx/Graph
                  • How many executions is our web part getting per day?
                  • How long do my web parts take to execute on the client side?
                  • How long are my async calls taking (e.g. to the Graph)? How different are they for users around the world?
                • Provisioning code
                  • How many sites are we creating per day/week/month?
                  • How many times do we hit an issue during provisioning?
                  • How long does provisioning take?
                • General
                  • How many times are we showing an error message to a user?

                You get the idea.

                A quick getting started recap (for JavaScript/SPFx)

                Remember that to use App Insights you need an Azure subscription and an App Insights Resource to be created – this will give you the instrumentation key which you obtain from the Azure portal (see my last post for more details). If you’re working with JavaScript/TypeScript/SPFx, there’s an npm package you can install with:

                npm i applicationinsights-js --save

                From there, you'll need the couple of lines which get you started. The import statement at the top of your module:

                import {AppInsights} from "applicationinsights-js";

                ..and then the initial bootstrap code which references your App Insights key:

                let appInsightsKey: string = "[YOUR KEY FROM THE AZURE PORTAL HERE]";
                AppInsights.downloadAndSetup({ instrumentationKey: appInsightsKey });

                Now you're ready to log various things which happen in your code to App Insights. In essence, we drop a line in when we want to log that something has happened - let's look at some examples.

                Example 1 – logging a call to the Microsoft Graph (in SPFx code)

                The code below fetches calendar events for the current user in SPFx code, and is taken from one of the SPFx React samples. This is a fairly typical use of the Microsoft Graph, and the logging approach used here could be used across lots of similar scenarios. The fact that it is in a React component is not important, but the bits to focus on are the calls to App Insights - note that what I’m also doing is recording the *time* taken to make the call, so as well as finding many times my web part is being used, I also start to understand how long calls to the Graph are taking for users around the world. To do this, I simply create a timestamp before the call, and then another in the promise which executes once the data has been fetched and subtract the difference:

                In App Insights, I can then see an event for each execution of my web part along with the time taken to call the Graph:



                As I showed in my last App Insights post, as you accumulate data you can use the ‘Analytics’ section in App Insights to filter and sort as you need (e.g. on the 'timeTaken’ value):


                Example 2 – logging a call in site provisioning/templating code

                So that’s an example of logging in SPFx. As a different flavor, let’s say you are creating some SharePoint sites based on a template – perhaps as part of a self-service site creation tool. You might be interested in things like:

                • How many sites are being created? With what details?  
                • How long is Office 365 taking to create the base site collection?
                • How long does it take for your template to be applied?

                In this case, you’ll probably be using the PnP Core library in C# code – so you’ll need the App Insights nuget package from

                To get started in C# code, you’ll need some bootstrap code:

                // at top of class..
                using Microsoft.ApplicationInsights;
                // to initialize..
                TelemetryClient telemetry = new TelemetryClient(); 
                telemetry.InstrumentationKey = APP_INSIGHTS_KEY;

                As the first scenario, let’s say you want to log the fact that a site collection was created and how long that step took. If you’re using PnP provisioning code, it might look something like the below – the key things are:

                • Simple use of the .NET stopwatch clock for timings
                • Creation of ‘metrics’ and ‘properties’ dictionaries to pass details to App Insights
                • Use of the TrackEvent() method to actually log the data

                If using PnP provisioning code, you might end up with something like: 

                This would then show up in App Insights with details of the SharePoint URL, and the time taken for site collection creation (shown here in the Analytics tool):


                We can extend this to PnP templating too. In a similar way, I would add logging statements around PnP 'ApplyProvisioningTemplate' call, and perhaps log any errors too.

                Code sample:

                As expected, you can then get the details of your template being applied with whatever details you logged (site URL, template ID and processing time in my case):



                App Insights is awesome for integrating into all sorts of Office 365 and SharePoint dev things. By simply dropping a couple of statements in your code, you get to report on it later and get way better visibility of what is happening than you might otherwise have. Whether it’s executions of your web part, errors which are happening, or how often users are going down particular paths in your app, it’s a great way to build this logging in with low effort. In terms of practicalities, you do need an Azure subscription of course and App Insights is chargeable if you pass more than 1GB of data per month (at the time of writing), and your data is only retained for 90 days. BUT, you don’t need to build any kind of front-end or query tool, you can get graphs/charts, weekly summary e-mails, and importantly, alerts if any conditions you define are not met. Additionally, there are lots of ways to integrate with the data (including BLOB download to keep the data for longer). All considered, the features are pretty awesome.

                I feel App Insights is definitely under-utilized by Office 365 and SharePoint developers, but there are lots of possibilities. I’m looking forward to building it in to more of our solutions!

                Monday, 11 September 2017

                Manage tenant-scoped SPFx extensions across your SharePoint sites

                As I mentioned in Use an SPFx Application Customizer to add JavaScript (e.g. header) to every page in a site, it’s now possible to *globally* deploy SPFx extensions (e.g. page headers, footers or other random pieces of JavaScript) or do a controlled roll-out across *many* SharePoint sites - without the app needing to be installed to each individual site. This is great news, and it was a gap for modern pages until now. SPFx web parts deployed at tenant scope will appear everywhere in the picker, but for SPFx extensions there is still something you need to do locally, and that’s “associate” your extension with the site/web/list/field. For Application Customizers, it’s this step which allows you to control exactly which sites use your extension. To do this you add a CustomAction to your site or web, specifying the GUID of your extension in the ClientSideComponentId property (new for SPFx). Although I’m focusing more on site-level customizations (Application Customizers) in this post, it’s a similar story for SPFx Field Customizers too (ClientSideComponentId is specified on the field) and SPFx Command Set Customizers (CustomAction with ClientSideComponentId is specified on the list). All this can be done a couple of ways:

                • Using CSOM or REST – perhaps in PowerShell or C# code
                • As part of PnP XML, if you are applying a custom template to the site – the XML schema and PnP Core provisioning library now supports this (Sept 2017 release onwards)

                In this post I’ll provide some PowerShell and C# code to help you apply Application Customizers across your sites – you could modify for other types of customizer without too much trouble. However, there are some prerequisites in all cases - in some ways, the association step is one of the last things you will do. So let's cover that quickly:

                Tenant-scoped SPFx extensions - recap/prerequisites

                SPFx extensions and webparts are possible from v1.2 of SPFx onwards. Broadly, the prerequisites needed before the script/code in this article can be used are:-

                • You specified "skipFeatureDeployment": true in the package-solution.json file
                • The app was packaged and then installed to the App Catalog, and the administrator checked the box for 'Make this solution available to all sites in the organization' (shown in image below)
                • The JavaScript bundle for the SPFx app has been deployed to a CDN or other web-hosting location

                Here's what the administrator will see when installing to the App Catalog, and the checkbox (which they need to check) that appears when "skipFeatureDeployment": true:


                The PnP XML option

                I'll focus on the C#/PowerShell options in this post, but there’s a PnP XML option which is very useful too. This allows you to include the association as part of a custom site template, and therefore is great for any sites being newly-created from such a template. In fact, you could also use it to apply a ‘partial’ template to existing sites, but I think most people might choose PowerShell or C# code at that point. The main info I want to convey here is that this is available from version 2.18.1709 onwards of PnP Core (Sept 2017 release). The 2017-05 schema has places to specify the ClientSideComponentId property on a CustomAction and on a field, since that’s what the association consists of. The XML extract to provision an Application Customizer at the web level would be:

                In next sections, I’ll cover PowerShell first and then C#.

                Using PowerShell code and PnP PowerShell

                Here are some PowerShell functions to add, remove and list the SPFx global extensions across a selection of sites, done by adding a Custom Action at the root web level – tweak if you need something else. I'm using a simple array of site URLs here, but you could fill that array however you like. Other notes:-

                • I'm using PnP PowerShell cmdlets here - you'll need to install those if you don't have them already, and then get connected to your tenant with Connect-PnPOnline etc.
                • At the time of writing, I had an issue with the PnP cmdlet that they provide (Add-PnPCustomAction), so I'm using direct CSOM in the 'add' method. I raised a GitHub issue about this (also noted in comments in script below), and I'm sure the guys will fix it soon (or tell me I'm doing something wrong ;), but the direct CSOM approach works fine too)

                Registering a globally-deployed extension with addSpfxExtensionCustomAction(ctx) will give:


                Listing the extensions on a site with:

                Get-PnPCustomAction -Web $ctx.Web | Where-Object {$_.Location -eq "ClientSideExtension.ApplicationCustomizer" }

                will give:


                Removing an extension with

                Remove-CustomActionForSPFxExt $spfxExtName $site $ctx

                will give:


                Using C# code and PnP core

                But instead of PowerShell, perhaps you want to use C# code instead. Some notes on this:-

                • I'm using the PnP Core library here - you'll need to install the NuGet package to your solution/Azure Function/whatever if you don't have it already. Get this from
                • In contrast to the PowerShell above I'm only processing a single site here, but it would be trivial to extend the code to run across whatever sites you need

                Sample code:


                As you’d expect, registering a globally-deployed extension with addSpfxExtensionCustomAction(ctx) will give:


                Listing the extensions on a site with getCustomActions(ctx) will give:


                Removing an extension with removeSpfxExtensionCustomAction() will give:


                Another option – CLI scripts

                As another option, note that my esteemed colleague Vardhaman Deshpande also has a super-cool CLI tool to help you manage SPFx extensions. He’s so hipster ;) His scripts offers the ability to manage SPFx Command Set Customizers too. See for more details.


                For tenant-scoped SPFx Application Customizers, you need to ensure the sites or webs which should use it have a CustomAction with the ClientSideComponentId of your extension (in addition to dealing with the other prerequisite steps i.e. getting the app package and corresponding JavaScript bundle deployed). Although not addressed with this code, it’s a similar approach for SPFx Field Customizers and Command Set Customizers too. Hopefully the options presented in this article (together with the underlying PnP awesomeness) are of some use.