Friday, June 29, 2018

Using PnP PowerShell to inspect the crawl log in SharePoint Online

One of the lesser know features for SharePoint Online is the ability to look at the crawl log. For on-premises SharePoint, scanning the crawl log is something any search troubleshooter knows how to do, and something I’ve often heard is an ask for SharePoint Online.

A typical scenario is someone asking why their file does not show up in search, or why a user profile hasn’t been updated in search. The crawl log won’t solve these issues, but might give you hints and insights for further troubleshooting as you can see any warnings or errors, and see at what time the item in question was last crawled.

Over two years ago I created a SharePoint App which allows you to search the crawl log and trigger re-indexing (, but I figured the time was right to share this with the world – hence the June release of PnP PowerShell introduced the new cmdlet Get-PnPSearchCrawlLog. But if you fancy a UI, the app is still there :)

selected image

Test it for yourself or take a look at the demo I did yesterday at the PnP sig call.

Tuesday, June 12, 2018

Dynamically load a web part from another web part

I coded a proof of concept last week on how to load a SPFx web part from another web part which I plan to use as pattern for display templates for a search web part I’m planning. By using SPFx parts as render templates we get better control of the code, and avoid script injection on the page.

I figured this approach might be useful for other scenarios so here’s the code to play with :)

The POC loads up two instances of the Modern Script Editor web part, and sets data in it. Which means the modern script editor web part has to be installed on the site you are testing on. Or replace with any of the oob web parts and set the correct properties.

Issues I haven’t gotten to yet as they are not a concern for my scenario are:

  • How to access web part properties of the dynamic loaded web parts in edit mode – can be worked around if the web part has a custom edit UI
  • How to persist the web part data and store it in the main web part – take a look at the serialize method of the ClientSideWebPartManager.
  • The text web part is a special kind of web part, so not sure how to dynamically instantiate it

Full sample can be found at

import * as React from 'react';
import styles from './HelloWorld.module.scss';
import { IHelloWorldProps } from './IHelloWorldProps';
import { Guid } from '@microsoft/sp-core-library'
import { ClientSideWebPartManager, IWebPartManagerContext, IWebPartData } from '@microsoft/sp-webpart-base';
import { DisplayMode } from '@microsoft/sp-core-library';

import { IClientSideWebPartManifest } from '@microsoft/sp-module-interfaces';

let _webPartManager: ClientSideWebPartManager;
let _sampleIdOne = "mAdcOW" + Guid.newGuid().toString();
let _sampleIdTwo = "mAdcOW" + Guid.newGuid().toString();
export default class HelloWorld extends React.Component<IHelloWorldProps, {}> {

