Azure Functions and Punch Cards

This is apparently a computer story, but is actually also very much a human story.  In which we explore the relationship between Azure Functions and Punch Cards.

My mother

It's been very warm in Sydney in this blistering summer.  My mother comes over to visit and relax and enjoy my air cond.  I'm preparing for Microsoft Ignite Australia on Azure Functions, and I was thinking about a human story.

I looked up at mum, this is the frail, little Chinese grandma that plants funny herbs in the garden.  We had a chat.  I then went online and found this picture.

By ArnoldReinhold - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=16041053

By ArnoldReinhold - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=16041053

Our story

I sometimes talk of my parents who met as comp science students in the 70s.  My mother, who sometimes can't remember how to restart her iPad.  Well, she cut her teeth on these punch cards. She tells me how big they are - gesturing with her hands - the box of cards would be nearly the size of A4 - much wider and longer than I thought.

I ask, so you need to pass the cards to an operator to run them and wait.

Of course.

What if you have an error in your code?

She pretends she spends a lot of time checking before submitting the cards.  But later admitted actually, the code would crash.  I think she figures out that it's a funnier story to tell the truth.

And since the output is a printout (the cards are input, there is no keyboard/screen) she'd get pages and pages of invalid instructions handed to her by the operator.

Imagine Developers, if your OPs is responsible to read to you all your compile errors.  Every time.

She will have to resubmit her program.

It'd be quite embarrassing she says.

I sat back, and tell her of @AzureFunctions and how I now submit code to be run in the cloud.

And how first few runs, my code would spit back rows of errors. we laughed.

Some things never change.

And then, some things do change

 

By NARA - http://www.archives.gov/75th/photos/1950s/20.html[dead link], Public Domain, https://commons.wikimedia.org/w/index.php?curid=17413686

I end this story with this picture.  This warehouse stores punch card programs for US National Archives 1959. Equivalent to 4Gb.

While my mother will have a second chance to resubmit her program in the afternoon, I can repeat as many execution as I'd like in the cloud.

The mainframe computer my mother used when she worked in Statistics Bureau of Taiwan is worth hundreds of thousands of dollars, and she has to wait with other programmers to use it.

The Azure Functions that I can write and deploy today, cost me less than $0.01 and most of the time the compute is free.

Future

Bonus: I told her future datacenters will be underwater and completely unmanned #ProjectNatick

Her eyes are full of wonder

 

 

 

Interact with Graph and make O365 Groups with AzureFunctions PowerShell

In this post, we talk about how to get an access_token in PowerShell to talk to the Microsoft Graph, so we can run automated non-interactive scripts in Azure Functions.

 

I'm so sorry for butchering the title every time.  But this blog post is cool.

I've written previously about creating SharePoint sites via PnP-PowerShell.  Which is very powerful and very popular - thank you for all the nice discussions and comments.  Soon, people asked - can we do the same for O365 Groups?

The PnP-PowerShell cmdlet for Connect-PnPMicrosoftGraph works, but it raises an login dialog, which makes it a show stopper for non-interactive scripts or Azure Functions.  I took it upon myself to find a workaround over my December holidays but alas the solution didn't come until January. 

What is the Trick?

The problem is to authenticate with Azure AD and get an access token that we can use to talk to the Office 365 Graph.  The trick, is a little not-well known thing called Resource Owner grant.

grant_type=password

I have a few links about the Resource Owner grant type at the end.  Basically, this grant_type lets you use username/password to obtain an access token.

Setting up Azure App Registration

You are probably familiar with these steps by now.  Today's screenshots came from the new Azure AD Portal.

Navigate to the Azure Active Directory portal, before we go further, grab the Directory ID - this is the tenant ID you'll need.  The tenant ID isn't a private value - it appears in URLs often when you are signing into Office 365.  But it's handy, right here, so take a copy.

Create our app.

Add Delegate Permission to Read and Write all groups.  Note this requires admin permissions.

Click the awesome Grant Permissions button at the top of the permissions registration, this grants it for users in your Active Directory.

You will need some clientsecrets - create them from Keys.  I like them not expiring for a long time.  So I pick the Never expires option.  It'll expire when I'm long gone.

Copy down your ClientSecret

One final check.  Copy the Application ID.  This is your app's Client ID.

To Azure Functions!

 

First, we create another HttpTrigger-PowerShell.

