SfB2Teams Telefonieumstellung

Solange sie mit Skype for Business On-Premises Telefonieren und im Hybrid Mode mit ADSync auch die Rufnummernkonfiguration (msRTCSIP-line) replizieren, brauchen Sie in der Cloud fast gar keine Rufnummern verwalten. Sobald sie aber die lokale SfB-Installation zurückbauen wollen, müssen Sie die Benutzer mit Disable-CSUser deaktivieren, ehe Sie den Pol löschen können. Tun sie dies nie ohne "vorbereitet" zu sein, denn ADSync löscht dann auch die Rufnummernzuweisung in der CLoud

SfB to Teams

Ich fange damit an, dass ich einen Benutzer in Skype for Business On-Premises mit Enterprise Voice aktiviert und einer Rufnummer versehen habe. Dieser Benutzer konnte telefonieren und angerufen werden. Maßgeblich war neben dem SfB-Homeserver natürlich auch der Dialplan, die Voice-Routen  mit PSTN-Usages und ein geeigneter SIP-Trunk.

Mit dem Wechsel in die Cloud Richtung Teams wurde ADSync und SfB Hybrid-Mode eingerichtet und dann der Benutzer in die Cloud verschoben. Im Hintergrund hat aber ADSync schon diese Informationen in die Cloud repliziert. Auch dazu habe ich auf ADSync mit Skype für Business schon einiges geschrieben. Daher fasse ich mich hier kurz und zeige nur, was ADSync für meinen fctest1 in die Cloud schreibt.

Wenn ich mit den Benutzer in der Cloud angeschaut habe, war der Benutzer schon dort angelegt aber noch etwas uneinheitlich.

PS C:\> get-csonlineuser fctest1 | fl *enab*,*lineuri,*time*,*dirsync*

AccountEnabled                   : True
EnterpriseVoiceEnabled           : False
IsSipEnabled                     : False
OnPremEnterpriseVoiceEnabled     : True
OnPremSIPEnabled                 : True
TeamsUpgradeNotificationsEnabled : False
UserDirSyncEnabled               : True
LineUri                          :
OnPremLineUri                    : tel:+495257123
LastSyncTimeStamp                : 08.06.2022 11:33:41
SoftDeletionTimeStamp            :
LastProvisionTimeStamps          : {[UserAuthoredProps, 2022-03-27T22:03:35.4212489+00:00]}
LastPublishTimeStamps            : {[ProvisionedPlanPublishAuthoredProps, 2022-03-27T21:48:36.0708285+00:00]}
UserDirSyncEnabled               : True

Das ist bei mir gewollt, da der Benutzer in der Cloud noch keine Lizenz hatte. Es ist aber gut zu sehen, dass die OnPremLineUri gefüllt ist aber die LineURI nicht. Sie sehen aber auch, dass "OnPremEnterpriseVoiceEnabled:$true" aber "EnterpriseVoiceEnabled:$false" ist. Der Werte "EnterpriseVoiceEnabled" wird wohl nicht durch ADSync abgeglichen. Das ist aber auch kein Wunder, wenn ein Aktivieren funktioniert mangels Lizenz nicht.

PS C:\> Set-CsPhoneNumberAssignment -Identity fctest1@uclabor.de -EnterpriseVoiceEnabled $true
Set-CsPhoneNumberAssignment_Set: C:\Users\adm-fcarius\Documents\PowerShell\Modules\MicrosoftTeams\4.4.1\custom\PsExt\Merged_custom_PsExt.ps1:5935
Line |
5935 |          Microsoft.Teams.ConfigAPI.Cmdlets.internal\Set-CsPhoneNumberA …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The user 'db4892f9-dbc1-4a2d-bdb2-48fc04c7b4ff' does not have required licenses to set attributes

Erst nachdem ich die Lizenz zugewiesen und etwas gewartet habe, konnte ich den Benutzer für "EnterpriseVoiceEnabled:$true" in der Cloud aktivieren. Interessanterweise wird durch den Prozess das Feld "LineUri" gefüllt.

PS C:\> get-csonlineuser fctest1 | fl *enab*,*lineuri,*time*,*dirsync*

AccountEnabled                   : True
EnterpriseVoiceEnabled           : True
IsSipEnabled                     : True
OnPremEnterpriseVoiceEnabled     : True
OnPremSIPEnabled                 : True
TeamsUpgradeNotificationsEnabled : False
UserDirSyncEnabled               : True
LineUri                          : tel:+495257123
OnPremLineUri                    : tel:+495257123
LastSyncTimeStamp                : 08.06.2022 14:45:51
SoftDeletionTimeStamp            :
LastProvisionTimeStamps          : {[UserAuthoredProps, 2022-06-08T14:45:17.3444633+00:00]}
LastPublishTimeStamps            : {[ProvisionedPlanPublishAuthoredProps, 2022-06-08T14:25:24.2197851+00:00]}
UserDirSyncEnabled               : True

Der Versuch nun diesen Wert manuell zu überschreiben, funktioniert nicht:

PS C:\> Set-CsPhoneNumberAssignment -Identity fctest1@uclabor.de -PhoneNumber "+495257456" -PhoneNumberType DirectRouting

