2

TL;DR:

what's the MS Graph API for setting the teams call forwarding policy of an user?

Background:

Currently I'm trying to migrate a Lync/Skype-based .NET application to Teams. The Teams related part is about setting the call forwarding preferences of a few specific users. Those users have direct routing enabled, i.e. you can call a fixed PSTN/suffix number and the user will receive the call on his mobile. That mobile number is depending on the shift, so the programm is adapting it to whoever has the shift duty at that time.

What I've tried so far?

  • I can authenticate with the MS Graph API.
  • I know that there's TAC extension for this purpose ([1] and [2])
  • There's also a Powershell extension [3]
  • I'm not the first one to ask the question, but other threads usually got stuck [4]
  • The Call-Redirect is not what I want, as I'm not actively listening on those instances.
  • There's a github for Teams related scripts, but unfortunately without sources ...
  • I haven't yet reflected the Powershell extension
  • There is a promising user settings entry, where you can change shifts but not the call forwarding

Plan B?

Update 2022-06-20

  • I'm starting to reflect the ps module. So API seems to be something like https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/ + userId
  • The teams user id can be retrieved
  • Some parts of teams rely still on an older REST API (german only, sorry)

Update 2022-06-30

a POC which can be improved would look like this (... if I've packed into the usual AcquireTokenOnBehalfOf, then I'll add it as an answer ...)

Imports System.IO
Imports Microsoft.Identity.Client
Imports System.Globalization
Imports System.Net.Http
Imports System.Text
Imports System.Net.Http.Headers
Imports System.Net
Imports Newtonsoft.Json
Imports System.IdentityModel.Tokens.Jwt

Public Class LyncTest

    Public Shared Sub Test()
        Dim InstanceId As String = "https://login.microsoftonline.com/"
        Dim RedirectURI As String = "https://login.microsoftonline.com/common/oauth2/nativeclient"

        ' Ids / Secrets and can be found on your Azure application page
        Dim TenantId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        Dim AppId As String = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        Dim secretVal As String = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        Dim username As String = "xxxxxxx.xxxxxx@xxxxxxxxxxxx.com"
        Dim password As String = "xxxxxxxxxxxx"
        ' Teams scope
        Dim scope As String = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"

        Dim httpClient = New HttpClient()

        ' start resource owner password credential flow
        ' see https://learn.microsoft.com/en-us/powershell/module/teams/connect-microsoftteams?view=teams-ps#example-4-connect-to-microsoftteams-using-accesstokens
        Dim baseParam As String =
            $"client_id={AppId}" &
            $"&username={WebUtility.UrlEncode(username)}" &
            $"&password={WebUtility.UrlEncode(password)}" &
            $"&grant_type=password" &
            $"&client_secret={WebUtility.UrlEncode(secretVal)}" &
            $"&scope={scope}"

        ' get user_impersonation token
        Dim tokenReq As New HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/token") With {
            .Content = New StringContent(baseParam, Encoding.UTF8, "application/x-www-form-urlencoded")
        }
        Dim TokenRes As HttpResponseMessage = httpClient.SendAsync(tokenReq).Result
        Dim TokenObj As GraphToken = JsonConvert.DeserializeObject(Of GraphToken)(TokenRes.Content.ReadAsStringAsync.Result())
        Dim JwtReader As New JwtSecurityTokenHandler
        Dim JwtToken As JwtSecurityToken = JwtReader.ReadToken(TokenObj.AccessToken)
        Dim UserOid As String = JwtToken.Payload("oid")

        ' set user calling routing
        Dim RoutingURL As String = $"https://api.interfaces.records.teams.microsoft.com/Skype.VoiceGroup/userRoutingSettings/{UserOid}"

        httpClient.DefaultRequestHeaders.Authorization = New AuthenticationHeaderValue("Bearer", TokenObj.AccessToken)

        Dim RoutingJSON As String =
            "{""sipUri"":""sip:andreas.beeker@kraiburg-tpe.com""," &
            """forwardingSettings"":{""isEnabled"":false,""forwardingType"":""Simultaneous"",""targetType"":""Unknown"",""target"":""""}," &
            """unansweredSettings"":{""isEnabled"":true,""targetType"":""SingleTarget"",""target"":""+491701234567"",""delay"":""00:00:20""}," &
            """callGroupDetails"":{""targets"":[],""order"":""Simultaneous""},""callGroupMembershipSettings"":{""callGroupMembershipDetails"":[]}}"

        Dim RoutingReq As New HttpRequestMessage(HttpMethod.Post, RoutingURL) With {
            .Content = New StringContent(RoutingJSON, Encoding.UTF8, "application/json")
        }
        Dim RoutingRes As HttpResponseMessage = httpClient.SendAsync(RoutingReq).Result

        Console.WriteLine(If(RoutingRes.IsSuccessStatusCode, "success", "failed"))
    End Sub

    Public Class GraphToken
        <JsonProperty(PropertyName:="access_token")>
        Public Property AccessToken As String
        <JsonProperty(PropertyName:="expires_in")>
        Public Property ExpiresIn As Integer
        <JsonProperty(PropertyName:="ext_expires_in")>
        Public Property ExpiresInExt As Integer
        <JsonProperty(PropertyName:="scope")>
        Public Property Scope As String
        <JsonProperty(PropertyName:="token_type")>
        Public Property TokenType As String

    End Class
