Patterns and Practices (PNP) – Inquisitive M365 https://thomasdaly.net Yet another SharePoint / Office 365 blog Fri, 06 Mar 2026 14:43:42 +0000 en-US hourly 1 116451836 Sort Your SharePoint Site Directory Alphabetically https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/ https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/#comments Sun, 02 Feb 2025 21:53:07 +0000 https://thomasdaly.net/?p=3339 In my previous article, Build a Site Directory with PnP Search Web Parts, I walked through how to create a dynamic site directory using PnP Modern Search. While that setup provides a powerful and flexible way to display SharePoint sites, you may have noticed a limitation—SharePoint doesn’t allow sorting by the Site Title property out of the box.

This article covers the extra step needed to sort your site directory alphabetically by title. The trick? Leveraging RefinableString fields to make the Site Title sortable. It’s a simple process with just a few tweaks, and by the end of this guide, you’ll have a properly sorted site directory in no time. Let’s dive in.

Updating the Search Schema

Navigate to the SharePoint Admin Center

Expand ‘Advanced’ then click ‘More Features’ and finally click ‘Open’ under the ‘Search’ group

Next click ‘Manage Search Schema’

Next enter ‘RefinableString’ in the search box and click the green button

Hover over any of the available properties and find the drop down, then click ‘Edit Map Property’

It’s not critical on what number refinable string you choose

Scroll all the way to the bottom and click ‘Add a Mapping’

Enter ‘display’ and click ‘Find’, then select Basic:displaytitle and click O

Verify the mapped managed property and click ‘OK’

This completed the Search Schema changes. These can take quite some time to take effect so be patient. It could be a day before you see it working.

Next navigate to the SharePoint page with the PnP Search Web Part configured as a Site Directory

NOTE: The following steps are only necessary if you have customized the Custom template.

  1. Edit the page and open the web part properties of the Search Results web part
  2. On the second page, click on the curly braces { }
  3. Take a copy of the entire

Change the template to Debug. This is so that you can visually see the property to ensure that the search property has taken effect.

Go back to the first page of the web part properties, enter the name of the RefinableString## you modified and hit Enter.

The result should appear on the left hand site – most likely it will read null to begin with. It will eventually populate. It can appear at any time but at least wait 8 hours or a full day. Recheck the steps in the search config but at this point there is not much more to do but wait.

What to do if the site title will no show up?

If it’s just not showing for a few sites

  • Update the Site Title of the site. Change it temporarily and then change it back
  • Trigger a reindex on the 1 site

If it’s not showing up for many sites

Recrawling puts strain on the service as a whole so it’s not meant to be run over and over as it can take weeks to finish on very large sites.

After the crawl property appears move on to the next step.

Apply the Sort

Navigate back to the Search web part page and edit the web part properties

Click ‘Edit sort settings’

Type in your RefinableString## into the Field name box, click Default Sort and then click ‘Add and save’

The sorting is now set to alphabetical order from A-Z by default.

Next go to the second page of the web part properties

Set the template back to what it previously was. In our case Custom and then click on the { } to edit the custom template

Copy / Paste in the template, Save and Republish.

The final result should be in order by site title.

Wrap Up

Sorting your SharePoint site directory by title might not be possible out of the box, but with a little creativity—leveraging RefinableString fields—it becomes a straightforward solution. By following these steps, you can ensure your directory is organized in a way that makes finding sites easier for users.

This small but impactful tweak enhances usability and keeps your directory structured exactly how you need it. If you’re already using PnP Search Web Parts, this is a great optimization to implement. Have questions or run into issues? Drop a comment—I’d love to hear how this worked for you!

]]>
https://thomasdaly.net/2025/02/02/sorting-your-sharepoint-site-directory-by-title-with-pnp-search/feed/ 2 3339
PnP PowerShell V4 Provisioning with Azure Functions V3 and Power Automate / Flow https://thomasdaly.net/2021/04/09/pnp-powershell-v4-provisioning-with-azure-functions-v3-and-power-automate/ https://thomasdaly.net/2021/04/09/pnp-powershell-v4-provisioning-with-azure-functions-v3-and-power-automate/#respond Fri, 09 Apr 2021 17:56:16 +0000 https://thomasdaly.net/?p=2357 Introduction

Trying out the new way to Provision via PnP PowerShell V4 and Azure Functions V3 was a little challenging at first. There are some of the difference and issues that I encountered which I could not get to work correctly. I happen to be one of the early ones that need to do this because Azure had made a change to their interface which prevented using PnP PowerShell V3 and the Microsoft documentation was not updated. Since that time and now Microsoft has updated their online documentation with examples of the exact steps. I’ve decided to post the process I used to get everything working but I still suggest reading the official Microsoft article as well.

