March PnP special interest group call and Azure Functions demos

On March 22, I put my hand up to do demos for the Office Patterns and Practices Special Interest Group conference call.  We talked about Azure Functions with PnP, and Bert talked about a new Modern Page scanner that can be used to check if sites have customizations that would make migrating to modern pages difficult.

PnP Core, PowerShell and Provisioning Engine SIG recording from March 22nd, 2017. Details around the covered content and direct links to demo section from TBD

I had a lot of fun.  It probably was very obvious I was laughing most of the way.  This is a follow up post of various things that I had noted down but unsaid.

Demo files

All my Functions in the demo are published to: https://github.com/johnnliu/azure-functions-o365 

That Get-AccessToken typo

It turns out the problem is the dash - character that I copied from GitHub.  If I retrype the command as - (dash) then the cmdlet is fine.

Costs

Vesa mentioned this at the end.  Azure Function's pricing is very cheap.  It is actually because Functions don't run on VMs provisioned for you.  Azure finds an unused VM, copy your function on it, then run it, and then delete it.  The free monthly compute bucket is 400,000 Gb/s.  If you exceed the limit it is still dirt cheap.  I'm serious about the fact that I have turned off all my VMs, I only run Functions.

Also, I'm just as shocked as you are that Vesa seems to know exactly what I'm about to present next.

Docker

My platform as a service goes up.  I see Docker as going downwards and not the direction I want to go.  Functions as a Serverless platform needs to be above Web Server as a platform.  They could all live on top of Docker, but that's an implementation detail that I don't need to care about.

Configure Inputs and Outputs

Because Functions are serverless, it is important to understand that you don't really want to even write your own code for handling output.  If you want to write to Blob Storage or Azure Queue - there are output configuration you can set up.  Then the output from the function is written directly to those sources without you having to write bare minimum code.

Configuring Inputs also allows you to switch from a HttpTrigger to a TimerTrigger, if you need that.

Flow to Azure Functions

If you feel uncomfortable with having an open public URL exposed - you can have Flow upload a JSON directly to an Azure Queue, then execute the Azure Function from the queue.  This also provides automatic-retries.

Future announcement - PnP SIG JS Call

I've done a bit more work with pnp-js-core, azure-functions-cli and azure-functions-pack.  And have put up my hands to Patrick to do a PnP-JS-Core SIG call in the future.  Need a few pieces to sort out first.

Azure Functions has a very definite place with NodeJS as well.  We'll explore that hopefully soon.

Simple custom Angular (Angular2) Pipe that extends Number

We have a lot of code that looks like this in our new Angular (Angular2) module:

<div style="width:210px">
    <div>
        {{ (overviewDetails.TotalTurnoverActualSecured ?
      (overviewDetails.TotalTurnoverActualSecured / 1000000) : 0) | number:'1.2-2' }}
    </div>
    <div>{{ overviewDetails.TotalTurnoverActualSP / 1000000 
      | number:'1.2-2' }}</div>
    <div>{{ overviewDetails.TotalTurnoverActualSPF / 1000000 
      | number:'1.2-2' }}</div>
    <div style="clear:both"></div>
</div>

The main reason is that we just want to display numbers in 1.2 million, not 1200,000.

So obviously, we think about wrapping this in a custom Pipe function.

number is a Pipe name for the DecimalPipe class.  So we can extend that and borrow all the work the DecimalPipe does with parsing and formatting.

import { Pipe } from '@angular/core';
import { DecimalPipe } from '@angular/common';

@Pipe({
  name: 'million'
})
export class MillionPipe extends DecimalPipe {
  transform(value: number): any {
    return super.transform(((value || 0)/ 1000000), "1.2-2");  
  }
}

The Angular2 template then simplifies down to:

<div style="width:210px">
    <div>{{ overviewDetails.TotalTurnoverActualSecured | million }}</div>
    <div>{{ overviewDetails.TotalTurnoverActualSP  | million }}</div>
    <div>{{ overviewDetails.TotalTurnoverActualSPF  | million }}</div>
    <div style="clear:both"></div>
</div>

It is so nice to work with a Proper Object-Oriented language like TypeScript here.  Look at that extends.  <3

 

O365 Customizations in the year 2017

It is the year 2017 - watch out, because O365 customizations are full speed ahead.