Set-CsPhoneNumberAssignment_Set: C:\Users\adm-fcarius\Documents\PowerShell\Modules\MicrosoftTeams\4.4.1\custom\PsExt\Merged_custom_PsExt.ps1:5935
Line |
5935 |          Microsoft.Teams.ConfigAPI.Cmdlets.internal\Set-CsPhoneNumberA …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The user 'db4892f9-dbc1-4a2d-bdb2-48fc04c7b4ff' already has a telephone number set in the On-Premises
     | Active Directory and synchronized to the cloud. To manage this user's telephone number in the cloud,
     | first clear the phone number in the On-Premises directory and synchronize to Active Directory.

Als Flussdiagramm sieht das dann so aus:

Solange die Rufnummer im lokalen AD im Feld "msRTCSIP-line steht, kann ich in der Cloud nichts verwaltet

Besitz übergeben

Ich muss daher zuerst das Feld im lokalen SfB entfernen, damit ich es in der Cloud dann zuweisen kann. Das ist der von Microsoft empfohlene Weg und wird beschrieben:

Allerdings sollten Sie den Artikel komplett lesen, denn es ist mehr als nur ein Feld zu leeren.

Diese Änderung bewirkt auch auch ein "Wipe" beider Felder in der Cloud.

In der Folge kann der Anwender nicht mehr telefonieren oder angerufen werden, bis Sie den "Fehler" korrigiert haben.

PS C:\> get-csonlineuser fctest1 | fl *enab*,*lineuri,*time*,*dirsync*

AccountEnabled                   : True
EnterpriseVoiceEnabled           : True
IsSipEnabled                     : True
OnPremEnterpriseVoiceEnabled     : False
OnPremSIPEnabled                 : True
TeamsUpgradeNotificationsEnabled : False
UserDirSyncEnabled               : True
LineUri                          :
OnPremLineUri                    :
LastSyncTimeStamp                : 08.06.2022 17:57:36
SoftDeletionTimeStamp            :
LastProvisionTimeStamps          : {[UserAuthoredProps, 2022-06-08T17:56:54.9569443+00:00]}
LastPublishTimeStamps            : {[ProvisionedPlanPublishAuthoredProps, 2022-06-08T14:25:24.2197851+00:00]}
UserDirSyncEnabled               : True

Sie müssen hier also nach dem Update durch ADSync zügig die LineURI nachpflegen, was nun aber geht, da das Feld nun "leer" ist.

PS C:\> Set-CsPhoneNumberAssignment -Identity fctest1@uclabor.de -PhoneNumber "+495257456" -PhoneNumberType directrouting
PS C:\> Get-CSOnlineUser fctest1 | fl *enab*,*lineuri,*time*,*dirsync*

AccountEnabled                   : True
EnterpriseVoiceEnabled           : True
IsSipEnabled                     : True
OnPremEnterpriseVoiceEnabled     : False
OnPremSIPEnabled                 : True
TeamsUpgradeNotificationsEnabled : False
UserDirSyncEnabled               : True
LineUri                          : tel:+495257456
OnPremLineUri                    :
LastSyncTimeStamp                : 08.06.2022 17:57:36
SoftDeletionTimeStamp            :
LastProvisionTimeStamps          : {[UserAuthoredProps, 2022-06-08T18:09:46.4478576+00:00]}
LastPublishTimeStamps            : {[ProvisionedPlanPublishAuthoredProps, 2022-06-08T14:25:24.2197851+00:00]}
UserDirSyncEnabled               : True

ADSync blockiert also nicht das Property generell, sondern Teams verhindert das Schreiben der LineUri, solange in OnPremLineUri etwas steht. In der Teams PowerShell habe ich eine Erläuterung zu den Hintergründen gefunden:

In Teams PowerShell Module version 3.0.0 and later, the OnPremLineURI attribute refers only to the LineURI that's set via On-Prem AD. Previously, OnPremLineURI also referred to Direct Routing numbers that were assigned to users via the Set-CsUser cmdlet. OnPremLineUriManuallySet is now deprecated as OnPremLineURI is representative of the On-Prem assignment. Also, Direct Routing numbers are available in the LineURI attribute. You can distinguish Direct Routing Numbers from Calling Plan Numbers by looking at the FeatureTypes attribute.
Quelle: https://docs.microsoft.com/en-us/powershell/module/skype/get-csonlineuser

Migration in die Cloud

Das bedeutet nun natürlich erhöhte Aufmerksamkeit bei der Umstellung von Teams Telefonie-Benutzern in die Cloud beim Rückbau des lokalen Skype for Business Topologie mit abschließenden Disable-CSUser für alle AD-Objekte zum Rückbau der SfB Topology.

Die Herausforderung besteht nun darin, den Export der Daten, den Disable-CSUser, ADSync und die Nachpflege in Teams möglichst kurz zu halten.

Microsoft beschreibt das auf der folgenden Seite sehr gut, dass Sie entweder das Feld "msRTCIP-Line" weiterhin On-Premises pflegen und per ADSync in die Cloud replizieren oder sie räumen On-Premises die Einträge weg und reparieren Sie in der Cloud.

