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?
- invoke the powershell cmdlet, but that seems to be so 2000-ish
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