Install PnP.PowerShell

  1. Open PowerShell 7 (if not installed, please install from here – https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1)
  2. Run the following cmdlet to install the PnP.PowerShell module

Install-Module -Name "PnP.PowerShell" -RequiredVersion "1.5.0"

Set up app-only access to your tenant

  1. Open PowerShell 7 and run the following cmdlets to register an Azure App

Select the appropriate tenant name before running.

Register-PnPAzureADApp -ApplicationName "PnPProvisioningDemo" -Tenant "<tenant-name>.onmicrosoft.com" -DeviceLogin -OutPath .

Follow the instructions to complete the Azure AD App registration. You will need to open a browser and enter the url above and supply the code. You will also be asked to log in.

This will now take 60 seconds to create the certificate in the out path that was specified in the above command

  • After the cmdlet is executed. It will create a PFX file. Keep this file saved, as we will have to upload it to Azure function.
  • Login to https://aad.portal.azure.com/
  • Click -> Azure Active Directory -> App Registration
  • Search for ‘PnPProvisioningDemo’ and the select the App Registration which got created. Copy the Application (client) ID from here.
  • Click API Permission
  • Click API Permissions, and Grant admin consent for {tenant}
  • In the small popup click Yes to approve this app those permissions.

Create the Azure function

  • Type in ‘Function’ and select ‘Function App’
  • In the Project Details, click on Create New, for the Resource Group
  • Type in ‘PnPProvisioningDemo’ for the resource group name, click OK

  • Enter in a Function App name – this will need to be unique, Runtime Stack, Version and select a Region in which you want the resources inr its created, navigate to your new function App
  • From the dropdown menu, select host.json file and add the following entry and save it.
  • Click ‘Review + create’
  • Click ‘Create’

After a few moments all of the assets will be created.

  • Click ‘Go To Resource’
  • Next click on ‘App Files’
  • I typically bump the timeout to 10 mins for the Azure Function from the default 5 minutes.
  • In the App Files > host.json, add this line. Make sure to use a ‘,’ on the previous line
"functionTimeout": "00:10:00"
  • Click Save to lock in the changes
  • Click on the dropdown and select requirements.psd1
  • You can remove the ‘Az’ = ‘5.*’ as it won’t be used
  • Click Save to lock in the changes
  • Create a new Azure Function Functions > Add:
  • Create a new HTTP Trigger function, by selecting the options as shown below
  • Scroll down, name the function InvokePnPSiteTemplate
  • Set Authorization level, Anonymous
  • Click Save

Upload the code for your Azure Function

  • Go to the Function App main screen and select Advanced Tools
  • Click “Go”, this will open Kudu
  • Select “PowerShell” from the Debug Console menu at the top.
  • Navigate to site\wwwroot\InvokePnPSiteTemplate

This is where it gets complicated. Hold on to your hats.

Extract the AzureFunCode.zip file provided as a sample.

  • Add your PnP template into the pnp-template.xml file
  • Update run.ps1
    • set $filePath to the correct drive [C or D] that you see in the azure portal
  • set $AzAppId to match your Azure App Id
    • set $certFileName to match your exported certificate
    • set $tenant to match your tenant prefix
  • Drag & drop the files to the site\wwwroot\InvokePnPSiteTemplate directory

NOTE: If you want to use a different version of PnP PowerShell then you can generate the PnP.PowerShell files for upload from the command line. Use the folder that is exported to upload.

Create a new folder and then execute the following commands

Save-Module PnP.PowerShell . 
  1. After the code is updated. Navigate back to Function screen on Azure portal and click on ‘Get Function Url’ and copy the URL

Create the Flow

  1. Go to the Power Automate site, sign in, and choose Create -> Automated Cloud Flow
  2. Click Skip at this screen
  1. Click ‘untitled’ and give the Flow a name, PnPProvisioningDemo
  1. Search for Request, and select Request – When a HTTP Request is received.
  1. Enter the following JSON as your request body:
{
    "type": "object",
    "properties": {
        "webUrl": {
            "type": "string"
        },
        "parameters": {
            "type": "object",
            "properties": {
                "event": {
                    "type": "string"
                },
                "product": {
                    "type": "string"
                }
            }
        }
    }
}
  • Select + New Step and choose Add an action.
  • In the search box type ‘http’ and click HTTP
  • Configure the properties as shown below.
  • You also need the Azure Function, HTTP endpoint. This is in the Azure Function, Overview screen, click Get Function Url
  • Copy this http endpoint to then paste into the flow
  • Choose Save Flow. This will generate the URL that you will copy in the next step.
  • Back in the Flow, Paste the URI in this box
  • Save the Flow
  • Once save is completed, click back on the first step and copy the Flow HTTP Post Url. Save this for later