End Class
kiwiwings
  • 3,386
  • 1
  • 21
  • 57
  • Could you please refer below doc: https://learn.microsoft.com/en-us/MicrosoftTeams/teams-calling-policy – Nivedipa-MSFT Jun 20 '22 at 06:51
  • @Nivedipa-MSFT I've already referenced the corresponding PowerShell command. I need the MS Graph API call ... of course I know how to this via the GUI, but this is about automation. furthermore your linked calling policy is the general setting, which doesn't contain a phone number. – kiwiwings Jun 20 '22 at 11:00
  • You can Forward a call to a PSTN number using [redirect](https://learn.microsoft.com/en-us/graph/api/call-redirect?view=graph-rest-1.0&tabs=http#example-3-forward-a-call-to-a-pstn-number) graph api. Then what exactly are you trying to achieve. Could you please elaborate on your issue? – Nivedipa-MSFT Jun 24 '22 at 10:57
  • @Nivedipa-MSFT: The redirect graph api means, I need to constantly listen to incoming calls on the phone numbers I'd like to redirect. I don't want to reinvent something Teams can do better than I - my service is also restarting itself once in a while. So my current problem is to get the bearer token for the teams internal userRoutingSettings call - which is [partly described](https://docs.microsoft.com/en-us/powershell/module/teams/connect-microsoftteams#example-4-connect-to-microsoftteams-using-accesstokens). The other REST calls can be easily identified as in the linked msxfaq.de article. – kiwiwings Jun 27 '22 at 07:20

2 Answers2

2

There is no Graph API available for setting the teams call forwarding policy of an user.

Any user policy/tenant configuration are only exposed through PowerShell or admin portal now.

Nivedipa-MSFT
  • 1,237
  • 1
  • 2
  • 8
  • Although you are technically correct that there's no Graph API, which was the assumption in my original question, it's possible to use the Teams Rest API with the Graph Token - I've updated my question with a POC. This ofcourse only works when MFA is not requested, e.g. in a conditional-access setup. – kiwiwings Jun 30 '22 at 13:14
0

If you just want to change the forwarding status in Teams without catching callId and transferring individual calls, there is a simpler way by using PowerShell:

  1. Install PowerShell module for M$Teams https://www.powershellgallery.com/packages/MicrosoftTeams straight to PowerShell, for example by using

    Install-Module -Name MicrosoftTeams -RequiredVersion 4.6.0 -AllowClobber

  2. Assuming that you have permission set up forwarding by using Set-CsUserCallingSettings command, for example

    Set-CsUserCallingSettings -Identity user@email.com -IsUnansweredEnabled $FALSE

    Set-CsUserCallingSettings -Identity user@email.com -IsForwardingEnabled $true -ForwardingType Immediate -ForwardingTargetType SingleTarget -ForwardingTarget "+123456789"

In theory, only the second line is necessary, but I've noticed that PowerShell throws an error if Voicemail is enabled

This will change the forwarding status for all calls incoming to the selected identity. Note, that the user can change it still in Teams GUI.

Yasskier
  • 791
  • 1
  • 14
  • 36