Wednesday 4 April 2018

Control Office 365 Group creation – a simple no-code solution

In the Microsoft view of the world, every user in an organization using Office 365 should be able to create Groups – and remember that they can be created from Outlook, Microsoft Teams, Planner, Power BI, SharePoint and so on. However, in the real world it seems there are few large enterprises willing to go with that. Personally I’m not surprised. I think there are many reasons to introduce more governance – perhaps you want to collect some metadata about the requestor/group/business unit/division, or perhaps you just want an admin to check this is a genuine/justified request. Or maybe you want to check if a SharePoint site already exists for this, because you’ll do something different if it does (e.g. “Groupify” that site instead). Of course, it’s possible to lock down Group creation to a central admin team using the "GroupCreationAllowedGroupId" approach (see Manage who can create Office 365 Groups) - however, unless you supplement this with something else (such as have users raise a support ticket when they need a new group) you have no real user-facing “request process”.

So what if we could have a really simple no-code solution using purely out-of-the-box things in Office 365, based on a simple SharePoint list which we could point users to, with Microsoft Flow providing the approval steps to get the control we need?

Of course, you might not care too much about the concept of Office 365 Groups itself. But you might care about providing Microsoft Teams or SharePoint sites to the business, or one of the other more functional things built on top of Groups. The solution outlined here may become even more valuable when Office 365 allows a Team to be provisioned alongside a Group – we’re currently waiting for APIs around this, but it’s on the way soon. So, consider the solution outlined here to be a Teams provisioning solution in the future, not just the Groups provisioning solution it currently is.

In implementation terms, I’ve seen many articles showing slightly different ways of provisioning Groups and sites in Office 365, but nearly all use some custom code e.g. an Azure Function. One of the nicer ones is Martina Grom’s series starting here, but I was wondering if there was a simpler approach. Azure Functions are great of course (I’m giving a talk on them at the European Collaboration Summit 2018 in Germany soon) – but unless the organization is already using Azure for code hosting, it can introduce some barriers. This is because an Azure subscription is suddenly needed, someone is asking about forecast costs (even though us devs know they are low on a consumption plan), someone needs to sign-off and so on. Or, you might just prefer a no-code solution for other reasons. So..

Implementing controlled Group provisioning with a SharePoint list, a Flow, and the Graph

The ingredients for this solution are:

  • A SharePoint list
  • A Flow (with just a few actions)
  • An Azure AD app registration (to allow calling the Graph)

Yes, we do need to do *something* in Azure. We need to register an application and grant it permissions to create Groups and add users to them. But you don’t need any pay-for Azure for this, since Azure Active Directory is bundled with Office 365 and you’re just registering an application there so that your Flow can call the Graph. As we said before, there’s no code running anywhere – so no Azure Functions, queues, databases, storage or anything like that.

Our completed Flow looks like this:

Group creation Flow

As you can see, there are a couple of extras beyond simply creating the Group, which I think you would want in the real world:

  • Groups get added to a separate “Created Groups” list – otherwise, our ‘requests’ list wouldn’t help us understand if any Groups actually failed to create and don’t exist. In the Created Groups list, we add the Group ID (which might be useful to administrators), and you could easily extend this to add other data
  • We add the person who requested the Group to be Group owner – otherwise, he/she doesn’t have permission! This is something of a gotcha, since you’d either need I.T. to do a manual step for each one (which kind of defeats the purpose of an automated Group provisioning system).
    • N.B. there is some complexity to this in Flow, and that’s what the latter steps of the Flow are all about – parsing some JSON to obtain the ID of the created Group and the user who requested the Group, and then making a separate call to the Graph to add this user as Group owner. But still, it *can* be done without code.
Approval step

NOTE – one thing I’m excluding in my Flow/the details in this article is the actual approval step which gives you the control. This is an exercise for the implementer, since it’s trivial to implement in Flow and everyone’s requirements might be a little different (e.g. one-level/two level approval, different recipients etc.). This is typically done with the “Start an approval” step in Flow.

The key – calling the Graph with Flow’s HTTP action

