Azure function failing with “Object reference not set to an instance of an object”

I have an Azure application that uses an Office 365 App only token. Followed similar instructions to the one here:

I’m using OfficeDevPnP to connect to SharePoint with my Office 365 App only token. Demo code shown below.

string clientId = GetApplicationSetting("clientId");
string tenant = GetApplicationSetting("tenant");
string certificateFilename = GetApplicationSetting("certificateFilename");
string certificatePath = GetCertificatePath(exCtx.FunctionAppDirectory, certificateFilename);

SecureString certificatePassword = ConvertToSecureString(GetApplicationSetting("certificatePassword"));

string tenantAdminUrl = GetApplicationSetting("tenantAdminUrl");
log.Info("Got details");
OfficeDevPnP.Core.AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager();

   using (var clientContext = authManager.GetAzureADAppOnlyAuthenticatedContext(siteProperties.Url, clientId, tenant, certificatePath, certificatePassword))
     Web web = clientContext.Web;
     clientContext.Load(web, w => w.Webs, w => w.Title, w => w.Url);
}catch(Exception ex){
log.Info("Failed! " + ex.Message);

The Azure function that has been deployed and running daily for a while now, when all of a sudden it stopped working last Wednesday. Just as it was authenticating with SharePoint it displayed the error message “Object reference not set to an instance of an object”

The stack trace is below:

2018-02-06T09:45:28.347 Failed! Object reference not set to an instance of an object.
2018-02-06T09:45:28.364 StackTrace:    at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T](Task`1 task)
   at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireToken(String resource, ClientAssertionCertificate clientCertificate)
   at OfficeDevPnP.Core.AuthenticationManager.<>c__DisplayClass36_0.<GetAzureADAppOnlyAuthenticatedContext>b__0(Object sender, WebRequestEventArgs args)
   at Microsoft.SharePoint.Client.ClientRuntimeContext.OnExecutingWebRequest(WebRequestEventArgs args)
   at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
   at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
   at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
   at AppFunctionDemo.Function2.GetTenantSiteProperties(AuthenticationManager authManager, String tenantAdminUrl, String clientId, String tenant, String certificatePath, SecureString certificatePassword, TraceWriter log)
   at AppFunctionDemo.Function2.Run(TimerInfo myTimer, ExecutionContext exCtx, TraceWriter log)

After a call with Microsoft, it turns out that the Azure Functions are slowly being updated throughout the tenants.

Last one was 11 days ago (at time of writing this)

If you go to your Azure functions and look in the Application Settings, you will see an application setting saying:


This means it will keep itself up to the latest date. By changing the version “~1” to a previous version “1.0.11490” after saving the Application Settings, and re-running my Azure function, I no longer get an error message saying “Object Reference not set to an instance of an object” and the function runs to completion.

There is obviously a bigger bug issue here, but at least my Azure functions can continue running until then.


SPFX obtaining the URL Query Parameters

This is a very quick blog post, but I needed to obtain the URL parameters of the page for an SPFX webpart.

There is a built in method for obtaining URL parameters.

import { UrlQueryParameterCollection } from '@microsoft/sp-core-library';


var queryParms = new UrlQueryParameterCollection(window.location.href);
var myParm = queryParms.getValue("myParam");

I have found this very useful with Console Logs. I have a method called “logMessageToConsole” passing in the message. If I find a parameter called debug in my query string, then all the console logs are written out.

private logMessageToConsole(message:string)
var queryParms=new UrlQueryParameterCollection(window.location.href);

That way I only need to add ?debug=1 to the end of my URL or &debug=1 if there are already querystring parameters, and then I can see all my console messages. This is useful to quickly debug on production environments.

View Trace Logs with PnP Provisioning Templates using PowerShell

When running the Get-PnPProvisioningTemplate and the Apply-PnPProvisioningTemplate it is sometime necessary to see what is going on while the call is processing.

Just run the following command first before calling your Get/Apply -PNPProvisioningTemplate command.

Set-PnPTraceLog -On -Level:Debug

If you need to turn it off again

Set-PnPTraceLog -Off

PnP Provisioning Templates Adding – Everyone except external users

On a recent project of mine, I’ve been working with the PnP Provisioning engine using PowerShell. It’s really the first time I’ve really worked with it, and I must say I’m impressed at how easy it is to use.

If you have never used it before I recommend you checking out the following articles on MSDN.

Basic installation setup

If you have a Windows 10 device or have installed PowerShellGet, to check if you have the latest version installed in your PowerShell environment, run the following below

Get-Module SharePointPnPPowerShell* -ListAvailable | Select-Object Name, Version | Sort-Object Version -Descending

I already have the latest version at the time of writing this 2.17.1708.1.

You can install or Upgrade the SharePointPNPPowerShell with the following commands.

To Install

#SharePoint Online
Install-Module SharePointPnpPowerShellOnline

#SharePoint 2016
Install-Module SharePointPnPPowerShell2016

#SharePoint 2013
Install-Module SharePointPnPPowerShell2013

To Upgrade

Update-Module SharePointPnPPowerShell*

Everyone and Everyone Except External Users

The quickest way to create a PnP Provisioning template ready to use again, is to create your site within SharePoint using point and click.

I’ve created my site with Members set up to “Everyone except external users” and Visitors set up to “Everyone”.

After you have created your site, you use the following commands to connect and export the template.

Connect-PnpOnline -Url: -Credentials: (Get-Credential)
Get-PnPProvisioningTemplate -Out 'pnpExample.xml'

If you open the XML file, and look in the <pnp:Security> section, you will see that Additional Members has c:0-.f|rolemanager|spo-grid-all-users/{GUID} and Additional Visitors has c:0(.s|true. These represent Everyone except external users and Visitors respectively.

If you are only using this template to create more sites in the same tenant that you exported it from, then you are good. The GUID after ‘spo-grid-all-users’ will always be that GUID in your tenant. However, when you want to use this template in other tenants – for example you have a staging and production environment – then this GUID will not work and the importing of the template will not add Everyone except external users to your members group.

What is the GUID after spo-grid-all-users?

It turns out that the GUID relates to the Authentication Realm ID of your tenant, and luckily PnP have a PowerShell command


How does that help us?

You can pass parameters into the Apply-PnPTemplate. First we need to change the XML inside <pnp:AdditionalMembers>


<pnp:User Name="c:0-.f|rolemanager|spo-grid-all-users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx" />


<pnp:User Name="c:0-.f|rolemanager|spo-grid-all-users/{parameter:AuthenticationRealm}" />

Save the XML template and now you can run the following commands to apply the template to a new site in a different tenant. (Please note my team site I’m applying this to has already been created)

Connect-PnpOnline -Url: -Credentials: (Get-Credential)
$AuthenticationRealm = Get-PnPAuthenticationRealm
Apply-PnPProvisioningTemplate -Path:'pnpExample.xml' -Parameters:@{"AuthenticationRealm"=$AuthenticationRealm}

After applying the template to another tenant, you will see your “Everyone except external users” inserted correctly.

Using the Windows Credentials Manager with PnP PowerShell

Do you get fed up keep typing in your username and password when you are connection to SharePoint via PowerShell? Or you have to keep changing between multiple tenants and get fed up keep typing in the username and password? Did you know you could use the built-in Windows Credential Manager to help ease your pain?

  • Open your Credential Manager

  • Under the Generic Credentials, click ‘Add a generic credential

  • For each tenant/user account you need, create a Generic Credential.
    • Put a label name to indicate what the permissions are for (e.g DevAdmin, TestAdmin, TestUser etc)
    • Put the username of the account
    • Put the password of the account

  • After you have created your Generic Credential(s), when you try to Connect to SharePoint using PNP, you can pass your Label to the credentials.
    Connect-PnPOnline -Url "" -Credentials:devAdmin

    In the screenshot below, I’m connecting to my tenant using a label I created called CFAdmin1

Using the above technique of Credential Manager labels, you can make your PowerShell scripts easier by creating a string variable called label and pass it in. This will make running the same script for multiple environments easier.

    # The environment label to use for connection

    # The URL of the tenancy to create the site collections in, do not include the -admin
if ($VerbosePreference) {
    Set-PnPTraceLog -On -Level:Debug
else {
    Set-PnPTraceLog -Off
Connect-PnPOnline -Url:$URL -Credentials:$Label
… #Additional code to update Web

If the above file was called UpdateWebSite.ps1 I would type in the following:

.\UpdateWebSite.ps1 -Url:'' -Label:devAdmin

Power BI using Parameters to use the same PBIX file for different tenants

In the past I, have created a Power BI file connecting it to the developer tenant data, design the reports based on the dummy data in my development tenant, before publishing it to the production tenant using the production data. For those that have done this before, you will know it’s not easy because all your data queries are pointing to the URL you first used, every query you have created will have this URL in, also GUIDs for lists filters etc could all be different in another tenant.

I will be continuing from my last example of a movie database from my previous post. I will be updating the queries so that in future, there is one location to change my parameters. My previous post has 4 queries which was my main Movies list from SharePoint, the TaxonomyHiddenList from SharePoint, and two references of the TaxonomyHiddenList renamed and filtered for Genre and Country.

First I need to think what might be different in the other tenant compared to my original one.

  • Tenant Name
  • Site/Web URL
  • Genre TermSet Id
  • Country TermSet Id

I need to create 4 paramters and name them to correspond with possible changing values. To do this, I need to ensure I’m in the Edit Queries. From your report, on the ribbon click Edit Queries. This will bring up the Edit Queries editor.

Underneath your current queries, right click and from the context menu, select New Group. Name the group Parameters. Your original queries will be places in a group folder called Other Queries.

Right click the Parameters folder, and from the context menu, select New Parameter…

Add 4 new parameters:

  • Tenant:
    • Name: Tenant
    • Required: True
    • Type: Text
    • Suggested Values: Any
    • Current Value:
  • WebSiteUrl:
    • Name: WebSiteUrl
    • Required: True
    • Type: Text
    • Suggested Values: Any
    • Current Value: /sites/taxonomy
  • GenreTermSetId:
    • Name: GenreTermSetId
    • Required:True
    • Type: Text
    • Suggested Values: Any
    • Current Value: f46ebfeb-cc18-479f-bac8-48fdca36dd6c
  • CountryTermSetId:
    • Name: CountryTermSetId
    • Required: True
    • Type: Text
    • Suggested Values: Any
    • Current Value: 6e0c3d2e-5514-4744-a08d-7318fd437a45

Click OK.

You should now have 4 parameters showing in your Query window. Now we need to use these.

Starting with the CountryTermSetId, previously my Country query was filtered on a text value that was the GUID of the TermSetId. Now I have a parameter I can use instead. I will want to update my query to use a parameter instead of free text. In the Applied Steps for Country, I can click the cog next to Filtered Rows which is step 2.

This brings up a Filter Rows dialog, where you can see it current is using a Text value to query against.

By selecting the dropdown where it currently shows ABC, you can select parameter instead. Then in the last dropdown box you are given all your parameters, here I would select CountryTermSetId.

I then repeat those steps for Genre query, using the GenreTermSetId instead.

For the movies query, I need to click the Advanced editor from the ribbon bar to amend the query to use parameters.

The text in this window is the query that has been currently set.

    Source = SharePoint.Tables("", [ApiVersion = 15]),
    #"acd616ae-ee59-4597-86f3-3d5b65e64547" = Source{[Id="acd616ae-ee59-4597-86f3-3d5b65e64547"]}[Items],
    #"Renamed Columns" = Table.RenameColumns(#"acd616ae-ee59-4597-86f3-3d5b65e64547",{{"ID", "ID.1"}}),
    #"Removed Other Columns" = Table.SelectColumns(#"Renamed Columns",{"Title", "Total Worldwide Box_", "Genre", "Country"}),
    #"Expanded Genre" = Table.ExpandRecordColumn(#"Removed Other Columns", "Genre", {"TermGuid"}, {"Genre.TermGuid"}),
    #"Expanded Country" = Table.ExpandRecordColumn(#"Expanded Genre", "Country", {"TermGuid"}, {"Country.TermGuid"})
    #"Expanded Country"

We need to change the Source row (Line 2), and the #”acd616ae-ee59-4597-86f3-3d5b65e64547″ (Line3).

The Source row (Line 2), would need the URL part changed from

Source = SharePoint.Tables("", [ApiVersion = 15]),


Source = SharePoint.Tables("https://"&tenant&WebSiteUrl, [ApiVersion = 15]),

You can see we are inserting the parameters names and concatenating them using the ampersand.

The Line 3 row we are using the Title of the list instead of the ID as this would be different in another tenant.

#"acd616ae-ee59-4597-86f3-3d5b65e64547" = Source{[Id="acd616ae-ee59-4597-86f3-3d5b65e64547"]}[Items],


#"acd616ae-ee59-4597-86f3-3d5b65e64547" = Source{[Title="Movies"]}[Items],

We would also do something similar to the TaxnomyHiddenList query too. Changing the first 3 lines from:

    Source = SharePoint.Tables("", [ApiVersion = 15]),
    #"63f7f485-a5ca-4be5-815f-d0e3235e96d1" = Source{[Id="63f7f485-a5ca-4be5-815f-d0e3235e96d1"]}[Items],


    Source = SharePoint.Tables("https://"&Tenant&WebSiteUrl", [ApiVersion = 15]),
    #"63f7f485-a5ca-4be5-815f-d0e3235e96d1" = Source{[Title="TaxonomyHiddenList"]}[Items],

If you have followed this correctly, you would find that your data still works, and there are no issues. Click Close & Apply from the ribbon. The apply query changes will happen but your data will be the same. In the future when you want to publish to a different tenant you just need to change your parameters, instead of going to each query and updating the URL ID’s/GUIDs.