Advanced Teams Auto Attendant Troubleshooting

It’s that time of the year again. The holidays are right around the corner. Which begs the question: Did you update the holiday schedules…

It’s that time of the year again. The holidays are right around the corner. Which begs the question: Did you update the holiday schedules for your Teams Auto Attendants already? And if so, are you sure they’re configured correctly?

No? Me neither. But I do remember that I wrote a comprehensive guide about Everything You Ever Wanted to Know About Teams Holidays about a year ago. This is a great resource to read up on some of my personal best practices and some lesser-known things about Teams Holidays and how they work.

If you’d rather outsource this to end users for next year, this article might be interesting to you as well.

What is today’s blog post all about?

I recently built a very large follow the sun type of call flow which consists of about ten different Auto Attendants and Call Queues. Each Auto Attendant has different business hours, and many Auto Attendants have a different time zone configured as well. This can get quite complicated to build, verify and troubleshoot. How can something like this be tested and verified that it works as intended?

Since this was not live yet, I started out by adding a greeting to each Call Queue which said the name of the Queue whenever a call was routed to a Call Queue. Then I just made a couple of test calls during the day to see if calls were routed to the correct Queue.

But then I thought of something much better. I’ve already got the M365 Call Flow Visualizer script in place which is capable of reading all nested voice apps recursively from any starting point. I only had to code some additional stuff to check whether an Auto Attendant is currently in business hours, after hours or in a holiday schedule. The best part about this is that it works for any date. Past, present and future. And of course, any date and time is converted to the time zone which is configured on each Auto Attendant in your call flow. Just as if you would call the Auto Attendant.

Demo Call Flow

This is the demo call flow I’ll be using to demonstrate and explain the new feature. Nothing crazy, just an Auto Attendant with two holiday call handlings and schedules and some business hours.

Note that the Auto Attendant is configured in Pacific Standard Time while I live in W. Europe Standard Time.

How to Check Business Hours and Holidays

To check if any Auto Attendant is currently in business hours or after hours or in a holiday schedule, simply run the M365 CFV script with the switch parameter -CheckCallFlowRouting .

Note that the-CheckCallFlowRouting parameter is not mutually exclusive from the Visualizer. You can generate a diagram and check business hours/holiday in the same script run.

. .\M365CallFlowVisualizerV2.ps1 -CheckCallFlowRouting -Identity edde8e13-1a73-434b-a724-xxxxxxxxxxxx

This will use your local system time and convert it to whatever time zone is set on the Auto Attendant. The script will output the local and the Auto Attendant time and time zones.

As you can see, it’s already Tuesday in Switzerland but it’s still Monday in Pacific Standard Time. Since the business hours for Monday are only configured to 17:45 PST the Auto Attendant is closed.

Further down in the output, we’ll see the information about holidays as well. In this case, the Auto Attendant has actually multiple holidays which match my local date and time. While an Auto Attendant can’t have two holidays with the same start date, it’s possible to have holidays which enclose others and/or have the same end date. In that case, the holiday which is most precise (smallest time range) will be active. (This is also explained in the Everything You Ever Wanted to Know About Teams Holidays article linked at the beginning of this post.)

In PST, it’s still Monday, November 6th and there are three holidays starting on this date. One starts at 00:00:00 one at 17:15:00 and one at 17:30:00 . The time in PST is currently 23:50:00 so it’s already past all start times of the aforementioned holidays which means, the one starting at 17:30:00 is the currently active one, because its start time is closest to the current time. You can see the name of the active holiday call handling and holiday schedule in the output. But that’s not all. You can also see that it lists the actual time range of the schedule on the line which starts with Holiday Schedule: .

If nobody can answer a call, during business hours, after hours, this demo Auto Attendant (USA Toll Free Test) just forwards to another Auto Attendant called Main Number Busy AA which will just play a greeting and disconnect. This Auto Attendant does not have any business hours or holidays configured, which is also visible in the console output when the -CheckCallFlowRouting switch is used.

It even tells you that it’s a nested Auto Attendant and which was the initially queried Auto Attendant.

Advanced Check