As I showed in 5 ideas for using Flow in your applications, it’s possible to easily create an Office 365 Group (or do MANY things around users, mail, calendar, files and so on in Office 365) by having your Flow call the Microsoft Graph. For many developers, this is simpler than code because there is none of the complexity around obtaining an authentication token (which varies depending on where you are calling from). The simple HTTP action in Flow can be used for this:

SNAGHTML61e70c

This works because it has a way of providing authentication details to the specified endpoint – to be precise, we use the Client ID and Client Secret of our AAD app registration. This is one way of authenticating with the Graph (known as the OAuth “Client Credentials” grant), which itself works from code, a Flow, or anything else which can call over HTTP. The config steps are simple. But let’s start with the SharePoint list..

Step 1 – create a SharePoint list for Group requests

All that’s needed here is a simple list for users to visit when they need a new workspace for their team. Add columns for:

  • Group short name
  • Group display name
  • Group description

N.B. You could combine the ‘Title’ field of the list with the Group display name or similar – I kept them separate (to perhaps use the Title for some other descriptive text), but up to you. So my list looks like:

SNAGHTML2514c402

..and then the form looks like this:

SNAGHTML25cdc45c

OPTIONAL – create a 2nd SharePoint list named something like “Created Groups” to track successfully created Groups. The steps I provide later to configure the Flow are based on this approach – I simply add a field for “Group ID”, although you could extend this to include the URL, owner and whatever other fields are useful:

SNAGHTML3a4a197e

Step 2 – configure an Azure AD app registration

The other thing we need is an AAD app registration. You’ll need permissions in Azure to do this, but the following screens walk you through:

SNAGHTML25d10dea

In the next screen, the sign-on URL can be anything you like when being used with Flow – just use something logical:

SNAGHTML25d1c718

Then go into the Settings for the App Registration, and select ‘Required permissions’:

SNAGHTML25d30574

Click ‘Add’, and then select ‘Microsoft Graph’.

In the next screen that appears, find the ‘APPLICATION PERMISSIONS’ area and in that section, select the following:

SNAGHTML25d5651e

Click ‘Done’ to complete.

You’ll also need to ensure the user that the Flow runs as has consented to the permissions. The simplest way to do this is actually grant permissions to all users in the tenant, since this can be done easily with the Grant Permissions button:

SNAGHTML3a32a299

Otherwise you need to write some code which uses this AAD registration and can prompt the user to consent (in a browser session logged in as the user who owns the Flow). In this case, you might legitimately decide that the permissions that this app has are not too far-reaching, and applying the consent to all users is fine. 

Step 3 – implementing the Flow

OK, so let’s move to the main config step – configuring the Flow. There are two ways you could do this:

  • Import the Flow that I’m providing at the link below, and reconfigure a couple of things
  • Create the Flow yourself, and configure the same actions – I provide some info in the table below if you choose this route
Option 1 – import the Flow I provide:

You can download my Flow from this link:

https://github.com/chrisobriensp/COBGroupCreationFlow/blob/master/COBGroupCreationFlow.zip 

To import, go into the Flow area in Office 365 by finding the Flow icon in the app launcher. Once in there, you should see an option to import:

SNAGHTML3a5a3c99

You’ll need to do the following once the Flow has imported:

  1. Define a new SharePoint connection (or use an existing one) so that the Flow can connect to your SharePoint lists
  2. Edit Flow – overwrite the following settings:
    1. Edit all the HTTP actions (the green ones) – for each, enter YOUR AAD app registration details:
      1. Tenant (this is also known as the Directory ID of the AAD directory you’re working with – you can get this from the Azure portal, in the “Properties” area for your Azure Active Directory)
      2. Client ID
      3. Secret
    2. Edit the “When an item is created in Group Requests list” action – for this, you need to select the “Group Requests” SharePoint list you created earlier. There’s a slightly non-obvious thing here – you need to select “Enter Custom Value” from the dropdown, and you will then be allowed to type/paste in the the site URL where your list is. Once this is done, the 2nd dropdown should display all the lists in the site, and you can pick the right one
  3. Save the Flow
  4. Test!