Create the Site Design

In this section we are going to create a SharePoint Site Design, based on a Team Site template.

  1. Open SharePoint Online Management Shell and connect to your tenant using Connect-SPOService
Connect-SPOService -Url https://[yourtenant]-admin.sharepoint.com
  • Update the URL property in the code below. Set the url property to the value you copied when you created the flow
{
  "$schema": "schema.json",
  "actions": [
   {
      "verb": "triggerFlow",
      "url": "{UPDATE THE FLOW URL HERE}",
      "name": "Apply PnP Template",
      "parameters": {}
    }
  ],
  "bindata": {},
  "version": 1
}
  • Select the JSON again and copy it, this will put it on your ‘clipboard
  • Open PowerShell and enter the following to copy the script into a variable and create the site script:
$script = Get-Clipboard -Raw
#before the next step verify you have data in $script by typing this
$script
#if that is empty try the copy and run the first line again.
Add-SPOSiteScript -Title "Contoso Team Config" -Content $script
Get-SPOSiteScript
  • You will see a list of one or more site scripts, including the site script you just created. Select the ID of the site script that you created and copy it to the clipboard.
  • Use the following command to create the site design:
Add-SPOSiteDesign -Title "Contoso Team" -SiteScripts {Paste the ID of the Site Script here} -WebTemplate "64"

Conclusion

That completes all the necessary steps to get the basics up and running. Hope this was helpful walkthrough to make your first time getting started a little easier. The screens are constantly changing in Office 365 but the basics steps should remain the same. Leave a comment below if you get stuck or have a suggestion.

]]>
https://thomasdaly.net/2021/04/09/pnp-powershell-v4-provisioning-with-azure-functions-v3-and-power-automate/feed/ 0 2357
PnP PowerShell V4 and Azure Functions V3 – First Look https://thomasdaly.net/2020/12/19/pnp-powershell-v4-and-azure-functions-v3-first-look/ https://thomasdaly.net/2020/12/19/pnp-powershell-v4-and-azure-functions-v3-first-look/#respond Sat, 19 Dec 2020 02:06:59 +0000 https://thomasdaly.net/?p=2258 I’m writing this blog to share my experiences with working the latest version of PnP PowerShell V4 this .NET Core version and Azure Functions V3.

Background

Up until a few weeks ago I was able to write PnP PowerShell provisioning code and run it in an Azure Function V1 to do almost anything I wanted in my SharePoint site. I was receiving warnings that Azure was going to be deprecating the V1 functions but not pay much attention. This forced me to try using the new way of using the Azure V3 function which run PowerShell .NET Core and the new PnP PowerShell libraries built on .NET Core.

Azure has removed all ways through the UI to use experiment languages. You can set the PowerShell Azure function to run in V1 mode, however the toggle switch to enable experimental languages has been removed. Rendering this article is no longer valid – https://docs.microsoft.com/en-us/sharepoint/dev/declarative-customization/site-design-pnp-provisioning#create-the-azure-function [UPDATE: 11/25/2020 – Microsoft has updated that article]

The now older version of PnP PowerShell is referred to as PnP PowerShell V3 which is built on the CSOM for .NET 4.5 Libraries. This runs in PowerShell up V5

The newer PnP PowerShell is referred to as PnP PowerShell V4 which is built on the CSOM for .NET Standard 2.0. This run in PowerShell V7.

You can read more about this here – https://github.com/pnp/PnP-PowerShell. A tremendous amount of work has been done to make the libraries available for .NET Core. It’s time we all start using the new V4 version and help the project by submitting defects and contributing.

My Experience

I was faced with many issues which I will outline. While this was my first time experimenting with the new PnP PowerShell and the Azure Functions V3 it was not an easy one. I wrote this article before changes to official Microsoft documentations updates and had to learn by trial and error which can be tedious.

  1. On Demand Loading – the function now use a requirements.ps1 file that contains a manifest of the libraries that your function will using. This is how you load the PnP PowerShell libraries. The files will be downloaded on demand when your function is initialized and will stay in memory until your function goes to sleep.
  2. Problems Connecting / Authentication – I believe there is some issues with Authentication as I spent many hours trying various combinations to work. I would recommend using a certificate as that is the only way I was able to get the functions to work correctly. I think it’s possible some pieces of PnP PowerShell V4 are not working 100% in Azure Functions. I was using 0.2.15-nightly
  3. Different Commands – not a huge deal but you need to be aware that some of the commandlets have changed and should update them accordingly. It’s well documented just be aware.
  4. Pre-Release Version – the PnP PowerShell is still currently pre-release and scheduled to be GA in Jan 2021. We can’t do anything about this, if you need this functionality you will be using the pre-release version. It shouldn’t matter too much if the functionality works with the version of PnP PowerShell that you built it on then you are fine. Somethings may or may not work – always send feedback in the github repo’s for issues.
  5. Timeouts – the on demand loading seemed to timeout my functions [default 5 mins max on Azure Function runtime] this was a problem with the libraries taking 3-4 minutes to load and my code only had 1 minute to finish.

