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.


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 = "";
$password = $env:PW;
$client_id = "9308c103-8208-40cd-85e2-37a994b3578d";
$client_secret = $env:CS;
$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$resource = "";

# grant_type = password

$authority = "$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

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

$body = Invoke-RestMethod -Uri "" -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
$body = @{"displayName"="ps-blog"; "mailEnabled"=$false; "groupTypes"=@("Unified"); "securityEnabled"=$false; "mailNickname"="ps1" } | ConvertTo-Json 
$body = Invoke-RestMethod `
    -Uri "" `
    -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.


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!

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!



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



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.