This is a MS Australia Ignite 'lightning talk' for Meetup Madness (sorry, I took twice the amount of time than I should) to convince a room full of people that loved O365 to become developers.

MS AU Ignite Meetup Madness - O365 Customizations in 2017

Much laughter was had.  But I stand by what I said - you are now all developers, now go build something amazing!

 

AzureFunctions, PowerShell, MS Graph and AppOnly permission

In a previous blog post, I wrote about connecting to Microsoft Graph with Resource Owner grant.

That particular authentication scheme is for delegate permissions.  So the function, utilizing an account's username/password, is performing actions as that user.

I'm revisiting that post today and instead talk about App-Only Permissions, and the steps are very similar, and to some may be easier.

 

Register App-Only

Head into the New Azure Portal.

Add "Read and write all groups" permission under "Application Permissions"

You should see this:

"1 Application Permission"

Hit the Grant Permission button here.

And set up a Client Secret

Nearly there, one more step we need to make the registered app allow implicit flow.

Hit the Manifest button, change oauth2AllowEmplicitFlow property to true, hit save.

Copy the Application ID - this is the Client ID.

On the first page of Azure AD properties, grab the Directory ID

 

 

You now have:

  • Directory ID (Tenant ID)
  • Application ID (Client ID)
  • Key (Client Secret)
  • And consent for your app has been granted.

 

PowerShell Code

 

$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$client_id = "44da3f20-fc0b-4f90-8bb1-54b1d50e3ecf";
$client_secret = $env:CS2;
$resource = "https://graph.microsoft.com";

$authority = "https://login.microsoftonline.com/$tenant_id";
$tokenEndpointUri = "$authority/oauth2/token";
$content = "grant_type=client_credentials&client_id=$client_id
            &client_secret=$client_secret&resource=$resource";

$response = Invoke-WebRequest `
    -Uri $tokenEndpointUri `
    -Body $content `
    -Method Post `
    -UseBasicParsing

 

The small difference between this time and the previous blog is now we are using AppOnly permissions.  The grant_type is client_credentials.  And you don't need to supply username/password.  The clientid/clientsecret pair is sufficient.

 

The whole thing

$name = "group-name-here"

$client_id = "44da3f20-fc0b-4f90-8bb1-54b1d50e3ecf";
$client_secret = $env:CS2;
$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$resource = "https://graph.microsoft.com";

$authority = "https://login.microsoftonline.com/$tenant_id";
$tokenEndpointUri = "$authority/oauth2/token";
$content = "grant_type=client_credentials&client_id=$client_id&client_secret=$client_secret&resource=$resource";

$response = Invoke-WebRequest -Uri $tokenEndpointUri -Body $content -Method Post -UseBasicParsing
$responseBody = $response.Content | ConvertFrom-JSON
$responseBody
$access_token = $responseBody.access_token

# GET https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/group_list
# $body = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/groups" -Headers @{"Authorization" = "Bearer $access_token"}
# $body | ConvertTo-JSON