In the host.json file I had increased the timeout to 10 minutes to account for this. At the time of this article I have not tried to upload and host the libraries in my function [more on this in another article]

updating host.json file

Summary

Since writing this article I have made more progress in this area. I will post a follow up in the next week with a walk through of setting up a site script to kick off a Power Automate Flow, that runs the Azure Function to make some modifications to a SharePoint site. I’ve had a lot of fun playing around and experimenting with different flows and can now appreciate this method along with the power behind it. I am excited to see the progress here and looking forward to future updates from the PnP PowerShell team!

]]>
https://thomasdaly.net/2020/12/19/pnp-powershell-v4-and-azure-functions-v3-first-look/feed/ 0 2258
Set Modern Page Properties with PnP PowerShell https://thomasdaly.net/2020/06/01/set-modern-page-properties-with-pnp-powershell/ https://thomasdaly.net/2020/06/01/set-modern-page-properties-with-pnp-powershell/#comments Mon, 01 Jun 2020 19:59:31 +0000 https://thomasdaly.net/?p=1857 Recently I had to provision a number of modern pages w/ some additional page properties. These page properties were custom fields added as columns to the Site Pages library. I found it somewhat annoying that there was not direct way to provision a page via PnP PowerShell with properties.

This blog covers the 2 steps w/ code on creating a new modern page (aka client side page) and then getting that page as a list item and updating its properties.

Step 1 of creating the page is very simple but, as you can see, you cannot supply additional values for custom properties. https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/add-pnpclientsidepage?view=sharepoint-ps

Add-PnPClientSidePage -Name "My New Page" -PromoteAs NewsArticle -Publish

Step 2 is to find the page and then update it as a list item. In case you didn’t know, everything inside the -Values @{} are your custom properties. https://docs.microsoft.com/en-us/powershell/module/sharepoint-pnp/set-pnplistitem?view=sharepoint-ps

$page = Get-PnPListItem -List "Site Pages" -Query "<View><Query><Where><Eq><FieldRef Name='Title'/><Value Type='Text'>My New Page</Value></Eq></Where><RowLimit>1000</RowLimit></Query></View>"

Set-PnPListItem -List "Site Pages" -Identity $page.ID -Values @{"Title"="My New Page";"Classification"="News";"Article_x0020_Date"=$startDateTime.AddDays($i); "LocationTag"="Enterprise Taxonomy|Locations|$location";}

I was unable to find a command-let to just get me the page by title. This CAML query should help you out.

]]>
https://thomasdaly.net/2020/06/01/set-modern-page-properties-with-pnp-powershell/feed/ 4 1857
SPFx Application Customizer that works on Classic SharePoint Sites https://thomasdaly.net/2019/08/28/spfx-application-customizer-that-works-on-classic-sharepoint-sites/ https://thomasdaly.net/2019/08/28/spfx-application-customizer-that-works-on-classic-sharepoint-sites/#comments Wed, 28 Aug 2019 13:48:41 +0000 https://thomasdaly.net/?p=1685 Introduction

Over a year ago I create a cross site collection navigation solution aka global navigation for Modern SharePoint sites using all the Microsoft goodies like SPFx, PowerShell PnP, PnP-JS & Office UI Fabric. At the same time, I had a very similar solution for Classic SharePoint sites for a different batch of clients. It was fairly typical for clients new to Office 365 go straight Modern and some of the more traditional SharePoint clients to stick with Classic sites.

One day I was asked to put the global navigation on the Classic site and the Modern sites. It just didn’t feel right to me having 2 separate solutions. One being built with jQuery and JavaScript while the other built in SPFx using TypeScript, SCSS & React. The SPFx being the more current way of developing client-side solutions has spoiled me. I don’t dislike jQuery / JavaScript solutions… I just prefer the tooling SPFx offers for us SharePoint developers.

New call-to-action

How can an SPFx Application Customizer work on Classic sites?

