Implementing Self-Service for End Users
In a previous article, I described the necessary steps to create an Azure Function connected to Exchange Online to allow users to perform actions like assigning mailbox permissions without administrator intervention. This is a very useful capability. Currently, there is no Microsoft Graph endpoint to allow users to update their Exchange Online mailbox settings.
Provisioning systems can leverage Azure functions by using HTTP transactions. By doing so, they can eliminate the dependency on the Exchange Online PowerShell V3 module.
With a kind of API for Exchange Online, we can use Azure functions to implement self-service capabilities for end-users to enhance their experience and productivity.
Creating an End-User Interface
In this article, I follow up on the previous article and show how to develop an interface for end-users using Microsoft PowerApps for interacting and rendering data from Exchange Online. In our case, data is the permissions of a mailbox.
I decided to use PowerApps as it is a low-code platform for the Microsoft 365 ecosystem that makes it relatively easy to create apps. If necessary, you can still write complex solutions. PowerApps offers a good balance between functionality and complexity.
Figure 1 shows the canvas app after a user signs in. The picture and user details come from the user’s account properties.
The user can either enter an email address in the text box and retrieve the permissions for the specified mailbox after pressing the “Get mailbox permissions” button. Alternatively, they can leave the text box empty and get the permissions for the user’s own mailbox. Figure 2 shows the permissions on Adele’s mailbox.
If an incorrect mailbox address is entered in the text box, the error from Exchange Online is displayed (Figure 3):
Creating the PowerApp
The solution is built with 2 parts. The first is the canvas app and its screen with labels, text boxes, buttons, and gallery. The other part is a flow, which triggers the Azure Function with an HTTP request.
Multiple ways exist to create a canvas app. I start with a blank app as shown in Figures 4 and 5.
Give your app a name. Note: This name is visible for users and should give information to end-users. It can be changed later, if necessary. (Figure 6)
Figure 7 shows the blank app we just created.
Now we need to add all the components we want to have represented to users (Figure 9):
- The image of the user: User().Image
- Three text labels:
- Fixed text: “User details:”
- User’s display name: User().FullName
- User’s e-mail address: User().Email
- One text label and one text input:
- Fixed text label: “Mailbox:”
- Variable text input: the property “Hint text” is filled with “Please provide e-mail address” (Figure 8)
4. The command button to trigger the flow
5. The gallery, which will be filled with data returned from our Azure function
6. Another text label, which is filled in case of an error by Exchange Online
Create the Flow
Before we add any code to our canvas app, we need to create our flow to trigger the Azure function and return data. This is similar to creating an app: multiple ways are possible. Here is mine:
In your app select the Flow symbol and create a new flow as shown in Figure 10.
The flow itself looks like the following (Figure 11):
- We create a variable “UserDetails” (which is the e-mail address) as the input from PowerApps (V2)
- Make sure there is no NULL input
- Send an HTTP request to our Azure function. Here you need to add two things:
- HTTP header “x-functions-key” for authorization
- Query parameter “name” with the value of “UserDetails”
- Finally, parse the response and create 3 text responses:
- rawResult: “if(contains(body(‘HTTP’),’An error occurred while processing this request’),”,array(body(‘HTTP’)))”
- rawError: ”if(contains(body(‘HTTP’),’An error occurred while processing this request’),body(‘HTTP’),”)”
- result: “if(contains(body(‘HTTP’),’An error occurred while processing this request’),false,true)”
Add Code to PowerApp
Now that we have our Flow and app created, we need to add some code and modify the layout of the gallery component.
First, add the following code to the button for the “OnSelect” attribute. The code will create a variable “rawPerms”, which will be used as the source (Figure 12):
Clear(rawPerms); Set (varFlowResponse, Mailboxpermission.Run( If(IsBlank(MailboxAddress.Text),User().Email,MailboxAddress.Text) ) ); If(varFlowResponse.result = “True”, ClearCollect( rawPerms, ForAll( Table(ParseJSON(varFlowResponse.rawresult)), { User: Text(Value.User), Accessrights: Concat(Table(Value.AccessRights),Value,",") } ) ), Blank() )
Make sure that you change the following attributes of the permission gallery (Figure 13):
- Data source: must be set to “rawPerms”
- Layout: must be set to “Blank”
As we have set the “Layout” to blank, we add the fields to be displayed. Add the following labels (Figures 14 and 15):
- Fixed text label for user and permissions: the values are “User” and “Permissions”
- Dynamic text label of all users and permissions in the response. For each row in the source table, a line will be generated by using ThisItem.User and ThisItem.Accessrights
Error Details
Finally, we add a text label to show details of any error returned by the Azure function. The following code must be added for the Text property (Figure 16):
If( varFlowResponse.result = “False”, "Error occured:" & Text(ParseJSON(varFlowResponse.rawerror)), Blank() )
Recommendations
I want to highlight that in PowerApps variables and flows are case-sensitive. Make sure that all variables, names etc. your using are correctly written. Otherwise, the canvas app will not work!
Here’s an example to illustrate the point (Figures 17 and 18).
The check of the result is text with Boolean. This seems to have changed and in my new app I received a warning:
It makes sense and I should have known better. However, this example clearly outlines complexity and many moving parts behind the scenes.
Conclusion
This example demonstrates how you can leverage Azure functions connected to Exchange Online sending HTTP requests without any PowerShell dependencies. With this, you can start building any kind of tools and/or apps for desktop or mobile devices (like you can do with Microsoft Graph).
This allows you to eliminate the existing gap in Microsoft Graph: missing Exchange Online support.
Hi Marcin,
it’s a beast. The name of the flow needs to be exactly the one you use in the code. In my case I named the flow “Mailboxpermission” and you run it with “Mailboxpermission.Run(…”.
I can see that you still have the default name for the flow “PowerAppV2->Condition…”
Ciao,
Ingo
Ahh missed this one, thank you. Seems like I am almost there.
Now I have the following error due to invalid arguments:
https://i.imgur.com/rGbs6OJ.png
Hi Marcin,
do you have the Text Input label named “MailboxAddress”?
Ciao,
Ingo
Yes Sir. It is displayed correctly when I highlight it. Looking at the error it seems like there is something wrong with the flow. I am trying to investigate it. Please see detailed screenshot:
https://i.imgur.com/4Rpo6Xa.png
Hi Marcin,
can you check if your flow works at all? Mayba just temporary issue? You should be able to test the flow and providing an e-mail address. Maybe you can see there more details.
So I have deleted the button and created from scratch. Flow started working perfectly fine but it could not find a recipient. It seems like you have made a small mistake in condition step. It should be “UserDetails” IS NOT EQUAL to null instead of IS EQUAL TO. Have a look on your screenshot 😉
Anyway, Power App is now working like a charm. Thank you very much, really appreciate your help!
Now I need to work a little bit on formatting the output. Any idea how to make smaller gaps between the results? So based on your example I would like to achieve something like this:
https://i.imgur.com/vBPMGhE.png
Hi Marcin,
thank you for pointing this out. I came across this and I took another screenshot. Obviously, I missed to replace the image…
In regards of the line height:
have a look at the “TemplateSize” property for the gallery. Decrease the value, which should do the trick.
I’ll have the article updated.
Thanks again!
Ciao,
Ingo
Hi Ingo. Great article but seems like I am stuck on creating 3 text responses inside the flow (rawResult, rawError, result). Says that the expression is invalid. Tried to replace ”” with ” and ‘’ with ” but with no luck. Not sure what I am doing wrong here. Any advise would be much appreciated.
OK. Figured it out. The key here was to use ‘ ‘ everywhere. So in my case rawResult expression looks like this:
if(contains(body(‘HTTP’),’An error occured while processing this request’),”,array(body(‘HTTP’)))
But now I am stuck on the next step (Add Code to PowerApp). Getting errors as follows:
https://i.imgur.com/WodHD0y.png