Speziell in größeren Umgebungen Vor dem Cleanup sollten Sie aber erst einmal ihren beiden Systemen, AD und Online, auf die Finger schauen, was Sie denn schon alles wissen und die Konsistent das alles ist.

Damit sollten Sie einen Überblick bekommen, welche Objekte vielleicht schon vorher "korrupt" sind oder noch nicht die passende Lizenz für Teams Telefonie haben. Microsoft beschreibt selbst, wie man die Rufnummer von dem On-Premises Server bezieht. Wenn Sie aber heute schon ADSync nutzen, dann wird der Inhalt von "msRTCSIP-Line" in "OnPremLineURI" repliziert, was aber aber in der Teams PowerShell 4.4.0 nicht auslesbar ist ("Not yet supported", siehe Get-CSOnlineUser). Aber die gleiche Nummer steht auch im Feld "LineURI", welches ausgelesen werden kann. Daher ist es aus meiner Sicht auch möglich indirekt die Rufnummern aller Personen zu exportieren.

get-csonlineuser `
| select sipaddress,enterprisevoiceenabled,lineuri,onpremlineuri,`
         dialplan,TenantDialPlan,TeamsUpgradeEffectiveMode,`
         @{name="EV";expression={$_.AssignedPlan.Capability.contains("MCOEV")}} `
| export-csv cstelefonie.csv -notypeinformation

Prüfen Sie, dass alle Benutzer mit Telefonie auch auf "EnterpriseVoiceEnabked:$true" stehen, einen Dialplan haben und TeamsOnly als TeamsUpgradeEffectiveMode nutzen und eine Phone System-Lizenz (MCOEV) haben. Nach der "On-Premises"-Umstellung mit dem finalen "Disabled-CSUser" im lokalen AD sind natürlich die Rufnummern entfernt. Dann ist es schon sehr einfach, diese Werte wieder anzuwenden.

Import-CSV cstelefonie.csv | foreach { `
   Set-CsPhoneNumberAssignment `
      -Identity $_.sipaddress `
      -PhoneNumber $_.lineuri.Replace("tel:","") `
      -PhoneNumberType Directrouting
}

Hinweis:
Sie sollten die Rufnummer mit "Set-CsPhoneNumberAssignment" setzen. Früher war "Set-CSUser" ebenfalls möglich aber ist seit ca. Jun 2022 nicht mehr möglich. Set-CsPhoneNumberAssignment braucht aber deutlich länger. Ich weiss nicht, ob es nur an der API liegt oder das Commandlet auf eine Bestätigung wartet.

Schreibschutz

Ich habe natürlich ausprobiert, was nach der Umstellung passiert Ich habe den Benutzer mit Teams Enterprise Voice versehen und das AD-Feld "msRTCSIP-Line" war leer. Ich habe dann "durch einen Fehler" das Feld im lokalen AD gefüllt. Beim nächsten ADSync-Lauf wurde die Rufnummer aus dem lokalen AD wieder in das Feld "OnPremLineUri" in der Cloud geschrieben UND in das Feld "LineUri" in der Cloud übertragen. Eine manuell dort konfigurierte abweichende Rufnummer wurde ohne Rückfrage überschrieben!

Wenn dann im lokalen AD die Rufnummer wieder gelöscht wurde, hatte der Anwender in Teams gar keine Rufnummer mehr., d.h. Teams hat nicht den alten Zustand wieder hergestellt.

Ich finde die "Lösung", die Microsoft hier vorgibt, sehr unglücklich. Wenn ich mit OnPremLineUri und LineUri schon zwei Felder in der Cloud habe, dann sollte ich diese auch unabhängig voneinander nutzen können, d.h. dass die LineURI die OnPremLineURI einfach überstimmt, wenn Sie manuell gesetzt wird.

Achtung:
Aus meiner Sicht ist es höchst gefährlich, die Replikation der msRTC-Felder mit ADSync aktiv zu lassen, wenn Sie lokal keinen SfB Server mehr betreiben aber vielleicht alte Provisioning-Skripte weiter in das AD schreiben.

Daher rate ich dazu, im ADSync die Replikation dieser msRTC-Felder zu deaktivieren. Anstatt nun aber im "Regel-Editor" etwas zu ändern, sollten Sie die ADSync Konfiguration über die "Azure AD app and attribute filtering" anpassen. Hier können Sie komplette Apps oder auch nur einzelne Felder ausschließen:

Diese Einstellung sorgt dann dafür, dass die entsprechenden "Outbound"-Regeln in den Synchronisierungsregeln entfernt werden:

Achtung
Durch diese Änderung schreibt und liest ADSync die Felder nicht mehr. Das bedeutet aber auch, dass Sie in der Cloud z.B. die "OnPremLineURI" damit nicht mehr löschen können!

Diese Änderung sollten Sie erst aktivieren, nachdem wirklich alle jemand von ADSync in die Cloud geschriebenen Felder in der Cloud auch gelöscht wurde.

Schade, dass ADSync hier zumindest beim "FullSync" die früher einmal vorgenommen Änderungen nicht mehr rückgängig macht.

Weitere Links