news and infos about microsoft, technology, cloud and more

Provisioning an Office 365 group with an approval flow and Azure functions-part 2

In part one, we saw how the Microsoft Graph API enables programmatic access to Office 365 groups. Now it’s time to let Azure Functions help us with the desired workflow.

For the following steps, an Azure subscription and a Global Admin in the target Office 365 tenant is required.

The plan

We want our provision group function to be able to create a new Office 365 group without any user interaction. So, we need an app with the permission to accomplish the operations in our Office 365 tenant, in the same way as did for the administrator account in part 1. The key is, to create such an application first and to use that access data in our code. The workflow will execute our function, pass the parameters, and the function will do the work. So, these are the necessary steps.

Create a new App

Open the Azure portal (in the target Office 365 tenant) with a Global Admin and click on the the "Azure Active Directory" service. Go to "App registrations". In here, click "New application registration".


…and fill out the new app "provisiongroupfunction" as Web app/API with a fake Sign-on URL as https://localhost:40000 (we won’t need that) as follows:


After the app was created, go to "Keys".


Add a new key "clientSecret", make it valid for 1 year and click "Save". Keys can be generated for 1 year, 2 years or without any expiration date. If you chose an expiration (which is usually a good idea), you need to renew the key from time to time.


Now the key is generated. You will not get any access to that key later, so save the key value, best to your OneNote, Notepad or similar tool.


We also need the "Application ID" property: 516b…


And of course, we need to set the permissions: Go to "Required Permissions", select the "Microsoft Graph" and select "Application Permissions" for "Read and write all groups". "Save" the app permissions.


Select more permissions depending on the desired features of the function if needed. We’re done with the app, but…

Get the tenant ID

..we need the "Tenant ID" as well. You get that in the "Properties" of the AAD with the "Directory-ID" property as shown here.


The Directory-ID d302… needs to go to our note. Now we’re done with the AAD. So we have this data collected:

string tenantId = "d302f5cf-00b3-44af-aff1-2cf91673813d";
string clientId = "516b6d70-05e4-43a7-bab1-6fa2060b04fa";
string clientSecret = "IQBz/fSblC…";

Create the Azure function as a container

The idea is to use server-less technology to provision an Office 365 group. No worries, we won’t need Visual Studio, Visual Studio Code (which BTW are great tools and highly recommended for larger code projects…) or any similar environment. We can perform all necessary steps online directly in the Azure Portal.

So, let’s create the new Azure function and fill it out… We are working with loose coupled architecture, so we can use any Azure subscription which must not be associated with the Office 365 tenant. This approach allows to build "black boxes" and to tie them together as needed easily. In our case, we let the function run in another Azure subscription.


Of course, Azure functions are a wide topic with many details, but this article concentrates on the solution. To learn more about Azure functions, see here and the videos on channel9.

Use a programing language – PowerShell is good enough

In Azure functions, there are several programing languages supported. We could use C#, F#, Javascript or … PowerShell. So, let’s keep it simple and use PowerShell, so that IT-Admins who are familiar with PowerShell can easily follow and understand this sample. (In my GitHub repository, you find the solution in C# and in PowerShell) , So, we create a new Azure function of type "HttpTrigger – PowerShell" as here.


The function name shall be "ProvisionGroup". Let’s create that with the default authorization level "Function" – we don’t want to use a user authorization in our scenario.


…and we get the new function with some default code from a template. When clicking "Run", the function shows the basic concept with an HTTP POST operation, a JSON input and a text output as here:


Develop the function and and configure it

The function needs to perform several operations. Keep in mind that Azure functions run in a sandbox, to be more specific, in an App service in a Virtual machine. You can use default functionality, but you need to take care if you need to integrate other libraries or modules that by default are not installed in the Windows environment. We don’t have any dependencies in our sample. Currently, PowerShell version 4.0 is available.

Ok, we also need to store the app data somewhere. Instead of having these values in the code, it’s more elegant (and safe) to save these as App Settings. In here, we need to add keys for the TenantID. the AppID and the AppSecret as here. The values must be inserted from the app we created above.


Now we’re good to code…

The PowerShell code

Get the code from my GitHub repository Officde365scripts at (directly here)  and paste it into the code window.


The functions reads two parameters from the HTTP body: groupname and upn. groupname is the name of the new group and since this is also the email address of the group, this must be compliant. upn is the login name of the group owner who shall be responsible for the group.

Then, it calls the Initialize-Authorization PowerShell function to authenticate with the app values from our AppSettings. If this works, we get an AccessToken that is stored in the global variable $script:APIHeader. This is the key we need to add to each Graph API operation. It must be sent in the HTTP header with the Bearer key name. So, this header is fully generated by the Initialize-Authorization function and can be added for each call.

Now back to the literal functionality. We need to do four operations:

  1. Create the group and get back the GroupID
  2. Get the UserID of the UPN passed as parameter
  3. Add the UserID as owner of the group with the GroupID
  4. Add the UserID as member of the group with the GroupID

Each request is sent as a HTTP POST operation with the PowerShell command $result = Invoke-RestMethod -Method Post and a JSON body as described in part 1. If the HTTP result of the operation is OK or Created, we know that the operation was successful and continue. In all cases, the function itself returns HTTP OK for not stopping the Flow (which will be described in part 3).

Test it

Add the parameters in the "Test" request body textbox.


Now click "Run".


The group will now be created and the user will become owner of the new group. Check the mailbox of the owner. The new group will show up in the groups list as here.


So, if this function works, we get the address of the function.

Get the function endpoint

As last step in this part, we need to save the function URL to use it in the workflow. You get it with the" Get function URL" link as here:


Off to the flow…

After we created and tested the Azure function, we can finish this workflow in part 3.


Pingbacks and trackbacks (4)+