Get-CsPhoneNumber

Dass Lync in der Oberliga der Kommunikationsplattformen mitspielt, ist nicht mehr zu bestreiten. Die Verwaltung der Teilnehmer per PowerShell als auch per Webbrowser per Silverlight geht den meisten Administratoren recht einfach von den Fingern. Aber eine komplette Liste der Telefonnummern lässt sich mit Lync nicht einfach erstellen.

Dieses Skript nutzt NICHT die Lync Commandlets, um nacheinander alle verschiedenen Objekte zu ermitteln, sondern liest "RAW" direkt im Active Directory und findet damit auch Objekte, die vielleicht nicht ganz korrekt konfiguriert sind.

Zwar werden die wenigsten Administratoren noch ein gedrucktes Firmentelefonbuch veröffentlichen, aber es kann bei der Rufnummernplanung und zur Verhinderung von doppelten Vergaben, die dann beide Teilnehmer unerreichbar macht, hilfreich sein. Zwar versuchen die Commandlets schon doppelte Nummern zu erkennen, aber Sie übersehen dabei doch auch Endpunkte und die AD-Replikation kann auch ein falsches Spiel treiben. Eine Liste und Validierung der Einträge ist daher wünschenswert. Genau das macht dieses PowerShell-Script.

Diese Auswertung ist wichtig, da leider Lync nicht alle Fälle von doppelt vergebenen Nummern bei der Konfiguration erkennt. So kann ein Benutzer die gleiche TelURI bekommen wie ein CommonAreaPhone. Lync warnt nicht nur können dann beide nicht mehr per Rufnummer angerufen werden.

Objekte

In Lync gibt es eine ganze Menge von Objekten, die eine Telefonnummer haben können. Seit Lync kann ein Anwender sogar eine zweite "private" Nummer haben, die entsprechend mit berücksichtig werden muss. Folgende Objekte konnte ich bislang mit einer Rufnummer identifizieren:

Object Partition Beschreibung

Benutzer Telefon

Domain

Ein normaler Lync Anwender mit seiner primären Nummer im Feld msRTCSIP-Line

Benutzer Private Line

Domain

Ein normaler Lync Anwender mit seiner privaten Nummer im Feld msRTCSIP-PrivateLine

Responsegroup

Config

Wer eine IVR-Lösung auf Basis des Lync Response Group Service bereitstellt, muss diesen Workflows auch eine Rufnummer geben.

Callpark

Config

Auch die "Call Park-Parkschleifen" für das temporäre Parken von Anrufern belegen Nummern.

Exchange AA

Domain

Wer Exchange UM einsetzt, der wird mit Lync auch die Objekte für den AutoAttendant anlegen, um Anrufer eine einfache IVR-Anwendung zu eröffnen.

Exchange SA

Domain

Der Exchange Subscriber Access ist die Nummer, unter der Anwender selbst auf ihr Postfach per Telefon zugreifen können.

Conference Dialin

Config

Für die Einwahl in Lync Konferenzen muss mindestens eine Nummer vorgehalten werden.

AnalogPhone

Domain

Die seit Lync möglichen "Analoge Telefone", die an Gateways angebunden sind, werden ebenfalls in Lync definiert

CommonAreaPhone

Domain

Der zweite neue Telefonapparatetyp ist das DCommon Area Phone

Audio Test Service

Configuration

Normalerweise hat der Audio Test Service keine Rufnummer. Wer aber z.B. sein Gateway "testen" möchte, kann dies auch aus dem Telefonnetz tun.

Unassigned Numer

Configuration

Wenn keine der vorgenannten Nummern "matched", dann gibt es immer noch die "unassignedNumner"-Konfiguration, mit der Rufnummernbereiche bedient werden können, z.B. mit einer Ansage oder als Weiterleitung auf eine andere Nummer.

Sie sehen also eine ganze Menge von möglichen Endpunkten. Und ich bin nicht mal sicher, ob ich damit alle habe.