If you break it down, part of the secret sauce behind SPFx is that it’s simple a wrapper around plain old JavaScript that tells SharePoint where your file is and load it. SPFx provides other greater capabilities, like property pane which passes parameters to your JavaScript or React components.

For Modern sites when you create a web part or app customizer there is a top level file. For example: in the global navigation projectSpfxGlobalNavigationApplicationCustomizer.ts. This file registers the Application Customizer and then loads the GlobalNav component into the Header placeholder [available on all Modern pages]. Everything inside the GlobalNav.tsx is React and nothing special.

For Classic sites there is no built-in framework to inject components. This is something that must be addressed. In the global navigation project I create a component called ClassicMode.ts which is the top level file.

Inside that file there is a reference to include @bable/polyfill. That helps supplement any browser shortcomings. On a Modern site there are already some polyfills so this would be unnecessary.

Next there is a secondary style sheet which would be used to handle style differences between Classic & Modern sites. In the global navigation project, I am reference the Office UI Fabric library for icons. On a Modern site those are also already there so this would be unnecessary.

Finally, on window load, the GlobalNav component is created into the element #DeltaTopNavigation. The DeltaTopNavgiation is the element where the default navigation is on a Classic SharePoint site.

** For this navigation scenario I am overwriting the default out of the box navigation. You can create a new DOM element and inject that anywhere and mount your React component into that new element. **

That’s it in terms of the code. The code of the GlobalNav component is the same for both Modern & Classic sites. The Modern Application Customizer points to the same files that the ClassicMode component points to.

Building an SPFx Application Customizer for Classic Sites

Going back to what I said earlier, SPFx is simply a wrapper around plain old JavaScript. SPFx allows you to write in TypeScript/React/SCSS but browsers only understand HTML/CSS/JS, not those other languages. All of the SPFx code gets compiled into a single JavaScript file.

You can’t just extract the JavaScript file from the .sppkg package and pop it into the Classic site.. that’s not going to work. The next step is to generate a new JavaScript that uses our new ClassicMode.ts file as an entry point. The key to this is Webpack.

In the SPFx Application Customizer folder create a webpack.config.js. This will tell webpack to use our ClassicModer.ts as the entry point and produce a new file called top-navigation.js in a folder called classic-dist

To execute webpack against this new file just run the following command:
npx webpack --config webpack.config.js

Note: This webpack file uses a few new dependencies that are NOT included with an SPFx project. You must include these new dependencies before you attempt to run webpack against this new config file.

Attaching Classic Mode build to SharePoint Site

The last thing we need to cover is how to hook up this file into your Classic SharePoint site. It’s straight forward and if you made it this far it should be a piece of cake.

Step 1 – Upload the file. You can manually copy / paste the file into SharePoint. Alternatively you could host this file on a CDN if the plan is to use it on more than 1 site collection.

Step 2 – Connect the JavaScript file to your site collection. You can’t do this through the UI unless you use a tool like SP-Editor for Chrome to attach a site script link

Alternatively, check out how I upload it and activate it using PowerShell PnP with a deploy script.

Classic Mode Deploy Script

Conclusion

That wraps up how to use your SPFx Application Customizer on a Classic SharePoint site. The most complicated part for me was building out the webpack.config.js file. It was a little tricky finding the right polyfills, getting the loading to work and testing across versions of SharePoint. I have even used this approach, for this project SPFx Global Navigation Application Customizer, on a SharePoint 2013 site. Interested in that solution check out my other article Cross Site Collection Navigation for Modern & Classic SharePoint Sites. Enjoy!

]]>
https://thomasdaly.net/2019/08/28/spfx-application-customizer-that-works-on-classic-sharepoint-sites/feed/ 4 1685
Cross Site Collection Navigation for Modern & Classic SharePoint Sites https://thomasdaly.net/2019/08/28/cross-site-collection-navigation-for-modern-classic-sharepoint-sites/ https://thomasdaly.net/2019/08/28/cross-site-collection-navigation-for-modern-classic-sharepoint-sites/#comments Wed, 28 Aug 2019 13:47:43 +0000 https://thomasdaly.net/?p=1672 TL;DR Go here for the code + instructions: https://github.com/tom-daly/spfx-global-navigation
Modern version works with: Office 365 & SharePoint 2019 – IE 11, Chrome, Firefox.
Classic version works on any SharePoint [yes any] – IE 11, Chrome, Firefox

Introduction

Maintaining a consistent navigation across all site collections has always been a problem for SharePoint. Site collections do not share navigation. The story goes back to the beginning of SharePoint’s existence. In earlier versions 2007, 2010… it was recommended to break up sites into site collection to keep the content database sizes small. Microsoft had recommended maximums for best performance. Ultimately the content of SharePoint are table in a SQL databases and small databases meant faster, more manageable backups. Alternatively you could have all your sites in one site collection and then all the out of the box navigation options would be perfect.