Because we aren't using PnP-PowerShell this time, there is no extra modules dependency.  This example is going to be simply Invoke-WebRequest and Invoke-RestMethod

Start with this code:

$requestBody = Get-Content $req -Raw | ConvertFrom-Json

$username = "[email protected]";
$password = $env:PW;
$client_id = "9308c103-8208-40cd-85e2-37a994b3578d";
$client_secret = $env:CS;
$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$resource = "https://graph.microsoft.com";

# grant_type = password

$authority = "https://login.microsoftonline.com/$tenant_id";
$tokenEndpointUri = "$authority/oauth2/token";
$content = "grant_type=password&username=$username&password=$password&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
$responseBody.access_token

Out-File -Encoding Ascii -FilePath $res -inputObject $responseBody

Change to your own username/password/clientid/clientsecret/tenantid - note my password and clientsecret are stored in Function App Settings.

When this Azure Function runs -

You'll see the $responseBody and specifically, the $responseBody.access_token

We now have a key.

Calling Graph - Get Groups

$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

Out-File -Encoding Ascii -FilePath $res -inputObject $body

Call graph, attach access_token in Header.

My Office 365 groups in JSON.  Notice the function took about 1 second between start, obtain access_token, and retrieve graph.

Calling Graph - Post Group

The Graph is not a read-only datasource, and our App has Group.ReadWrite.All

# POST - this creates groups https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/group_post_groups
$body = @{"displayName"="ps-blog"; "mailEnabled"=$false; "groupTypes"=@("Unified"); "securityEnabled"=$false; "mailNickname"="ps1" } | 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

Out-File -Encoding Ascii -FilePath $res -inputObject $body

Here we go.  A new O365 group "ps-blog" is created.  Note the function took 3 seconds.

Why I like PowerShell to demo Functions

  1. Code looks simple.  Cmdlets compresses a lot of functionality. 
    Take for example ConvertTo-Json or ConvertFrom-Json.  In C# we'd have to call a JsonSerializer and in NodeJS we'd need double promises just to get a json from fetch()
  2. PowerShell wraps C# and .NET libraries so they can be fairly powerful without a lot of code
  3. Not everyone understand JavaScript, or NodeJS JavaScript
  4. Suitable for IT Pros that may only know PowerShell
  5. Developers should learn more languages - and you can convert this in your head to C# or NodeJS anyway.

Bonus

This part is an exercise for the reader.  Make an PowerApps app that will call this function - passing in a parameter for the group name.  Hook up the Azure Function as a connection and bind it to a textbox and a button press.

Ignite Australia

Come and see me present all these cool techniques and more at Ignite Australia!

https://msftignite.com.au/sessions/session-details/1988/serverless-in-office-365-build-services-with-azure-functions-prod324

We'll talk about the Azure Functions story for today's Office 365 Developer, IT Pro and Power User.

Azure Functions has an amazing place from microservices to Swagger to the BotFramework!

 

Summary

  • Use PowerShell
  • Get access_token via username/password
  • Get our graph
  • Make O365 Groups

References

 

If you liked this post - please leave a comment below.  Please also try the code and let me know how it goes for you.  I love reading about people taking my brief demo code further to solve real problems.

How to tell WebPack Uglify to support IE8

Many that uses WebPack also applies the UglifyjsPlugin.  By default, UglifyJS doesn't support IE8.  There's a few problems that we'll see:

IE8's non-standard catch is a keyword, so as a property it will be renamed to "catch": and promise["catch"]()

IE8's non-standard class is a keyword, so similarly it needs to be escaped as "class".

The UglifyJS settings needed for WebPack.config is this:

    new webpack.optimize.UglifyJsPlugin({
      mangle: {
          // mangle options, if any
      },
      mangleProperties: {
        screw_ie8: false,
        //ignore_quoted: true,      // do not mangle quoted properties and object keys
      },
      compress: {
        screw_ie8: false, 
        //properties: false // optional: don't convert foo["bar"] to foo.bar
      },
      output: {
        screw_ie8: false         
      }
    })

 

Yes, by default, UglifyJS has screw_ie8 = true

Thankful for MVP 2017 and 2016 in Review

I've just received email that I've been rewarded with Microsoft MVP for 2017.  I am thankful to be counted with some of the smartest people that does what we do.  I still stay up and wait for this email.  It is still very exciting :-)

