PRTG – Office 365 Lizenzen im Blick

Nachdem das letzte PRTG Skript zur Überwachung der Office 365 Dienste anscheinend doch ganz gut angekommen ist, habe ich eine Anfrage erhalten, ob ich nicht auch etwas schreiben könne, mit dem man die Lizenzen in Office 365 überwachen kann (später haben wir dann noch den DirSync Status mit dazugenommen). Na ja, das hat dann nicht so lange gedauert, bis es mich in den Fingern juckte … der Anfang war relativ leicht, allerdings hat PRTG dann für etwas Hirn-Akrobatik gesorgt, dazu aber später mehr …Deshalb das Wichtigste zuerst: Das funktionierende Skript. Nach einigem Testen und Verfeinern (Danke für die Idee und das Feedback, Ollie), habe ich das fertige Skript auf GitHub veröffentlicht:

PRTG-O365Licensing auf Github.

Die Installation

Einfach die aktuelle Version des Skripts aus GitHub (hier) herunterladen und in den Ordner „Custom Sensors\EXEXML“ ablegen.

Da sich das Skript per PowerShell an Office 365 anmelden muss, müssen auf der Probe noch folgende Komponenten installiert werden:

  1. Microsoft Online Services-Sign in assistant (Download)
  2. Azure Active Directory-Module for Windows PowerShell (Download)

Wichtig: PRTG startet PowerShell Skripte in der 32-Bit Umgebung, damit muss die Execution Policy der PowerShell 32-Bit min. auf RemoteSigned umgestellt werden. Da aber das Azure Active Directory Modul nur als 64-Bit Version verfügbar ist (und das Skript automatisch auf 64-Bit umschaltet), muss in der PowerShell 64-Bit auch die Execution Policy geändert werden.

Update: Windows markiert heruntergeladene Dateien aus dem Internet als potentiell unsicher. Dadurch wird die Ausführung in PowerShell erst einmal unterbunden. Das Skript muss also zuvor entweder per PowerShell oder über die Eigenschaften der Datei im Explorer freigeschaltet werden.

Die Konfiguration

office365licenses_sensordetailsDas Skript benötigt für die Abfrage der entsprechenden Informationen ein Login zum Office 365 Tenant (administrativ). Da ich persönlich ungerne Login Daten im Klartext hinterlege, habe ich diese im übergeordneten Gerät (in PRTG) als Linux Benutzername und Passwort hinterlegt. Somit kann das Skript dann mit folgenden Parametern gestartet werden:

Da das Skript schon etwas Last auf die Probe bringt, sollte man den Scanning Interval auf 5 Minuten oder höher stellen.

Das Ergebnis

office365licenses_outputNachdem der Sensor den ersten Durchlauf absolviert hat, sollte eine Ausgabe ähnlich der nebenstehenden erfolgen. Wahrscheinlich wollt ihr die Schwellwerte für die verschiedenen Kanäle noch an eure Ansprüche anpassen, aber grundsätzlich sollte das schon mal das Wichtigste abdecken. Es werden folgende Informationen angezeigt:

  • Time since last DirSync: Zeit in Stunden seit dem letzten DirSync Lauf (falls DirSync eingesetzt wird)
  • Time since last PasswordSync: Zeit in Stunden seit der letzten Passwort Synchronisation (falls PasswordSync eingesetzt wird)
  • <Tenant>:<Lizenz> – Active Licenses: Gesamtzahl der Lizenzen
  • <Tenant>:<Lizenz> – Available Licenses: Anzahl der verfügbaren Lizenzen
  • <Tenant>:<Lizenz> – Consumed Licenses: Anzahl der benutzten Lizenzen
  • <Tenant>:<Lizenz> – Warning Licenses: Anzahl der Lizenzen mit Warnungen oder Hinweisen

Je nach dem, welche Berechtigungen der für die Anmeldung an Office 365 benutzte Account hat, kann es sein, dass mehrere Office 365 Tenants abgefragt werden können. Außerdem ist es möglich, dass mehrere Lizenzverträge innerhalb eines Tenants auftauchen. In jedem dieser Fälle erscheinen dann zusätzliche Lizenzaufstellungen für all diese Kombinationen. Werden zu viele Lizenzen angezeigt, kann man dies noch einschränken.