Enter Modern… Each modern site is a site collection. This approach creates a flat hierarchy of sites. Each site collection having its own navigation, security, look and feel, content, components and more.

How can you create a consistent navigation across modern pages? Microsoft’s answer is to use Hub sites. “Hubbing” your sites will add a hub site navigation element to the top of the page.

Great! Hub sites to the rescue… What if you have some classic sites? Most organizations are currently in a hybrid mode of classic and modern pages. You can’t hub classic sites.

This blog will cover the solution that I built to add a list based navigation to modern pages using SPFx application customizer. But wait there’s more… It will also show you how you can use the same code base and repackage it to work on Classic SharePoint sites as well. Essentially creating the perfect cross site collection navigation solution that works on both classic and modern.

Solution Overview

The solution is broken down into a couple of parts. This blog is meant to explain the approach and the github repository contains an in depth guide to install and provision.

  1. Navigation List – PnP Powershell Template + Provisioning scripts
  2. SPFx application customizer – Global Navigation – React Component

Step 1 – Provision the Global Navigation List

I’m all about repeatable provisioning – as a developer I almost never create anything manually. In this solution I use Powershell PnP, mainly the provisioning template to provision the site columns, content types and list schema and connecting a lookup like with a cmdlet.

Using the list based approach, I can centrally host the list in the root site of the tenant where my users generally have read access. In the case that you have secured the root site from users, you could break permissions on the Global Nav List and grant read only access.

The list based approach has benefits that I like:

  1. It’s easy to talk to the list and using a simple rest query or PnP-JS as I do in this solution.
  2. Lists can be security trimmed so you can hide nodes from certain groups by breaking inheritance on those items. For those items they would have item level permissions.
  3. Lists are easy to work with for the end users, they don’t need lengthy instructions on how to manage the navigation

The entire list is easily deployable via the deploy.ps1 in the provisioning folder of the project. Check that out for an example of a template and the standard script I use to provision assets via Powershell PnP

Step 2 – SPFx Application Customizer

As of now the only way to install the solution is to build it. Clone or fork the repo and you’ll need to have a SPFx development environment in order to complete the build. Check out the github for the full instructions. Once you have the code, the build and deployment is the standard process for SPFx apps.

Future versions I might include a package that you download, let me know if that’s something you might want. Most people will want to at least customize the colors and best way is to get the code and do it yourself.

The SPFx Application Customizer lives inside the Header placeholder on any modern site that you add the app to. The code has been written such that it makes a call to the Global Nav List on the “/” root site of the tenant. You could change that location in the code and rebuild if you desired by modifying the GlobalNavProvider.tsx

Global Navigation

Once you’ve installed the list, add some nodes, deploy the app customizer, activate the app on a site you should get something like this below. The navigation can support as many levels as you want.

Classic Build

Yes it works on Classic SharePoint as well. By far the coolest part of this whole project. How can that be? For the complete explanation check out this article: SPFx Application Customizer that works on Classic SharePoint Sites.

Classic site deployment process is different. It’s not an app / app package. The solution creates a separate JavaScript file that is uploaded to your site and linked via a site script link.

To generate the latest JavaScript run the ‘build.cmd‘. That will generate both a new .sppkg for Modern sites and the .js file for Classic sites. After a successful build, the top-navigation.js file will be in the ‘classic-dist‘ folder.

If you want an automated deployment approach you would also want to run the deploy.ps1 file. The deploy script will upload the file and attach the JavaScript to your site collection. If deploying to multiple sites it’s a good ideal to centrally host this file in a CDN.

Once the file is attached via a script link, it’s live. Your site should look like this.

Conclusion

There you have it, a global navigation solution built for Modern sites using SPFx, Powershell PnP, PnP-JS, and Office UI Fabric that also works on Classic sites. One code base to maintain for both versions of SharePoint. This provides a flexible, consistent navigation for customers that have a mix of Classic & Modern sites.

]]>
https://thomasdaly.net/2019/08/28/cross-site-collection-navigation-for-modern-classic-sharepoint-sites/feed/ 27 1672
Trimming the Suite Bar + Ribbon on Modern SharePoint Sites in Office 365 https://thomasdaly.net/2018/05/14/trimming-the-suite-bar-ribbon-on-modern-sharepoint-sites-in-office-365/ https://thomasdaly.net/2018/05/14/trimming-the-suite-bar-ribbon-on-modern-sharepoint-sites-in-office-365/#comments Mon, 14 May 2018 08:00:43 +0000 https://thomasdaly.net/?p=1581 Update 2/26/2020 – due to the comments I’ve posted a github project that you can check out to help. https://github.com/tom-daly/spfx-trim-ribbon