Option 2 – create your own Flow, and configure the right actions:

If you prefer to create the Flow yourself, you’ll need to go to the “Group Requests” SharePoint list you created first. Click the “Flows” button on the command bar, then create a new Flow. Select the “when an item has been added” option. Here’s a high-level view of the actions to add to the Flow:

Action to add Purpose/name Steps you need to take
HTTP Create Office 365 Group (team space)

In this action, you’re making a POST request to the following Graph endpoint:

https://graph.microsoft.com/v1.0/groups 

Reference the Create Group documentation in the Graph to understand the headers and body to pass. Make sure to drop in variables for the values for the mailNickname, displayName and description of the Group.

Also specify details for your AAD app registration:

- Tenant ID

- Client ID

- Secret

Parse JSON Parse JSON (created Group details)

Parse response body from previous action - the purpose is to get the ID of the Group that was just created (so that we can add a Group owner later, and also to log the Group ID to the “Created Groups” list).

Paste the following into the ‘Schema’ box:

{

"type": "object",

"properties": {

"id": {

"type": "string"

},

"description": {

"type": [

"string",

"null"

]

},

"displayName": {

"type": [

"string",

"null"

]

},

"groupTypes": {

"type": "array",

"items": {

"type": "string"

}

},

"mail": {

"type": "string"

},

"mailEnabled": {

"type": "boolean"

},

"mailNickname": {

"type": "string"

},

"securityEnabled": {

"type": "boolean"

}

}

}

SharePoint - add item to list Add item to Created Groups list

Add an item to the other list (“Created Groups”) to log that the Group was created. Once you have selected the site, you should be able to select the list and reference columns.

Drop in variables from the previous “parse JSON” action to obtain the Group ID and display name.

HTTP Get user

In this action you’re making a GET request to the following Graph endpoint:

https://graph.microsoft.com/v1.0/users/ [UserID]

Reference the Get User documentation to understand how to call, but this one is simpler since no body or headers are required.

Make sure to drop in the variable for the UserID at the end of the URL – you’ll need the ID or UPN of the user. If your e-mail addresses are the same as UPNs, you can use the “Created by e-mail” variable from the first action in the flow (when a new item is added to the “Requested Groups” list).

Also specify details for your AAD app registration:

- Tenant ID

- Client ID

- Secret

Parse JSON Parse JSON (Group requester)

Parse response body from previous action - the purpose is to get the user ID (in AAD) of the Group requester, so that we can add this user as a Group owner.

Paste the following into the ‘Schema’ box:

{

"type": "object",

"properties": {

"businessPhones": {

"type": "array",

"items": {

"type": [

"string",

"null"

]

}

},

"userPrincipalName": {

"type": "string"

},

"id": {

"type": "string"

}

}

}      

HTTP Add owner to created Group

In this action, you’re making a POST request to the following Graph endpoint:

https://graph.microsoft.com/v1.0/groups/[Group ID]/owners/$ref

Reference the Add Group Owner documentation in the Graph to understand the headers and body to pass. Note that you need the Group ID in the URL, and the User ID to be passed in the body of the request – drop in variables from earlier actions as appropriate.

Also specify details for your AAD app registration:

- Tenant ID

- Client ID

- Secret

Summary

With the right combination of calls to the Graph and parsing the responses returned, it’s possible to create new Office 365 Groups and (add the requesting user as the owner) purely through Flow, with no need for custom code such as an Azure Function. Since Flow has great support for approvals, it’s easy to add whatever approval steps you need to get the control which is right for your organization – and approvers can approve/reject directly from the e-mail they receive, the Flow app on their phone or tablet, or the Flow approvals center. Perhaps some items in my 5 ideas for using Flow in your applications article could also be useful in helping you build out a really nice Group provisioning process – in some cases you might want to put a lot more effort in (e.g. to produce a custom form and user experience), but if you want something at the simpler end, the approach described here might be helpful. And if you do need a richer solution, perhaps consider that this Flow/Graph approach to provisioning Groups could be dropped in as the core mechanism in something bigger too. Good luck!