Abfrage

Auch wenn in Lync eigentlich "fast" alle Objekte per PowerShell abzufragen sind, habe ich mich doch für eine einfache AD-Abfrage ohne Lync Module entschieden, da damit die Auswertung auf jeden PC und mit jedem Benutzer ausgeführt werden kann, der den globalen Katalog lesen darf. für eine Suche nutze ich einfach folgenden LDAP-String:

(|(msRTCSIP-Line=*)(msRTCSIP-PrivateLine=*))

Diesen Filter können Sie z.B. mit CSVDE oder LDIF direkt verwenden:

REM bitte als Server einen GC in ihrer Umgebung verwenden
csvde -s gcname:3268 -r "(|(msRTCSIP-Line=*)(msRTCSIP-PrivateLine=*))" -f test.csv -l msRTCSIP-PrivateLine,msRTCSIP-Line

Natürlich muss ich die Ergebnisse dann selbst entsprechend aufbereiten und die einzelnen Felder auswerten, z.B.:

Feldname Beschreibung Inhalt

msrtcsip-optionflags

Enthält binäre codiert die Funktionalität

PConly   0xxx0xx0xxxx
RCC      0xxx0xx1xxxx
EV       0xxx1xx0xxxx
noAV     1xxx0xx0xxxx
RCCOnly  1xxx0xx1xxxx

msrtcsip-ownerurn

Klassifiziert den Dienst genauer

CommonAreaPhone        urn:device:commonareaphone
AnalogFax              urn:device:analogfax
ResponseGroup          urn:application:RGS
ConferenceDialin       urn:application:Caa
ConferenceAnnouncement urn:application:Cas
Audio Test Service     urn:application:testbot
CallPark               urn:application:Cps

otherIpPhone

Anhand des Inhalts in diesem Feld lassen sich die Exchange UM-Kontakte erkennen.

Enthält "opaque=app:exum". Zusätzlich muss noch msrtcsip-optionflags ausgewertet werden. Wenn "-band 1024" zutrifft, dann ist es ein AutoAttendant

Überprüfung von Feldern

Mit einer stumpfen Ausgabe der Inhalte wäre ich nun schon fast fertig. Aber wenn ich die Daten eh schon habe, dann möchte ich auch ein paar Checks durchführen.

  • Rufnummer ohne EV
    Wer eine Rufnummer hat, aber nicht für "Enterprise Voice" aktiviert ist, ist wahrscheinlich falsch konfiguriert
  • Gültige Nummern
    Wenn dem Script ein "REGEX-"Ausdruck übergeben wird, der einen korrekten Nummernbereich benennt, dann kann auch dies geprüft werden. Natürlich wäre es sogar noch interessant eine RegularExpress zu definieren, um "gültige" Nummern zu erkennen.

Achtung: Im Skript ist meine "Net at Work-Nummer" als Muster vordefiniert. Übergeben Sie daher ihren Ausdruck per Parameter oder ändern Sie das Skript ab. Vergessen Sie auch nicht das "tel:" davor.

  • Dubletten und Extensioncheck
    Die Erkennung doppelter Rufnummern ist natürlich naheliegend. Wobei das nicht ohne einen Extensioncheck erfolgen kann. Eine Rufnummer kann ja ohne Extension als "Tel:+495251304600" geschrieben werden, Wer aber auch Lync Phones per Extension anmelden will, wird eher "Tel:+495251304600;ext=600" schreiben, so dass die Extension den letzten Stellen der Rufnummer entspricht. Es gibt aber auch Länder wie die USA, bei denen alle die gleiche "Stammnummer" haben und sich die Extension unterscheidet. Die muss dann aber auch eindeutig sein.

Weitere Überprüfungen sind natürlich denkbar. Ich hatte anfangs z.B. auch eine Prüfung auf die Eindeutigkeit der SIP-Adresse eingebaut. da ich aber nur nach Objekten mit "Rufnummern" suche, wäre das Ergebnis nicht komplett.