What I’m about to show you is a technique that you could use to trim the ribbon and suite bar off an Office 365 – SharePoint site. If you worked with any previous on-prem version we had the SPSecurityTrimmedControl where we could set permissions string. I first learned of this from Dr. Z’s famous post, “How To Hide Ribbon From Users Without Edit Page Privilege

 

New call-to-actionIn comes new modern SharePoint sites and pages where we don’t have master pages to work with. Yet the desire of some clients to remove that top bar for users with minimal permissions still remains. So what can we do? I have 2 ways that I can show you how to accomplish this. Let’s start with the easy method and I’ll save the more complex for another post.

Create an SPFx – Application Customizer 

Create the basic hello world application customer. Click the link in the header to reference the Microsoft guidance. We are focused on the top placeholder for this example but any placeholder would work just fine. If you have an application customizer then skip this section

Now that you have an application customizer with top placeholders you are ready for the good stuff.  For this we’ll use PnP JS library to check user permissions. This is consider the easier method because the PnP JS core library does all the heavy lifting. It allows you to easily make a call given a Permission level. Trust me, doing this yourself requires in depth knowledge about the High/Low security permissions, converting decimals to binary and mapping permissions to a bit on a binary string. If you are feeling adventurous you can read some more details on André Lage’s post “It is SharePoint Permission call FullMask or “NearFullMask” in CSOM?”

Add PnP-JS to your project

Follow the guidance here “Getting Started: Install & Use” with the NPM Install

Now in your application customizer .ts file you need to import PnP

import pnp from "sp-pnp-js";

inside the onInit() you must initialize the pnp.setup before you call your content placeholders. If you don’t do this then pnp won’t be ready to use inside the content placeholders.

  @override
  public onInit(): Promise<void> {
    Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);

    return super.onInit().then(_ => {
      pnp.setup({
        spfxContext: this.context
      });

      this.context.placeholderProvider.changedEvent.add(
        this,
        this._renderPlaceHolders
      );
      this._renderPlaceHolders();
    });

  }

This setups up PnP so it can do it’s work. My application customizer creates a sub component called Header and here is where I do my permission checking and trimming.

 private _renderPlaceHolders(): void {
    if (!this._topPlaceholder) {
      this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
        PlaceholderName.Top
      );

      if (this._topPlaceholder) {
        if (this._topPlaceholder.domElement) {
          const element: React.ReactElement<IHeaderProps> = React.createElement(Header, {});
          ReactDom.render(element, this._topPlaceholder.domElement);
        }
      }
    }
  }

Insides Header.tsx I create a function that will trim the suite bar / ribbon. I am using pnp js to check for a particular security level and then hiding or showing. In my case below I’ve hidden the ribbon for everyone using CSS and then I unhide it here. You can use any of the PermissionKind enumeration listed here

import pnp, { PermissionKind } from "sp-pnp-js";
  public componentDidMount(): void {
    this._trimSuiteBar();
  }
 
 private _trimSuiteBar(): void {
    pnp.sp.web.usingCaching()
      .currentUserHasPermissions(PermissionKind.EditListItems)
      .then(perms => {
        var suiteBar = document.getElementById("SuiteNavPlaceHolder");
        if (!suiteBar || !perms) return; //return if no suite bar OR perms not high enough

        suiteBar.setAttribute("style", "display: block !important");
      });
  }

And there you have it. Suite Bar / Ribbon trimming on Modern Office 365 / SharePoint sites using an SPFx Application Customizer and PnP JS

** Disclaimer ** I have to tell you that this is simply for  information and demonstration purposes. Use at your own risk. It’s not recommended to trim the ribbon or suite bar as it provides functionality to users within the SharePoint site. This is obviously a hack to the product and I’m sure Microsoft would not like you to do this.

]]>
https://thomasdaly.net/2018/05/14/trimming-the-suite-bar-ribbon-on-modern-sharepoint-sites-in-office-365/feed/ 12 1581
The Easiest Way to Attach CSS or JavaScript to your Office 365 or SharePoint Site https://thomasdaly.net/2017/10/29/the-easiest-way-to-attach-css-or-javascript-to-your-office-365-or-sharepoint-site/ https://thomasdaly.net/2017/10/29/the-easiest-way-to-attach-css-or-javascript-to-your-office-365-or-sharepoint-site/#comments Sun, 29 Oct 2017 04:35:46 +0000 https://thomasdaly.net/?p=1477 Introduction
I’m typically asked quite often on how I can attach global CSS or javascript like jQuery to my SharePoint / Office 365 site. There are a number of ways in order to ‘hookup’ or ‘connect’ CSS or JavaScript to your Office 365, SharePoint site. I’m going to review what your options are and what my favorite (easiest) way is. Let’s begin.