Das Feintuning

windows-powershell_showskusWenn die Abfrage also Lizenzverträge anzeigt, die mich nicht interessieren, oder aber für jeden Vertrag ein eigener Sensor erstellt werden soll, kann das Skript mit weiteren Parametern aufgerufen werden:

  • -IncludeSku „Sku1″,“Sku2“,…: Nur die aufgezählten SKUs (also <Tenant>:<Lizenz>) werden ausgelesen
  • -ExcludeSku „Sku1″,“Sku2“,…: Die angegebenen SKUs werden nicht ausgelesen
  • -ShowMySkus: Ist nur für die manuelle Ausführung in PowerShell gedacht: Gibt eine Liste der SKUs in lesbarer Form aus. Diese kann für das Füllen der Parameter IncludeSku und ExcludeSku verwendet werden

Beispiele:

Die Herausforderung

Das Schwierigste am Skript war nicht die Abfrage der relevanten Daten aus Office 365 oder die Aufbereitung für PRTG, sondern ein „hausgemachtes“ Problem von PRTG: Der Probe Prozess von PRTG läuft immer unter 32-Bit, auch wenn das Betriebssystem in 64 Bit installiert ist und der ausführende Computer mehr als 6 GB RAM hat (was beim Core dafür sorgt, dass die 64-Bit Version installiert wird). Nun gibt es das Azure Active Directory Modul für PowerShell nicht als 32-Bit Version und somit kann die 32-Bit PowerShell, die vom PRTG Probe Prozess gestartet wird, auch nicht auf das Modul zugreifen.

Somit muss das Skript zum einen erkennen, dass es in einer 32-Bit Umgebung läuft (einfach) und dann dafür sorgen, dass es sich selbst in einer 64-Bit Umgebung neu aufruft (WTF?). Ok, klingt einfach (die Lösung ist dann auch einfach), aber wie? Ich habe wirklich einige Zeit mit meinem Freund Google verbracht, um den richtigen Weg zu finden. Da ich euch das ersparen möchte, hier die Essenz:

Wird auf einem 64-Bit System ein Prozess gestartet, werden verschiedene Systemordner von Windows automatisch umgeleitet (je nach „Bit-igkeite“ des Prozesses), um es den Programmen (oder besser den Programmierern) „einfach“ zu machen, weiterhin zu funktionieren, auch ohne genau zu wissen, auf welche DLLs sie zugreifen müssen (32- oder 64-Bit).

Systemordner 32-Bit Prozess 64-Bit Prozess
%windir%\System32 32-Bit Versionen der Dateien 64-Bit Versionen der Dateien
%windir%\SysWOW64 nicht verfügbar 32-Bit Versionen der Dateien
%windir%\Sysnative 64-Bit Versionen der Dateien nicht verfügbar

administrator_-windows-powershell-x86Die Verzeichnisse System32 und SysWOW64 kennt man ja aus der Explorer Ansicht, das Verzeichnis Sysnative ist mir so aber noch nie begegnet. Selbst in einer 32-Bit PowerShell ist es nicht sichtbar, allerdings kann darauf zugegriffen werden. Da es nur für einen 32-Bit Prozess verfügbar ist und darin dann die 64-Bit Systemdateien enthalten sind, kann darüber auch eine 64-Bit PowerShell gestartet werden. Und genau darin liegt der Trick, aus einer 32-Bit PowerShell eine 64-Bit PowerShell zu machen. Der Code dazu sieht dann (in meinem Fall) so aus:

Hier ist Zeile 15 eigentlich die interessanteste. Das Skript ruft also eine 64-Bit PowerShell auf und übergibt dorthin den vollständigen Pfad zur eigenen Datei und die (davor mühsam zusammengeklöppelten) Parameter (die zu allem Überfluss auch noch Arrays enthalten können).

Das Fazit

Funktioniert … und wieder was gelernt. Wenn ihr Fehler findet oder Verbesserungsvorschläge habt, benutzt bitte gerne den Issue Tracker des Github Projekts. Ich freue mich natürlich auch immer über Feedback, wenn ihr das Tools einsetzt. Gerne könnt ihr es auch wie Ollie machen und mich mit guten Ideen für neue PRTG Sensoren bombardieren – wenn ich Zeit habe und das Thema eine Lücke auch für andere füllen kann, setze ich mich (sehr wahrscheinlich) dran. Also: Benutzt die Kommentarfunktion!