# POST - this creates groups https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/group_post_groups
$body = @{"displayName"= $name; "mailEnabled"=$false; "groupTypes"=@("Unified"); "securityEnabled"=$false; "mailNickname"=$name } | ConvertTo-Json 
$body = Invoke-RestMethod `
    -Uri "https://graph.microsoft.com/v1.0/groups" `
    -Headers @{"Authorization" = "Bearer $access_token"} `
    -Body $body `
    -ContentType "application/json" `
    -Method POST
$body | ConvertTo-JSON

There are no other dependencies - authenticate and calling MS Graph is really that simple - two web requests!

 

The default "Owner"

Usually, the user that created the group becomes the Owner of the group.

In the Delegate Permission example in the last blog, the group is created with my user account and I'm the owner.

In the Application-Only Permission example in this blog, the group is created with the app account and there is no user owner!

 

 

 

 

Where is SharePoint Customization going in 2017

I'm actually pretty terrible at gambling the future of Technology.  But I like writing these posts because it makes me sit down and think.

User Experience: SPFx is king

 

The user experience is dominated in 2016 with the news of SharePoint Framework (SPFx).  Which shifts development and toolchain to a more modern JavaScript Stack:  NodeJS, Yeoman.  WebPack.  There are component libraries like Office UI Fabric, but we explored options such as Kendo UI and UI Bootstrap and there are many benefits too.  In 2017, SPFx should come down to On-Premises too, we'll have to wait and see what that looks like.

Sure - there are still plenty of gaps where SPFx can't cover - many of us are looking to a solution that allows us to do a site-level script injection or something that will let us do a Single Page Application override.  But I'm very bullish on the SPFx.  I think 2017 will rock.

https://github.com/SharePoint/sp-dev-docs

 

Frameworks: Angular or React

React continues to better suit component development, and Angular might catch up, but we'll see.  In SPG, we are divided into both camps, and for people that aren't familiar with Angular, I am not opposed to them learning React.

I am however, dead serious that no one should try to learn both Angular and React at the same time.  One need to pick one, master it, then the concepts of the other framework will map in the mind and come naturally.  Learning both at the same time without mastering either of them will screw one's learning path.  Don't risk this.

Have an ASPNET MVC background?  Angular will make more sense.  Want a more code / component based approach?  Then React will make more sense.  Pick one and run with it.

I have picked up Angular now and am quite happy with it.  Feel free to reach out with Angular+SharePoint questions.  I can't help with React questions.

 

SP Helper: PnP-JS-Core

I have high hopes that PnP-JS-Core will continue to gain popularity and wrap around the SharePoint REST Services well.  I can totally see a few blog posts in the future using NodeJS, PnP-JS-Core inside an Azure Function to manage SharePoint Online.

As a bonus, it works really well with On-Premises too.  Congrats on hitting 2.0.0 Patrick!

 

Build tool: Webpack

Pick up webpack - do it now.  gulp and grunt are no longer the right tools that manage the build process.  Use them to automate the tasks around the build.

The rise of command-line-interface CLI tools will be the theme of 2017.  We have angular-cli, create-react-app, SharePoint Framework has its own yeoman template.

CLI is just a command line's way of "new file wizard"

 

Dashboards: Power BI

We did a bit of work with embedding Power BI dashboards into SharePoint, and with the rapid pace of releases of upcoming Power BI SPFx, Push data with Flow to PowerBI and PowerBI Streaming Datasets - it will become increasing no brainer to use Power BI to build your reporting dashboard and embed them into your sites.  With a local gateway, Power BI works for on-premises data too.

 

Forms: ???

I would like to say Power Apps is the thing.  But it's not, not yet.  The reason I say this is that business wants Forms.  They want forms to replace paper processes.  They want forms to replace older, aging digital forms (InfoPath).

Power Apps isn't trying to be a Form.  It is trying to be a Mobile App-Builder.  It might get there one day.  But I'm not sure if that's the course they have set.

I was thinking Angular-Forms for heavy customizations and Power Apps for simple ones.

I'm open to suggestions. 

 

Automation: Flow / Logic Apps + Azure Functions

Several products hit the scene - Flow, Logic Apps are fairly basic.  But once you pair them up with an Atomic Hammer (Azure Functions), then everything will look like a nail and everything's easy.

The way I see it, Flow is better for single events and Logic Apps is better for sets of data.

And don't get me started on the dirt cheap price point too. 

 

Server Code as a Service: Azure Functions

You've probably seen from my recent posts where I rant on and on about Azure Functions.  I truly see it as the ultimate power to do anything that we need a server to do.

  • Any Elevate Permissions task - in Workflow, Flow, Logic Apps or JavaScript Front-End Application
  • Any long running task
  • Any scheduled task
  • Any event response task - especially combined with the newly released SharePoint Webhooks
  • Any task that requires you to build a set of microservices for your power user to build complex Flows or Power Apps
  • Choose any language you like: C#, NodeJS or PowerShell, in fact, mix them in your microservices - nobody cares how it runs, and it's great.

 

Auth Helper: ADAL, MSAL

We can't escape this.  As soon as we begin to connect to various APIs we'll need authentication bearer tokens.

We seem to have better and better helper libraries as time goes on.  But regardless, in 2017 - we will need to be able to auth to the Microsoft Graph in any language that we use.

Julie Turner has an excellent series:

 

Summary

And these are my picks for 2017.  Do let me know what you think - I'm really interested in points where you disagree with my choices, because I want to learn.