Obviously, we won’t always have the time or the patience to stay up all night just to verify that business hours or holidays are configured correctly on an Auto Attendant which serves customers on the other end of the world.

To check the call flow routing for any specific date we can just pass an additional parameter to the script. It doesn’t matter if the date lies in the past or in the future.

-CheckCallFlowRouting -CheckCallFlowRoutingSpecificDate "07.11.2024 17:00:01"

The only thing you need to consider is that you need to enter it in a format which is expected by your system. This depends on your regional settings in Windows.

For me that would be dd.MM.yyyy HH:mm:ss . You can test this using the following code.

Get-Date -Date “08.11.2023 17:00:01”

If you for example, typically use MM/dd/yyyy HH:mm:ss you have to specify it like this.

Get-Date -Date “11/08/2023 17:00:01”

As long as this doesn’t throw an error and the returned date is correct, you should be fine.

When I queried the Auto Attendant in the first example it was 08:50:00 in my local time. Now, I’m going to query the same Auto Attendant again but this time, I’m specifying a date and time which was 7 hours before at 07.11.2023 01:50:00.

. .\M365CallFlowVisualizerV2.ps1 -CheckCallFlowRouting -Identity edde8e13-1a73-434b-a724-xxxxxxxxxxxx -CheckCallFlowRoutingSpecificDateTime “07.11.2023 01:50:00”

At this time, which is 16:50:00 in PST, the Auto Attendant was still open. Even though there are multiple schedules configured for Monday (which are also listed in the output) the script is still able to determine which time range from the Monday schedule is the currently active one.

And because it’s not 17:15:00 or 17:30:00 in PST yet, there are only two matching holiday schedules returned now.

Let’s check what happens if we query it again after the holiday on 18.11.2023 has ended. Pacific Standard Time is currently -9 hours from W. Europe Standard Time. So, I need to check for 18.11.2023 .

If I check for 18.11.2023 00:00:00 it’s still in the holiday schedule.

But if I check for 18.11.2023 00:00:01 the holiday is over, but since this is a Saturday, the Auto Attendant is closed because of business hours anyway.

Let’s try Monday 20.11.2023 17:15:00.

Looks good, the Auto Attendant is open again. However, there is one caveat. There is another holiday scheduled on 20.11.2023 (which can be seen in the diagram above as well). Holidays always take precedence over business hours.

The M365 CFV was built in a way, where it first checks the business hours and then the holidays. So, there’s no easy way to properly reflect that in the output, because the script is unaware of possible holidays at the time it outputs the information about business hours. I’m sure it’s possible somehow but I don’t know how much work that would require.

For now, we must accept that and just pay attention to all the output. If there’s an active holiday, business hours will be disregarded until that holiday is over. On the other hand, I think it’s great to get all the information, so one could check how the call would have been routed at that date and time, if it weren’t a holiday.

Let’s do one more check to see if everything will be back to normal on 21.11.2023 .

I set the time to 21.11.2023 23:30:00 so that it would be 21.11.2023 14:30:00 in PST which is covered by the second date time range on Tuesday’s schedule. Looks good to me.

Deep Dive on Auto Attendant Schedules

There’s one more thing I want to mention. You might have noticed the Complement: Enabled output in the screenshots above. This is a parameter which belongs to New-CsOnlineSchedule or Set-CsOnlineSchedule which is used to create/update business hours schedules for Auto Attendants. You can find the official parameter description here.

As of writing this article, it says the following:

The Complement parameter indicates how the schedule is used. When Complement is enabled, the schedule is used as the inverse of the provided configuration. For example, if Complement is enabled and the schedule only contains time ranges of Monday to Friday from 9AM to 5PM, then the schedule is active at all times other than the specified time ranges.

If you think about this from looking at Teams Admin Center and how business hours are configured under Call flow for after hours in TAC it makes sense. There is no way to configure business hours under Call flow (which is the default call flow). So, when you configure Business and after hours, the time ranges you define will be the times during which the default call flow is active. Outside of the configured times, the after hours call flow will be active. This is 100% in line with what the docs say for the -Complement switch parameter.