13 Gedanken zu „PRTG – Office 365 Lizenzen im Blick

  1. Frank Antworten

    Hallo Marc

    Vielen Dank fürs Teilen der Skripte und die tolle Anleitung. Ergänzend möchte ich noch erwähnen, dass ich auf Windows Server 2012R2 zusätzlich zu Deiner Anleitung noch folgende Powershell Kommandos absetzen musste, um die Berechtigungsfehler beim Ausführen der Skripte zu umgehen:

    Unblock-File -Path „C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-Office365Status.ps1“

    Unblock-File -Path „C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-PRTGO365Licenses.ps1“

    • Marc Autor des BeitragsAntworten

      Hallo Frank,

      danke für die Ergänzung. Da das Skript von einer Website heruntergeladen wurde, markiert sie Windows erst einmal als „gefährlich“. Mit den beschriebenen Befehlen kannst du diese Blockierung aufheben (oder durch Rechtsklick und Anklicken der entsprechenden Option in den Eigenschaften). Ich habe eine entsprechende Anmerkung in den Artikel übernommen.

      Gruß,
      Marc

  2. Alexander Grimm Antworten

    Hallo Marc,
    auch von mir erst einmal vielen Dank für das Skript. Leider bekomme ich immer XML Fehler, dass es nicht im richtigen Format wäre (XML: The returned XML does not match the expected schema. (code: PE233) — JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)). Habe es nun zweimal neu von GitHub geholt und komplett durchgezogen, aber die Meldung bleibt.

    Hast du da eine Tipp, wo ich Fehlersuche betreiben kann? Der User ist ein global admin und es kommt auch kein Tendent Fehler.

    Besten Dank
    Alexander

    • Marc Autor des BeitragsAntworten

      Hallo Alexander,
      der Fehler bedeutet erst mal nur, dass das Skript wahrscheinlich einen PowerShell Fehler erzeugt hat und damit die Ausgabe im XML Format nicht mehr korrekt war. Am einfachsten findest du heraus, was das Problem ist, indem du in den Sensoreinstellung „Write EXE result to disk“ aktivierst. Damit wird die Ausgabe des Sensors in die entsprechende Datei auf der Probe gespeichert („Result of Sensor [ID].txt“ im Verzeichnis „Logs (Sensors)“). Wenn du dir diese Datei mal anschaust, wirst du wahrscheinlich einen PowerShell Fehler sehen, anhand dessen du erkennen kannst, was das Problem ist.

      Üblicherweise passiert das etwa, wenn die heruntergeladene Datei noch blockiert ist (siehe „Unblock-File“ oben) oder die Execution Policy noch nicht korrekt ist (auch im Artikel beschrieben). Wenn du nicht weiter kommst, Poste einfach mal die Fehlermeldung, vielleicht bekommen wir es gemeinsam hin.

      Gruß,
      Marc

  3. Alexander Antworten

    Hallo Marc,

    erst mal Entschuldigung, dass ich erst jetzt wieder schreibe, aber hatte „lange frei“ und konnte daher nicht weitermachen.

    Jetzt habe ich wieder einen Versuch gestartet und alles von vorne neu gemacht (neuer Sensor, User und sowas) und bekomme im PRTG wieder den Fehler „XML: The returned XML does not match the expected schema. (code: PE233) — JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)“.

    Habe auch mal die Fehlerdatei schreiben lassen:
    …\EXEXML\Get-PRTGO365Licenses.ps1 : A parameter cannot be found that
    matches parameter name ‚O365User‘.At line:1 char:231
    + … tor\custom sensors\EXEXML\Get-PRTGO365Licenses.ps1′ -O365User s-group …
    + ~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [Get-PRTGO365Licenses.ps1],
    ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Get-PRTGO365Licenses.ps1

    Kann das evtl. an einer zu alten Server- oder PowerShellversion liegen? Lokal auf dem Core läuft es einwandfrei. Nur bei der Ausführung durch PRTG kommt der Fehler. Installiert ist das WMF 1-5, Unblock ist gemacht und ExecutionPolicy ebenso.

    Besten Dank
    Alexander

    • Marc Autor des BeitragsAntworten

      Hallo Alexander,
      die Meldung kann ich mir so jetzt nicht erklären. Allerdings habe ich gesehen, dass du den Benutzernamen direkt in den Skriptaufruf geschrieben hast (ist das so?). Da der Benutzername anscheinend einen Bindestrich enthält, könnte es sein, dass PowerShell versucht, das als Operator „Minus“ zu interpretieren. Kannst du bitte mal versuchen, Benutzername und Passwort entweder in Anführungszeichen zu setzen, oder wie im Artikel beschrieben, etwa in die Linux Anmeldedaten des Sensors zu speichern?

      Wenn es das nicht ist, wird es schwierig zu troubleshooten, ohne direkt draufschauen zu können … 😉

      Gruß,
      Marc

  4. René Antworten

    Hallo zusammen,

    Ein tolles Skript.
    Ich habe leider nur das Problem das ich bei IncludeSKU und mehre auswähle via „Tenant:SKU1″,“Tenant:SKU2“ immer den Error SKUs not found im PRTG bekomme.
    In der Commandline gibt er es korrekt aus.
    Woran kann das noch liegen?

    • Marc Autor des BeitragsAntworten

      Hallo René,
      ich könnte mir vorstellen, dass es ein Problem mit den Anführungszeichen ist. In meinen anderen PRTG Skripten hat es bisher immer funktioniert, mit einfachen Anführungszeichen (‚) zu arbeiten. Vielleicht testest du das mal?

      • René Antworten

        Ich habe schon alle erdenklichen Variationen probiert: ‚,“,`,´
        Echt eigenartig im CLI geht es wunderbar egal mit welchen.

        • René Antworten

          hiermit bekomme ich jetzt nur immer den ersten SKU geliefert. Der zweite taucht nicht auf:
          -IncludeSku „xxx:PROJECTESSENTIALS“,“xxx:PROJECTPROFESSIONAL“

          • Marc Autor des Beitrags

            Hallo Rene,
            ich hatte jetzt gerade etwas Zeit, mir das mal genauer anzuschauen. Es sieht mir danach aus, dass PRTG bei der Weitergabe der Parameter an das Powershell Skript ein Problem mit dem Escaping hat. Ich habe mit der Debug Ausgabe und verschiedenen Arten der Parameterübergabe getestet, da stimmt etwas nicht. Spätestens mit einem Parameter in der Form @(‚Parameter1′,’Parameter2‘) müsste ja korrekt ankommen, daraus macht PRTG allerdings einen String.
            Ich werde dazu mal einen Fall bei Paessler eröffnen, von meinem Skript aus habe ich jetzt 2 Stunden lang unterschiedliche Aufrufe getestet, alle aus der Kommandozeile erfolgreich, über PRTG nicht. Ich hoffe, da gibt es eine Lösung für …

  5. Rudi Antworten

    Hallo Marc,
    vielen Dank für die Idee und die tolle Umsetzung.
    Leider will mein PRTG noch nicht so recht. Ich bekomme die Meldung „Error connecting to your tenant. Please check credentials“, obwohl die Zugangsdaten definitiv korrekt sind. Manuell auf der Probe in der PS x64 ausgeführt bekomme ich korrekte Daten zurück, in der PS x86 dieselbe Fehlermeldung wie in PRTG.
    Funktioniert da in PRTG der Aufruf der x64 PS nicht?

    • Marc Autor des BeitragsAntworten

      Hallo Rudi,
      PRTG startet leider externe Programme (also auch PowerShell) immer im 32-Bit Kontext, deshalb der „Aufwand“, von dort aus in die 64-Bit Umgebung zu kommen. Bisher hat das immer funktioniert, ich glaube allerdings, dass das Skript nicht aus der PowerShell x86 heraus funktioniert – müsste ich mal prüfen. Das angesprochene Sysnative-Verzeichnis, das für den korrekten Aufruf der x64 Umgebung notwendig ist, steht dort (meiner Meinung nach) nicht zur Verfügung.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.