Monday, 21 January 2019

Update navigation nodes in SharePoint site using PnP-PowerShell

Recently I wanted to update a quick launch link's TITLE and URL in a lot of modern SharePoint team sites. I thought PnP PowerShell would be the best way to loop through the sites and update the links.

You can easily add and remove navigation nodes using PnP-PowerShell by using commands (Add-PnPNavigationNode and Remove-PnPNavigationNode) however, there is no direct command to update it at the time of writing this. Yes, I could add a new link and delete the older one that needs to be updated, but that would change the order of the link in quick launch which I did not want.

So here is a very simple approach to update the navigation link. Get-PnPNavigationNode returns all the links in the navigation.

So fetch the navigation node by filtering on the "Title" and update the required properties. ExecuteQuery on the context of the Nav node.

Tuesday, 30 October 2018

Get File content action in Microsoft Flow using File Identifier and File Path

I was working on a HTTP Triggered Flow that copies a file from one document library to another. I wanted the source and target path of the file copy operation to be dynamic and could also be different site collections, so these paths were sent through the HTTP request body. However, the Flow threw errors that it could not find the Source file. This was because I was using the source file path as-is in the "Get File Content" action.

The Flow that I was building would look something like this

The request body is parsed using the Parse JSON action and the values can be used in the "Get File Content" and the "Create file" actions.

Ideally when the source and target are pre-determined, the flow looks like below.

Now in the Get File content action, the File Identifier is not the same as File path although it looks like it in the UI. We will see this in the upcoming steps.

The request body that we have sent through the HTTP request looks like below. It has all the data that we have used in the two file actions above.

So now we use these values in the "Get File content" and "Create file" actions.

Simple ! but when I execute the Flow, I keep running into an error in the Get File Content action.

 "message""The response is not in a JSON format.",
 "innerError""The resource you are looking for has been removed, had its name changed, or is temporarily unavailable."

To check the "identifier" value, I used the "Get Item" action

So with the identifier value, the Flow worked without any error ! The output of the Compose action shows the identifier value

If you notice the "Get File Content" action, we need to input the "File Identifier" and that is why the path that we used from request body did not work.

Then I discovered there is already an action - "Get File Content using path" to directly use the path that we are getting in the HTTP request body.


Since the identifier is encoded, we can encode the "SourceFileUrl" that we have from the request body and use it in the Get file content action. 

However if you notice, the identifier returned by the "Get Item" action, the spaces are encoded as "%2b" ie "+" and "encodeUriComponent" expression will simply encode the spaces as %20

Using the Get File content using path action is clearly simpler option


Tuesday, 18 September 2018

Copy SharePoint modern site page along with content

Being able to copy a modern site page along with the content and layout enables us to use page templates in a SharePoint modern site. In a scenario where we want to create multiple site pages with a defined template, this functionality comes very handy. For instance, you can create a news page with all the sections and required web parts laid out on it and treat it as a page template to be used to create pages on demand.

For testing purpose, I placed a few web parts on the page template to see if they get copied over correctly and the following web parts worked well. You can try the functionality with other web parts to see if it fits your requirement.

  • Custom SPFx webpart
  • Recent Documents
  • People
  • Quick Links
  • Text
  • Embed
  • Bing Maps

Copying works within the site and also to a different site. When copying a page with custom SPFx web part to a different site, the web part solution must be installed on the target site.

Here is the sample code. It extracts the HTML content and title from the source page and adds the content to the "CanvasContent1" field of the target page. The Code uses PnP Core library - "SharePointPnPCoreOnline" nuget package.

Replace the placeholders in the code below.

Friday, 10 August 2018

Bulk upgrade SPFx solution in multiple site collections using Microsoft Flow

I was recently working on an assignment where we set up an automated Site Collection provisioning process and developed several SPFx webparts. Each of the newly provisioned site collection would have these SPFx web parts provisioned on the pages of the site.

In the web part development process, we re-deployed the solution several times after the initial deployment. This was for the two scenarios below.

Changes made to the already deployed web parts :

When changes are made to the existing web parts which are already deployed to Site collection pages, the process of making updates available to these web parts is easy. Just update the SPPKG file in the App Catalog and replace the web part bundle files with the new build. Once this is done, the web parts in all the sites where the solution is deployed would get the updated functionality

New webparts added to the solution

If you have added new web parts to your SPFx project since the last release, the above process won't make these web parts available in the site collections where the solution was already installed.
In this case, we need to 

  • Increment the solution package version number
  • Redeploy the SPPKG file to App Catalog 
  • Update the web part bundle files in the CDN location 
  • UPGRADE the solution in the site collections.

When we have tens or hundereds of site collections where we need to upgrade the solution, manual upgrade is definitely not an option. We can automate this with a PnP PowerShell script using the "Update-PnPApp" command.

In our case, the list of all the provisioned site collections was available in a SharePoint list column (part of provisioning process where users request for new site.)

Microsoft Flow came to the rescue - Read all the list items and for each site in the list, execute a REST API call using the "Send an HTTP request to SharePoint" action.

ALM API Endpoint to upgrade the solution is (


The GUID of the solution can be found using the PnP PowerShell Command. Connect to a site collection and run the command : Get-PnPApp

Fast and easy !! Hope this helps.

Thursday, 12 July 2018

Extract site classification report of Modern SharePoint sites using PnP-PowerShell

The Classification value of a SharePoint modern Team Site is not exposed through CSOM (at the time of writing this) unlike for the Communication Sites. This property for Team Sites exists on the Office 365 Group object (modern team site has a Office 365 Group connected to it) and can be extracted through a Graph API call.

The latest PnP-PowerShell release supports extracting classification value of a Team Site (Office 365 Group) using the Get-PnPUnifiedGroup command. This makes it very easy to extract a report of classification values of all the Team Sites in a tenant.

Below are a couple of scripts to export classification reports of all the modern sites - both Team and Communication sites in a tenant using PnP-PowerShell in just a couple of lines of code.

Make sure you have  2.28.1807.0 release installed before running the scripts.

Extract report for Team Sites :

To extract the classification report for Team Sites, we first need to connect to Microsoft Graph. Register an APP in and provide it appropriate permissions to be able to read Office 365 Group information. Also make sure you consent the app. Here is some documentation on how to do this

The report extraction might take some time as for each Office 365 Group, a separate call has to be made to the Graph API to fetch its classification value. This will change soon as PnP Core has been updated to the Latest Graph Version which supports extracting the classification value without a separate Graph call. Till this change is available, the report extraction process will be relatively slow :)

Extract report for Communication sites :

For communication sites, we first fetch all the Communication sites using the Get-PnPTenantSite command and filtering on the Template property. Then we get the Site object of each Communication Site and include the CLASSIFICATION property.

Execute the below command with the tenant admin account by replace the placeholders with relevant values in the below script