Ausgabe

Am einfachsten ist die Ausgabe als CSV-Datei, da diese sehr schnell in Excel oder anderen Werkzeugen weiter verarbeitet werden kann und selbst ein SORT und WHERE ist mit PowerShell trivial. Die Ausgabe erfolgt demnach auf die Pipeline und kann von ihnen per "Export-CSV" weiter gegeben werden. Die die Ausgabe mit GM. damit sie die einzelnen Felder shene

PS C:\> .\get-csphonenumber.ps1 | gm
loading Lync Recipients
Total objects found: xx
writing AD-Search Result to XML
write  Lync Recipients to CSV

   TypeName: System.Management.Automation.PSCustomObject

Name         MemberType   Definition
----         ----------   ----------
Equals       Method       bool Equals(System.Object obj)
GetHashCode  Method       int GetHashCode()
GetType      Method       type GetType()
ToString     Method       string ToString()
adspath      NoteProperty System.String adspath=GC://netatwork.de/CN=Carius\, Frank,OU=Technik,OU=Abteilung,DC=netatwork,DC=de
AudioVideo   NoteProperty System.String AudioVideo=EV
Displayname  NoteProperty System.String Displayname=Carius, Frank
Extension    NoteProperty System.String Extension=613
Federation   NoteProperty System.Boolean Federation=True
Name         NoteProperty System.String Name=Carius, Frank
RCCUri       NoteProperty System.String RCCUri=sip:613@csta.netatwork.de
Resforst     NoteProperty System.Boolean Resforst=False
RTCenabled   NoteProperty System.DirectoryServices.ResultPropertyValueCollection RTCenabled=System.DirectoryServices.ResultPro...
SIPUri       NoteProperty System.String SIPUri=sip:frank.carius@netatwork.de
Status       NoteProperty System.String Status=OK
Statusdetail NoteProperty System.String Statusdetail=OK
TELUri       NoteProperty System.String TELUri=tel:+495251304613;ext=613
Type         NoteProperty System.String Type=User Public

Für eventuelle Fehler werden die Ergebnisse der AD-Suche und der Liste in XML/CSV-Dateien exportiert. Die beiden Zeilen müssen Sie auskommen tieren, wenn Sie dies nicht möchten.

$colresults | export-clixml '.\adsearchresult.xml'
$list | export-csv .\numbers.csv

Die Dateien helfen mir aber bei einer etwaigen Fehlersuche oder wenn Ergebnisse nicht

PS C:\> .\get-csphonenumber.ps1 | `
  Export-Csv .\lyncphone.20120408.csv -Delimiter ";" -notypeinformation

Ebenso können Sie die Daten dann natürlich auch filtern.

Download

Für die Ausführung des Skripts benötigen Sie einzige eine PowerShell auf ihrem PC und "Lese-Rechte" im Active Directory. Genau genommen erfüllen diese Voraussetzungen alle Domänen Benutzer auf einem halbwegs aktuellen Betriebssystem.

Daher werde ich das Skript nicht öffentlich zur Verfügung stellen, um es nicht allzu einfach zu machen, eine Liste der Rufnummern und Berechtigungen zu erstellen.

Das Skript ist aktuell noch nicht öffentlich. Da ich die Daten aus den LDAP-Feldern anstatt per Lync PowerShell auslese, möchte ich erst einige Daten aus produktiven Umgebungen haben, um die Ergebnisse zu bestätigen.

Ausgehend von dem Feedback dieser Personen werde ich überlegen, wie ich das Skript sinnvoll verfügbar machen kann.

Weiterentwicklung

Wenn man eh schon filtern kann, dann könnte das Skript zukünftig ja auch alle SIP-aktivierten Konten heranholen und als Liste ausgeben. Dann wären auch noch umfangreichere Prüfungen möglich.

Weitere Links