Teams calling is a feature that allows you to provide your users with a Direct Inward Dialing number facility or DID. This allows your users to communicate effectively with customers and business partners who are external to your company. This also allows your customers and business partners to reach you directly using Public Telephony whereas you are reachable on Microsoft Teams with an extension number.
Before you can set up users in your organization to make and receive phone calls, you must assign phone numbers to them. To know more about this you can read an article here.
we started off with a project to assign Microsoft Teams phone numbers to our users as their Microsoft Teams extension. This allowed our users to be truly mobile. Their extension numbers that they were assigned during Avaya/Cisco days were no more stuck to their desk. We used AudioCodes as our SBC to integrate our Avaya Telephony with Microsoft Teams.
The benefits are immediately seen. Users can be reached on their extensions wherever they are. With the recent civil unrest in Hong Kong, we found that this was particularly useful for the business to be conducted from literally anywhere.
Whilst this really helped the business, but it created some overhead for our operations team. Now they had to continuously ensure that new joiners are assigned numbers whereas leaver’s number is unassigned and made available to another new joiner. Sometimes there is a need to reassign numbers between users.
We wanted to make this process seamless and ensure that numbers are assigned efficiently and promptly. However, with a legacy disjoined telephony system and lack of effective onboarding process someone had to go and setup users in Microsoft Teams with extension numbers.
We started off with an internal discussion on what approach should we follow to achieve this with minimal operational overhead. We decided to go with a couple of options 1) SharePoint list 2) Microsoft Flow 3) Azure Automation and 4) Skype for Business Online (sfb) Powershell
We started off working on 1) and 2) to get web-based frontend for our users so that they can simply key in the user`s email address (UPN), phone number and calling plan (Pre created) and submit a request.
Whilst this was all a modern way of getting things done we hit a few roadblocks.
a) We have accounts that are MFA enabled. When used with Azure Automation we had no way to make our script work with MFA based accounts.
b) We tried to use SPNs in Azure AD to grant permissions to Microsoft Teams so that we can use SPNs to setup numbers for end users however that is not supported by Microsoft Teams workload.
We were immediately limited, and we needed to get this automation done as soon as possible. It not only added a lot of overhead, but we were severely limited by resources.
We took a very simple approach.
a) We needed input from users (spread across different geographies). We had DFSR at our disposal. So we created a folder to receive input CSV files and replicate those to a central location. One CSV file per location updated by respective location information owners.
b) Files replicate using DFSR to a central location and our scripts use that file to stamp the numbers.
c) Once numbers are stamped in Microsoft Teams, clear the file.
d) If we receive any errors catch those and amend them in the output file. Finally, once all the CSVs are processed, send the output (status) files along with a message to all respective users using SMTP send.
You need to run two commands to assign a calling number/DID to a user.
Set-CsUser -Identity $Email -EnterpriseVoiceEnabled $true -HostedVoiceMail $true -OnPremLineURI tel:$Number
The command below assigns a routing plan. (This decides if your users can make international calls or just domestic calls. Or you can even limit them to make only internal extension numbers-based calls. More about Voice Routing Policies here.
Grant-CsOnlineVoiceRoutingPolicy -Identity $Email -PolicyName $CallingPlan
Challenges we faced to get this up and running.
1) First and foremost, the immediate challenge was to ensure that we can script this and ensure it runs on regular intervals without any manual intervention. So whatever script we came up with we needed to run it from an on-premises infra without any MFA prompts and any inputs. We needed to tackle MFA first.
We solved this by using location-based conditional access policy of Azure AD where we suppress MFA prompts from Known/Trusted Locations.
2) The next challenge was to provide credentials of the account that we needed to use safely and securely. For that, we created a key that store encrypted password and bypass MFA since the script run from trusted location (you can skip the MFA for users for trusted locations).
3) The third challenge was to connect to Skype For Business Online PowerShell admin0f.xxxx.lync.com from a dedicated server for this task that sat behind a corporate Http proxy. We managed to convince our security team to allow our server and user to be whitelisted on a proxy for admin0f.xxxx.lync.com and login.microsoftonline.com URLs.
4) The final challenge was to ensure that our PowerShell script ran from a task scheduler using the service account where the account was logged on or not. We also wanted to ensure that PowerShell always pointed to proxy to connect to SFBO Online Powershell.
We fixed that by adding the following commands and creating a Powershell profile file in the service account`s user profile. You have to atleast logon once with the service account on the server. Then create a PowerShell Profile file and add the proxy details in that file. Once you do that every time a PowerShell is launched in the user`s context it will always point to proxy and connect to SFBO.
Simply execute the following two commands, and all further connections in the session will use the proxy server transparently:
netsh winhttp import proxy source=ie
(New-Object System.Net.WebClient).Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
Taking this one step further, if you want to automatically run these commands every time you open the PowerShell command line, add them to the file returned by the $PROFILE variable:
Just open or create this file in Notepad or your favorite text editor and paste in those two lines above.
Thanks to <http://jongrant.org/2017/07/13/powershell-behind-a-proxy-server/> for this wonderful article.
With all the challenges tackled, we were now ready to try our script. We had few issues here and there, but we managed to work all through them and had one true automation of Teams number assignment.
How the script works ?
a) The script connects to the proxy.
b) Then uses the encrypted credentials and creates a Skype for Business Online session. Loads all the necessary cmdlets.
c) Reads the CSV file that the user updated. These CSV files supply the details such as email address of the user; number to be assigned and calling plan to be assigned. We need these 3 elements to get the Microsoft team's phone number assigned.
d) We read the CSV and check if there are any details in it. If no details simply exit or do nothing.
e) If there are any details, then load the info into variables and run set-csuser.
f) If there is any error while running this, capture the error details and send email to the user for that country with error code details.
g) If there is no error and execution is a success, send email to the user with success status.
The script also caters to offboarding an employee from Microsoft Teams.
To achieve this, requestors are advised to update the CSV file with the email address of the leaver and stamp number as $Null. Calling Plan can be anything as it doesn't`t really matter.
Use the same set-csuser however with $Null value to remove the assigned phone number.
Set-CsUser -Identity $Email -EnterpriseVoiceEnabled $False -HostedVoiceMail $False -OnPremLineURI $null
Please refer to the Attached powershell file (ps1) file for the code snippet.
The attachment contains powershell script ,.key file ,folder structure with CSV file and output file samples.
If the requester input number to CSV file and if that number that is already taken, then the script will throw an error saying the number is already assigned to someone. So instead of extending the script to check the user who taken the number, we decided to use SCCM and create a nice SSRS report so users can search based on number, user email, samaccount name, etc.
We went ahead and made this a complete solution by providing the requestors the ability to query the phone numbers. So they can refer to the SCCM report to make sure that the phone numbers are available and not assigned to someone else. I will share more on that in my next blog post and provide a link here once I am done writing it.
This post is written in collaboration with @alpsonthego