    public async componentDidMount(): Promise<void> {
        _webPartManager = new ClientSideWebPartManager(;
        await _webPartManager.fetchWebPartManifests(); // Ensure all manifests are available

    private async addData() {
        // local webpart properties - in this case props for the modern script editor webpart
        let props = {
            script: "<div>Foo</div>",
            title: "The Modern Script Editor web part!",
            removePadding: false,
            spPageContextInfo: false
        await this.loadWebPart("ScriptEditorWebPart", document.getElementById(_sampleIdOne), props);
        await this.loadWebPart("ScriptEditorWebPart", document.getElementById(_sampleIdTwo), props);

    private async loadWebPart(alias: string, domElement: HTMLElement, webPartProperties: any) {
        let manifests = _webPartManager.getWebPartManifests();
        for (let i = 0; i < manifests.length; i++) {
            const manifest = manifests[i];
            if (manifest.alias === alias) {
                let instanceId = Guid.newGuid().toString();
                let wpManifest: IClientSideWebPartManifest<any> = manifest as IClientSideWebPartManifest<any>;
                let wpData: IWebPartData = {
                    instanceId: instanceId,
                    title: "",
                    dataVersion: "1.0",
                    properties: webPartProperties

                // Specify any as webpartLoadExtraLogInfo is not defined on the interface and has to be present
                let initialize: IWebPartManagerContext & any = {
                    domElement: domElement,
                    instanceId: instanceId,
                    manifest: wpManifest,
                    displayMode: DisplayMode.Read,
                    webPartData: wpData,
                    webpartLoadExtraLogInfo: {
                await _webPartManager.loadWebPart(initialize);

    public render(): React.ReactElement<IHelloWorldProps> {
        return (
            <div className={styles.helloWorld} >
                <div className={styles.container}>
                    <div className={styles.row}>
                        <div className={styles.column}>
                            <span className={styles.title}>Dynamic loading!</span>
                            <span id={_sampleIdOne}></span>
                            <span id={_sampleIdTwo}></span>

Monday, May 28, 2018

How to reset a modern home page using PnP PowerShell

Photo by Nikita Kostrykin at Unsplash

Here’s a short snippet which will reset any modifications done to a modern home page back to the default layout.

Basically you clear out the CanvasContent1 field which stores the page layout and contents.

Connect-PnPOnline https://<tenant>
# Get welcome page url
$web = Get-PnPWeb -Includes WelcomePage
# Load the page
$file = Get-PnPFile -Url $web.WelcomePage
# Get the page's item
$item = $file.ListItemAllFields
# Load the item id
Get-PnPProperty -ClientObject $item -Property Id
# Clear the content to reset
Set-PnPListItem -List SitePages -Identity $item.Id -Values @{"CanvasContent1"=$null} -SystemUpdate

Quickly clear Followed sites using PnP PowerShell

In my dev tenant I do a lot of testing with Groups and sites, and this has the effect that my demo user is following a lot of, often with the same name as seen in the image below.


The followed sites are actually stored in a list named Social in your OneDrive. This list was introduced with SharePoint 2013, and still alive and kicking. You can access followed sites from the following URL:

https://<tenant><user site>/Social/Sites.aspx

This list also tracks followed documents and people, but that’s not the focus of this post.

First connect to your OneDrive using PnP PowerShell, then execute the code below to remove all followed sites, and be sure to set the correct URL in the first line.

$followedSitesUrl = "/personal/<user site>/Social/Private/FollowedSites"
$sites = Get-PnPListItem -List Social -Query "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='FileDirRef'/><Value 
$sites |% { Remove-PnPListItem -List Social -Identity $_.ID -Force }

Once complete, the list is now empty.


Tuesday, May 22, 2018

Two SPFx manifest settings you might not be aware of


If you take a look at the manifest schema for a SPFx web part there are a couple of settings you might want to take a look at.


If hiddenFromToolbox is set to "true", the web part will not be visible in the modern SharePoint toolbox. Very useful for web parts you provision automatically on pages, but don’t want users to add themselves.


If supportsFullBleed is set to "true", the web part can be added to a full page width zone on a modern page in a communication site, spanning from the left margin to the right margin without any white space.

Friday, May 11, 2018

Caution when using $expand with Microsoft Graph

Using the $expand parameter with calls to the Microsoft Graph is very handy. In one API call you can retrieve both the object itself and additional properties.

Two examples are fetching a user and the direct reports, or a group and it’s members.$expand=directReports$expand=members


The caution is that when you expand a property which has a collection of values, you will only get the first 20 items returned. This means that if you work in an organization with more than 20 people in it, you should not use $expand if you need all the values, but resort to two calls instead, one for the item, and one for the property you want to expand.


While using expand is very handy, it’s almost always better to break it into two API calls to avoid having issues if you can expect more than 20 items.

Tuesday, May 8, 2018

How to get the list item from a file URL using PnP PowerShell

Photo by Karly Santiago at Unsplash

This is one of the snippets I always forget, but which is very handy in cases where you have the absolute URL to an item in SharePoint. The magic is really line 6 which uses the static method WebUrlFromFolderUrlDirect to get the web URL of the file, so that you can connect properly.

$uri = [Uri]''
# Connect to the root site, or any other site
Connect-PnPOnline -Url ($uri.Scheme+'://'+$uri.Host)
$ctx = Get-PnPContext
# Get the web url for the file
$webUrl = [Microsoft.SharePoint.Client.Web]::WebUrlFromFolderUrlDirect($ctx, $uri)
Connect-PnPOnline -Url $webUrl
$fileItem =  Get-PnPFile -Url $uri.AbsolutePath -AsListItem

Sunday, May 6, 2018

Locating where a term set is used in SharePoint using search

Joanne Klein asked on Twitter if there is a way to get all places where a specific term set is used in SharePoint.


One way would be to iterate all site collections and check if the term set was present in the Hidden Taxonomy List, which stores all used terms on a site collection (and if you have no idea what that is, that’s ok as well).

Hidden Taxonomy List at /Lists/TaxonomyHiddenList/AllItems.aspx

Another option which is the solution I proposed, is to use search. Of course you need to have read access to the items where the term set is used for it to be 100% accurate as well items using terms from a term set has to be present in the search index.

Friday, May 4, 2018

Use Microsoft Flow to implement approval of site pages

Photo by Zachary Nelson at Unsplash

Again I’m late to the party, but Microsoft has released an action to Flow called “Set content approval status”. This action enables you to add content approval not only to list elements and documents in SharePoint, but also to news pages.

Microsoft has talked about content approval for ECM scenarios with communication pages for a while, but until a proper UI is in place, you can get started today!

This is how.

Thursday, May 3, 2018

Addendum to Chaks’ post “Deep dive into ‘Get items’ and ‘Get files’ SharePoint actions in Microsoft Flow”

Chaks recently wrote a post where he explained the difference between the two Microsoft Flow SharePoint actions Get items and Get files (properties only).

Behind the scenes they are both calling the following undocumented service which seems to wrap the regular OData call:


Good news is you can use both actions interchangeably. If you want to get the properties for a document library using the Get items action simply pick Custom value in the dropdown and enter the title or id for your document library and it works just fine (been using this already a while).


So, to me, having the Get files (properties only) action seems unnecessary, but for some users it might be easier to understand with two different actions targeted towards lists or libraries.