2016 was a wonderful year

It was a wonderfully busy year for me personally.  (I say personal, because learning lots of new JavaScript is nothing but personal).

In the beginning of the year, we* were coming off a new Angular module that was built in 2015, and with that fresh in our minds, marching into 2016 with a focus on modernizing our Javascript stack (to Angular - which seems like the only choice at the time).

This was also the time where we talked about building Angular applications for Office and stepping out of not just Intranets but even into Office client applications.

May the 4th 2016 was amazing with Jeff Teper stepping out and stamped SharePoint back into the minds of many unbelievers who had brushed it off.  We had some inking this was coming - but it was hard to tell what effect this would have set off in the SharePoint world - 7 months later, I think the SharePoint team has successfully followed up with several big hits.

https://blogs.office.com/2016/05/04/the-future-of-sharepoint/

About midway through the year, we started working with Webpack and realizing that it will revolutionize our entire build pipeline.  (As a bonus, it unifies our work across different frameworks - some KnockoutJS, some DurandalJS and the new modules in Angular).

If you aren't sure whether to learn React or Angular - Learn Webpack.

https://webpack.js.org/

There's going to be lots of JavaScript...

In the meantime, our paths crossed with Nora at Telerik (Progress) who was looking for someone to contribute to a Office 365 or SharePoint based whitepaper.  There were several synergies in our meeting - we wanted to explore deeply using an existing KendoUI framework with SharePoint, we know SharePoint Framework was coming and there's a lot of talks of the toolchain needing to be refreshed.

http://developer.telerik.com/featured/how-to-prepare-your-toolbox-for-the-sharepoint-framework/

We also saw how Webpack fitted in all the pieces, and picked up PnP JS Core - new at the time, but rapidly gaining momentum with several major releases through the year.

https://github.com/SharePoint/PnP-JS-Core

Our whitepaper was finished in August, but took a while to come out as it passes though several reviews.  It was of great interest to me personally how many libraries we talked about had a new version while the whitepaper was being reviewed:  Angular went from 1.5/2.0rc5 to release.  JS Core went from 1.02 to 1.0.4.  Webpack released 2.0 end of the year, and SPFx went through 5 revisions.

http://www.telerik.com/campaigns/kendo-ui/sharepoint-framework-ui-customization-angular

We asked John Bristowe to come down and visit and recorded a podcast with Andrew Coates for the Dev Office Podcast (recorded in person and in studio!)

 

https://blogs.office.com/2016/12/15/episode-111-john-bristowe-john-liu-office-365-development-kendoui-angular2-office-365-developer-podcast/

We hit our Melbourne Cup with a major rewrite of our Melbourne Cup app (it was already in Angular, but now it is Webpack'd and deployed through Azure CDN - taking the actual download of the package from 10mb down to 2mb).

https://sharepointgurus.net/melbournecup/

We started experimenting with Azure Functions - first with Javascript/Node.  We wanted perhaps to get PnP JS Core to run in a Function.

http://johnliu.net/blog/2016/5/azure-functions-js-and-app-only-updates-to-sharepoint-online

We then looked into PnP PowerShell and saw how easy it was to run that within Azure Function - this will revolutionize IT Pros when we connect it with Flow.

http://johnliu.net/blog/2016/11/build-your-pnp-site-provisioning-with-powershell-in-azure-functions-and-run-it-from-flow

 

2017 - what's Your Stack

Looking towards 2017, we are marching ahead on both fronts - our Frontend work is backed by Angular, Webpack and Azure CDN, ready to go with SPFx.  Our backend work is backed by PnP PowerShell or JS Core and Azure Functions, ready to go with Flow.

I have an upcoming session in Australian Ignite on Azure Functions

https://msftignite.com.au/sessions/session-details/1988/serverless-in-office-365-build-services-with-azure-functions-

 

*We refers to me and various colleagues in SharePoint Gurus or otherwise.  Sometimes it might be just the royal 'we'.  Because we aren't consistent.

 

Running OfficeDev PnP cmdlets in 32bit AzureFunctions

Some recent changes with AzureFunction created a small problem - x64 functions are not available in the starter-consumption plans.

The situation is not game over.

Since all the assemblies are not compiled for x64 only.  So just open the psd1 file and change 'Amd64' to 'None'.  They actually run just fine.