Option 1 [Only Publishing Enabled]
+Alternative CSS URL

Pros:
No special tools needed other than the browser of choice.
Very easy to attach a file using the interface.
The CSS can be applied to every sub site under
Different CSS can be applied per site

Cons:
Can only link 1 file in this slot. Once it’s used you can’t link anymore.
Manual process, not scriptable or repeatable.

From Site Settings

Under Look and Feel, Click on Master Page

At the bottom, Expand Alternate CSS URL, Click Specify a CSS file to be used, locate a CSS file to attach, then Click OK

Option 2 [Not Recommended]
+Using Content Editor / Script Editor Web Parts (CEWP)

Pros:
Quickly add CSS / JavaScript to a page by directly copy/paste into these web parts.

Cons:
Works only on that particular page, not a global solution.
If you accidentally delete the web part, you will lose your customizations. (not if you host the customizations in an external files and link it as content source (CEWP only))
Manual process, not scriptable or repeatable.

Option 3 [Best for Multiple Environments / Repeatable / Scriptable]
+Using SharePoint PnP

Add-PnPJavaScriptBlock – used to add a block of JavaScript to execute
Add-PnPJavaScriptLink – used to add links to JavaScript file

Below is some PowerShell PnP used to attach CSS and JavaScript files. In order to reference CSS you must load it via JavaScript. To do that I’ve borrowed some JavaScript that the PnP JS library uses. You can download that here


## CSS FILES
Add-PnPJavaScriptLink -Name "loadStyles" -Url "$($configObject.siteUrl)/Style Library/js/cssLoader.js" -Sequence 0 -Scope Site
Add-PnPJavaScriptBlock -Name "googleFonts" -Script "cssLoader.loadStylesheet(`"https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Condensed:400+700|Alegreya+Sans+SC`", false);" -Sequence 1
Add-PnPJavaScriptBlock -Name "fontAwesome" -Script "cssLoader.loadStylesheet(`"$($configObject.siteUrl)/Style Library/vendor/font-awesome/css/font-awesome.min.css`", false);" -Sequence 1
Add-PnPJavaScriptBlock -Name "styles" -Script "cssLoader.loadStylesheet(`"$($configObject.siteUrl)/Style Library/css/styles.css`", true);" -Sequence 2
## JS FILES
Add-PnPJavaScriptLink -Name "jQuery" -Url "$($configObject.siteUrl)/Style Library/vendor/jQuery/jquery-3.2.1.min.js" -Sequence 0 -Scope Site
Add-PnPJavaScriptLink -Name "moment" -Url "$($configObject.siteUrl)/Style Library/vendor/moment/moment.min.js" -Sequence 1 -Scope Site
Add-PnPJavaScriptLink -Name "resize" -Url "$($configObject.siteUrl)/Style Library/vendor/resize/jquery.ba-resize.min.js" -Sequence 1 -Scope Site

Pros:
Easy to apply JavaScript to your site (takes a little bit more for CSS).
Builds a repeatable method to attach JavaScript & CSS to your site. Great for repeatable process and source control (as you can store these files)
You can use the C# PnP or PowerShell PnP

Cons:
Takes a little bit more than 1 command, need to establish a connection.
Need to be comfortable using powershell or C#.
Need to have the powershell modules installed.
No native command to attach CSS, they recommend using JavaScript to attach CSS.

Option 4 [My Favorite for Quick & Easy Applications]
+SP-Editor / Chrome Only

Download SP Editor plugin from the Chrome Store

Once you have the plugin installed and navigated to your SharePoint site, hit F12 to open the developer tools bar.

Click on the SharePoint tab and then click ScriptLinks. Here you can enter the sequence number to order your CSS references or JavaScript links. You also enter a site collection relative url from JavaScript only. After you enter that information, Click on the Add ScriptLink dropdown and select either current web or site collection

Pros:
Super Fast & Easy
Quickly apply CSS or JavaScript to a site or web (sub site) using the browser

Cons:
Requires Chrome [only a con if your organization doesn’t allow you to have Chrome]
Manual process, not scriptable or repeatable.

]]>
https://thomasdaly.net/2017/10/29/the-easiest-way-to-attach-css-or-javascript-to-your-office-365-or-sharepoint-site/feed/ 4 1477