Automatically Notify Users to Update Teams Holidays for Next Year

In my last few articles, I’ve talked about building Teams Phone self-service solutions for end users. The reason one might want to do this…

In my last few articles, I’ve talked about building Teams Phone self-service solutions for end users. The reason one might want to do this is quite obvious: We don’t want to give users access to Teams Admin Center but as engineers, we don’t want to take on tedious tasks like updating an Auto Attendant’s Holiday list either.

Even though pretty much everything that can be configured in TAC, including managing Holidays can be scripted with PowerShell, Holidays still require a fixed date and time range and can’t be renewed automatically or fetched from an external source. This results in a considerable administrative overhead for both Teams admins and end users.

When I need to configure Teams Holidays, I always ask users to provide a list where each holiday is noted with an explicit date. I’m not going to do the work for them and go look up when exactly a Holiday takes place next year. (For Holidays which don’t have a fixed date at least.) I’ve seen some lazy users try to take a shortcut and tell me to just add “all lawful Bank Holidays” of Country/State/Canton XY. Unfortunately, that’s not how it works my dear users. I’d spend hours looking up this stuff and probably still end up with some wrong dates anyway. That’s why I set out and created a better solution. /rant

In this article, I’m going to show you a solution where the whole process of maintaining a Holiday List can be outsourced to end users. Admins only need to set up Holidays once initially.

Recap

Before we dive in, let’s recap what I’ve published in my last articles to give you some context on Teams self-service solutions using Azure Automation and Adaptive Cards.

It all began with this article where I wrote about my take on a self-service solution which lets users manually open or close an Auto Attendant. This solution builds on the work of Microsoft MVPs which are linked in the original article.

I then went on and published this piece which uses the same principle but lets users enable or disable immediate forwarding to an external number or update the external forwarding target number on a Call Queue.

We can use these examples and build on them to create something similar for Auto Attendant Holidays.

How Does it Work?

It’s important to understand that there needs to be an existing, initial configuration in your Tenant. This means that you as a Teams Phone admin need to sit down with the person in charge of the reception phone or whoever oversees Holidays at your company. You then need to configure either a single or multiple Holiday lists in TAC and link them to each Auto Attendant, where they’re required.

My solution currently doesn’t have an option to allow users to add new Holidays to a list. When a new Holiday needs to be added, users must still request the change at IT. After it has been added to the list, there’s no additional work required for the new Holiday to also support user self-serviced updating.

I created an Azure Runbook which runs on a schedule. I suppose running it weekly will suffice. If you wish, you can even run it daily. The script checks if the difference between the run time of the Job and the end date of a Holiday is bigger than 24 hours. This is because Holiday dates/lists itself don’t have a time zone property. But Auto Attendants do have a time zone setting, thus, we need to make sure that a Holiday is not updated/deleted before the Holiday would end in an Attendant specific time zone. A buffer of 24 hours should work well considering that the largest UTC offset is +14 hours.

When the script runs, it will send a Teams Message Card to a Channel for each Holiday which now lies in the past. (Even though they are technically Legacy Actionable Message Cards I will just refer to them as Adaptive Cards from now on.)

Members of the channel will be able to see the dates, the name of the Holiday schedule as well as all linked Auto Attendants on the Adaptive Card. Furthermore, the script will add one year to the current dates and pre-fill the dates of next year as a suggested value in the date picker.

Because we’re using Adaptive Cards, the date format will automatically adjust to the Teams Clients display language. In this example, the Teams Client was set to German (Switzerland).

Members can then review and accept the new dates or change them in case a Holiday falls on a different day next year.

If needed, they can also configure a start or end time, if for example, a Holiday only starts at noon.

Finally, they will need to select their local time zone. This is due to the fact that the Adaptive Card will submit the date and time based on the time zone which is configured on the local PC where Teams is running.

In early testing stages of this solution, “00:00” was always passed to the Azure Function as “23:00” because I live in UTC-1. Without this information the Function wouldn’t be able to do its magic and convert it back to the correct date.

I’ve included all time zones which are supported on Windows Systems.