It’s not possible to set ComplementEnabled to $false using Teams Admin Center. It’s only possible through PowerShell. This will set ComplementEnabled to $false on an Auto Attendant’s after hours schedule.

# Define Auto Attendant
$aaId = “b74da106-ea89-4786-b8aa-xxxxxxxxxxxx”
$aa = Get-CsAutoAttendant -Identity $aaId

# Get schedule
$schedule = Get-CsOnlineSchedule -Id $aa.Schedules.Id

# Disable ComplementEnabled
$schedule.WeeklyRecurrentSchedule.ComplementEnabled = $false

# Check value in schedule variable

# Set new (disabled) value for the schedule
Set-CsOnlineSchedule -Instance $schedule

# Check result
$aa = Get-CsAutoAttendant -Identity $aaId

In this case, the after hours call flow will be active during the specified time ranges.

This is where it gets complicated. Any time you change business hours in Teams Admin Center, complement will be ENABLED again without any warning. I haven’t figured out changing which properties exactly trigger TAC to reset the Complement setting but it’s definitely not just editing business hours. A change to the default and after hours call flow greeting resulted in TAC overwritting ComplementEnabledto $true too.

Also, Teams Admin Center won’t display open/closed hours correctly when complement is off. When I view the after hours call flow in TAC, it says, it’s closed during that time when in fact it should say open.

I verified that the schedule is in fact not inverted by calling the Auto Attendant at 11:26 which is within the defined time range of 09:30-12:00 . I was indeed able to hear the greeting which was configured for the after hours call flow. To summarize: setting ComplementEnabled to $false through PowerShell is working, but TAC won’t display it correctly.

I’ve enabled complement again to verify if there’s any change in how TAC displays things. There isn’t. TAC simply doesn’t care if ComlementEnabled is enabled or disabled.

After I enabled ComplementEnabled I called the Auto Attendant again, still between 09:30-12:00 and was able to hear the greeting which is configured for the default call flow.

Sadly, I didn’t consider this in the CFV so here, the output was wrong, when Complement is disabled.

When Complement is disabled, the Yes and No nodes should be switched.

The output of the CheckCallFlowRouting is correct though. Even though the checked time of 11:41 is within the schedule 09:30:00-12:00:00 it says it’s closed because Complement is disabled. In this case, the colors (red/green) are also inverted, and it says Active After Hours Time Range instead of Active Business Hours Time Range.

When I check it for 13:49 which is not part of the specified schedule, the Auto Attendant is open, and the default call flow is active.

Luckily, it was easy enough to fix the CFV and add support for Complement disabled schedules in Version 3.1.1. Even when you don’t use the CheckCallFlowRouting paraemeter, you’ll still see a warning when ComplementEnabled is $false .

Here we can see an Auto Attendant, which has two nested AAs. One has Complement disabled and the other one enabled and everything is displayed correctly now. You can see that on the left side, for Complement Disabled AA the Yes option for the business hours goes to the after hours call flow greeting. On the right side for Complement Enabled AA it’s the opposite. (This is the standard.)

And here you can see, that the after hours call flow greeting in TAC for Complement Disabled AA says: This is the after hours greeting.

You can get Version 3.1.1 of the M365 CFV from my GitHub.

Anyway, this doesn’t change the fact that I strongly recommend not to use **ComplementEnabled: $false** in any case. There’s no point in using it since TAC won’t display it correctly and even more important, will always set it to $true again if you update the Auto Attendant through TAC.

Using schedules with Complement enabled (inverted) schedules makes total sense because the business hours are configured under Call flow for after hours and the title says Set business hours in TAC, so, it’s only logical that the schedules are inverted and that the after hours call flow is active outside of the configured business hours and business hours (default call flow) are active during the specified time ranges.

I hope that this new feature, to check any Auto Attendant’s schedules for any given date and time, also helps you to verify and troubleshoot complex call flows more efficiently. By the way, thanks to a Pull Request from a community member, the CFV now also supports export to PDF!

If you like my work, feel free to consider sponsoring my work through my GitHub Sponsors Profile.

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