One of the past projects I worked on for a client was to help them move from a Mitel PBX phone system to Microsoft Teams as their phone system. Aside from the design and implementation for the routing during the transition and cutover, a key pain point for their organization was to allow their help desk to easily configure Microsoft Teams users for Enterprise Voice. The Microsoft Teams PowerShell cmdlets required to configure a user can be easily copied and paste as the following sample:
$dialPlan = "Toronto"
$voiceRoutingPolicy = "Toronto"
$usernameUPN = "firstname.lastname@example.org"
$extension = "tel:+141655555390;ext=390"
Set-CsUser -Identity $usernameUPN -EnterpriseVoiceEnabled $true -HostedVoiceMail $true -LineURI $extension
Grant-CsTenantDialPlan -PolicyName $dialPlan -Identity (Get-CsOnlineUser $usernameUPN).SipAddress
Grant-CsOnlineVoiceRoutingPolicy -Identity $usernameUPN -PolicyName $voiceRoutingPolicy
… but this wasn’t very friendly for the helpdesk team. What I ended up presenting to the client was to leverage the existing Microsoft 365 and Azure services they already had to provide a form for the helpdesk team to fill in that would then configure the accounts. The components required for this automation are the following:
- MS Teams Channel
- Logic App
- Automation Account
The organization already used Teams channels heavily, which meant no training was required for the team when we created a Form that was displayed as an additional tab in a Microsoft Teams Team. Once the form is filled out and submitted, it would send the fields to a Logic App that will then execute a Runbook in and Automation Account to configure the desired user. We started off with a simple form, then added an approval notification, and finally to a customized web page. I did not get to document the settings but would like to replicate part of the configuration in the post to demonstrate the process.
What this post will provide are as follows:
- Creating a form displayed as an additional tab in a Microsoft Teams team
- Creating a Logic App that will be triggered when a new response is submitted from Microsoft Forms
- The Logic App will retrieve the two fields: email address and DID, then use a runbook in an Automation Account to configure the user
Before I begin, this post was written on June 5, 2022 when the Connect-MicrosoftTeams cmdlet has removed the -ApplicationId switch for defining a service principal with the AccessTokens authentication. I spent a full day going through pages of forum and blog posts to realize that none of the modules up to the current 4.4.1 works as Microsoft is still in the process of fixing it. Having exhausted all the avenues including Graph (it does not provide the functionality to configure anything outside of Teams at the moment), I decided use a regular user account with permissions and 2FA disabled. This is absolutely not best practice and I always discourage the use of non-Service Principals or Managed Identities for automation but there does not appear to be an alternate method.
With that, let’s get started!
Creating an embedded Microsoft Form in a Team
Begin by creating a Microsoft Teams Team that will host the Microsoft Form and click on the + sign in the tabs:
Click on the Forms icon:
Type in a name for the new form and click on the Save button:
The new form should now be displayed and can be edited if you click on the fields:
With the form created, proceed to close the form in editing mode by click on the Edit | <Form name> and click on the Remove option:
The message can be a bit misleading but proceed to remove it as we’ll be re-adding it back in:
With the form removed, proceed to click on the + sign in the tab again:
Click on the form icon again:
We will now use the Add an existing form option to add the form we had just created:
The form will now be in Fill mode (non editing):
Obtain the Form ID
We will need the form ID for the Logic App to reference so navigate to www.office.com, click on the top left corner tile button and then Forms:
The most recent for we created will be displayed but if the recent list contains other documents you have worked on that has pushed the form off the list then we can navigate to it by clicking on the team under My Groups:
Proceed to open the form by clicking on it:
With the form displayed in the browser, copy the URL and locate the string after the id= string and copy it:
Create the Logic App
Now that we have the form to collect the user input created, proceed to create a new Logic App:
Fill in the appropriate fields for the new Logic App:
Create the Logic App:
With the Logic App created, proceed to navigate to the Logic app designer:
Scroll down to the Templates section and create a Blank Logic App:
A new blank template will be discovered for steps to be configured:
Type in Microsoft Forms in the search field and click on When a new response is submitted:
Sign into the tenant to create a connection to Microsoft Forms:
Select Enter custom Value for the Form Id:
Paste in the form ID we copied previously:
Proceed to create a new step, type in Get response details in the search field and select the action:
Paste in the previously copied form Id into the Form Id field and select List of response notifications Response ID for the Response ID field:
Proceed to save the Logic App:
Create Service Principal
I, unfortunately, could not get the Connect-MicrosoftTeams module to use a service principal for authentication but will include the instructions and update this post when it is fixed.
Navigate to App Registrations > New Registration:
Provide a name for the App Registration and click on Register:
Create a new client secret and document the following fields for the App Registration:
- Application (client) ID
- Object ID
- Directory (tenant) ID
- Secret ID
I won’t include the permissions that are required as I’m not sure if the documentation will change when the module is fixed.
Create the Automation Account and Runbook
The automation account will need to store the credentials of the service principal that will run the Microsoft Teams cmdlets. Navigate to the Credentials blade and click on Add a credential:
Navigate to the Credentials blade and configure the App Registration / Service Principal credential that the PowerShell script will use to authenticate against Azure AD:
Add the service principal credentials.
**Note that for the purpose of this example, I actually put in a regular user account without 2FA as service principal authentication currently does not work with the Connect-MicrosoftTeams module:
The following screenshot shows the service principal credentials configured:
We’ll need to reference the tenant ID when the Service Principal authentication with Connect-MicrosoftTeams module works so I will include the steps to create the variable that will be called within the PowerShell script runbook:
The Automation Account will not have the MicrosoftTeams module available by default so click on Browse gallery:
Search for MicrosoftTeams and install it:
With the credentials, variable and module configured, we can now navigate to Runbooks to create a new runbook:
Select PowerShell for Runbook type and 5.1 for Runtime version:
In the PowerShell Runbook paste the following code:
Obtain email address and DID and enable user for Teams enterprise voice
AUTHOR: Terence Luk
LASTEDIT: June 4, 2022
[Parameter (Mandatory= $true)]
[Parameter (Mandatory= $true)]
# Connect to Azure with App Registration Service Principal Secret
# Retrieve the App Registration credential (App ID and secret)
$spCredential = Get-AutomationPSCredential -Name 'Teams Administrator Account'
# Retrieve the Azure AD tenant ID
$tenantID = Get-AutomationVariable -Name 'Tenant ID'
Connect-MicrosoftTeams -Credential $spCredential
# Declare variables with for dial plan and voice routing policy (can also be passed by form)
$dialPlan = "Toronto"
$voiceRoutingPolicy = "Toronto"
# Convert DID to e164 format with ;ext= extension format
$extension = $DID.SubString($DID.length - 3, 3)
$e164 = "tel:+1" + $DID + ";ext=" + $extension
Write-Host "Teams DID value:" $e164
Set-CsUser -Identity $EmailAddress -EnterpriseVoiceEnabled $true -HostedVoiceMail $true -LineURI $e164
Grant-CsTenantDialPlan -PolicyName $dialPlan -Identity (Get-CsOnlineUser $EmailAddress).SipAddress
Grant-CsOnlineVoiceRoutingPolicy -Identity $EmailAddress -PolicyName $voiceRoutingPolicy
Get-CsOnlineUser -Identity $EmailAddress | FL *uri*,*voice*,*dial*
Proceed to publish the runbook:
You can test the PowerShell runbook by clicking start as it should ask you for the email address and DID values:
Complete configuring Logic App
With the Automation Account and Runbook configured, navigate back to the logic app to execute the Runbook when a form is submitted. Proceed by adding an additional step, search for Create Job and click on Create Job under Actions:
Fill the values for the Create job step and ensure you configure the Runbook Parameter EmailAddress and Runbook Parameter DID with the form submission:
… and that should be it. A user using the form in the Microsoft Teams Team will not be able to configure a licensed user for Enterprise Voice. This automation can be expanded to assigning the appropriate license, other enterprise voice configuration such as dial plan and voice routing policy (these are hard coded in the example), approval, email notification and much more.
Hope this helps anyone who might be looking for a demonstration of this!