Now all a user needs to do is to click “Submit New Dates”. This will pass all the information to an Azure Function, Update the card, and fire up the Runbook.

In other words, users won’t need to bother you to update their Holidays anymore. After each time a Holiday has passed, they will get a card which allows them to update it for next year by themselves.

Prerequisites

Just as with my previous articles you need to have the following things ready in Azure.

  • An Azure Function App so that we can create a new Function
  • An Azure Automation Account so we can create 2x new Runbooks
  • Azure Automation Credentials with Teams Administrator Permissions
  • An Incoming Teams Webhook

If you struggle to set up any of these, I recommend reading my first article about this topic. I also suggest creating a dedicated Teams Channel where the webhook will be added. More on that later.

Azure Runbook: CheckHolidaySchedules

Let’s create the first Runbook. This will be the one which logs into Teams PowerShell and checks if there are any Holidays which already lie in the past compared to the time of the Runbook Job.

Enter your $teamsWebhookUrl on line 2. If you like, you can change the $defaultLocalTimeZone on line 3 to the time zone where most of your users are located. Make sure you also adjust the name of your Credential if yours has a different name.

Leave the $functionUrl empty for now since we don’t have that one yet.

Save and publish the Runbook. Don’t forget to add a schedule to the Runbook. If you need a reminder on how to do that, please see here.

Azure Runbook: UpdateHolidaySchedules

This Runbook will receive all the information a user has entered on the Adaptive Card. Because we also want to update the card, but Runbooks don’t support that, we will pass all the information from the card to the Function first. This includes the old date time range (so the script knows which one needs to be replaced), the newly entered dates and the time zone of the user.

The Function will then pass the data to the Runbook. Because the script now has both the old and new dates, it will be able to remove the old values and add the new ones to the Holiday schedule.

Paste your Teams Webhook URL on line 7 before you save.

To be able to call this Runbook from the Function, we’ll need to add a Webhook trigger to it as it’s described here. Before you click Create, copy its URL.

Azure Function: UpdateCardAndTriggerRunbook

Now we can create the Function. Set $runBookUrl to the Runbook’s webhook URL on line 6 and save the Function.

For the last step, we need to copy the URL of the Function and go back to our first Runbook “CheckHolidaySchedules”.

Runbook CheckHolidaySchedules (Again)

Edit the Runbook and set the $functionUrl variable to the copied Function URL on line 1. Save and Publish the Runbook again.

Test Drive

During normal operation, we would need to wait for a Holiday to be over before anything happens. In our case, we can test by manually starting the Runbook.

After a few seconds, we should start seeing some new Adaptive Cards in our channel. Keep in mind that triggering the Runbook for the first time will post a card for each Holiday which has already passed. We can also see which Auto Attendants are affected on the card.

After new dates have been submitted by a user, the Function will update the card.

As soon as the Runbook has finished, it will post another card to the channel to confirm that the Holiday has been renewed for next year. For review purposes both the old and new dates are included. If anybody made a mistake, they could still contact IT to manually fix the dates.

If we switch to the Holiday list in TAC, we can see that the Runbook added the new Holiday and removed the old one.

Conclusion

Out of all the Teams self-service automations I already did, I think that this is actually the coolest one. Not only does it provide a great user experience because everything can be done from within Teams, but it also makes sure nobody forgets to update the company’s Holiday list. No more last-minute support tickets just before you were about to leave for the Christmas break.

And the best part is that we don’t need to grant any kind of admin permission. The only thing we need to make sure is that only the people who are allowed to update the Holidays have access to the Teams Channel.

The whole point of using a script to automatically notify us when a Holiday has passed instead of using the request a change on-demand approach like with the other two self-service examples is that nobody forgets about updating the Holidays. To make sure that users don’t miss the Adaptive Cards in Teams, I suggest using a dedicated channel and having them turn on notifications for all activity on said channel.

By using a dedicated channel for Holiday self-service, we don’t need to force users to turn on all notifications for channels which might have much more activity/trigger too many notifications.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Hosted on GitHub Pages
Built with Hugo
Theme Stack designed by Jimmy