ReportWeb - Module

Für jeden Report gibt es ein Report-Modul, die vom Worker aufgefunden werden. Die Module sind einfache PS1-Dateien, welche nach der Einbindung in die Jobliste nach Zeitplan oder getriggert aufgerufen werden. Die Programme nutzen den gleichen "Runspace" wie der Worker und können also auf von dort bereit gestellte Komponenten (Exchange, Lync, Logging etc.) zugreifen.

  • Zusätzliche Module
    Das Skript muss schon selbst sich darum kümmern, die erforderliche Umgebung zum Ablauf zu schaffen. Entsprechende Snapins oder remote Connections muss es selbst einbinden. Das mag kompliziert klingen, z.B. wenn mehrere Reports mit Exchange arbeiten aber so wird die Umgebung nach dem Ende des Skripts schön wieder aufgeräumt. Da alle Reports in eigenen Runspaces laufen und nicht mehr sequentiell im gleichen Runspace laufen, ist dies aber sowieso erforderlich.
  • Logging
    Das Skript kann einfach mit Write-Host Ausgaben auf die "Konsole" schreiben. Das aufrufende Programm kann diese Ausgaben abfragen
  • Standalone
    Wichtig für die Entwicklung ist, dass das Report-Modul in der Regel auch komplett losgelöst aufgerufen werden kann. Damit lässt es sich auch einfach in Editoren wie PowerGUI etc. interaktiv bearbeiten.
  • Rückgabe
    Die Rückgabe der Ergebnisse erfolgt über STDOUT zum aufrufenden Programm. Es erwartet entweder einen HTML-Textblock oder ein Objekt mit mehreren Properties, die auf entsprechende Ersetzungsbereiche in der HTML-Vorlage passen. Die Rückgabe ist auch das, was Sie eventuell anpassen müssen, wenn Sie einen Betrieb mit oder ohne ReportWeb unterstützen.

Wichtig ist mir, das diese Module auch außerhalb von ReportWeb genutzt werden können und nur, wenn Sie als Module von Reportweb gestartet werden, die Ausgabe vielleicht anders machen. Das erleichtert Debugging und Erweiterungen.

Das Module kann anhand der Variable "ReportWeb" die Einbindung in ReportWeb erkennen. Sie wird als Parameter beim Aufruf mit übergeben.

Module sollten prüfen, ob erforderliche Voraussetzungen vorhanden sind und diese gegebenenfalls selbst herstellen, z.B. das Einbinden verschiedener Add-ons. Trotzdem bleiben die von diesen Modulen genutzte Variablen etc. "lokal" und werden beim beim beenden des Skript wieder frei gegeben. Will das Skript also Informationen über mehrere Aufrufe hinweg erhalten, muss es diese selbst in eine Datei oder Datenbank z.B.: mit Export-CliXML/Import-CLiXML exportieren und importieren.

Auch wenn der Namen "Reportmodul" den Anschein haben könnte, sind die Reportmodule von ReportWeb keine PowerShell Module. Sie tragen nicht die Erweiterung "PSM1" und können nicht mit Load-Module eingebunden werden.

Eingabe

Das Modul wird im Prozessraum des Hauptprogramme mit dessen Rechten und den dort schon geladenen zusätzlichen Modulen (z.B. Exchange, Lync etc.) gestartet. Hier der Ausschnitt aus dem Code:

Alle Module bekommen zwei Parameter mit übergeben.

  • -ReportWeb:$true
    ähnlich wie SCOM beim Aufruf von Test-Commandlets einfach "monitoringcontext:$true übergibt, startet das Hauptprogramm die Module mit dem Parameter "-ReportWeb:$true". Der Sinn ist, dass ich im Modul dann unterscheide, ob ich es z.B: für Debugging und Test eigenständig aufrufe und mehr Debug-Ausgaben oder eine andere Ausgabe am Ende genereire oder ob ich die Ausgabe so erstelle, dass ReportWeb.ps1 damit arbeiten kann.
  • -Reportparameter
    Steuerungsparameter
    Optional kann noch ein weiterer Parameter übergeben werden. So kann ein Code abhängig von diesem Parameter etwas andere Funktionen ausüben, z.B. einen anderen Report erstellen. Dieser Wert wird aus der Steuerdatei-Datei geholt.

Das ist dann aber schon alles.

Ausgabe

Als Rückgabe der Ergebnisse habe ich STDOUT gewählt, d.h. das Hauptprogramm ruft das Module auf und sammelt die Ausgaben nach STDOUT am Ende wieder ein. Das Hauptprogramm erwartet dabei eine von drei Variablentypen, wie sie auch im Code erkennen können:

Damit kann ich im wesentlichen zwei Fälle abdecken:

  • String und Array of String
    Das Hauptprogramm geht dann davon aus, dass die Rückgabe bereits formatierter HTML-Code ist und dieser als "content" betrachtet werden soll.
  • PSCustomObject
    In diesem Fall läuft ReportWeb.ps1 alle NamedProperties durch und sucht in der HTML-Vorlage einen passenden Platzhalter, um die Texte einzufügen. Zudem gibt es drei besondere Properties SMTPTO, SMTPSUBJECT, "SMTPBODY". Es reicht den SMTPSUBJECT zu füllen, um eine Mail zu senden. Mit SMTPTO kann in der Steuerdatei vordefinierter Empfänger überschrieben werden und mit SMTPBODY kann ein Mailbody übergeben werden.

Sie können also direkt per STDOUT einfach HTML-Code erzeugen.

"<h1>Prozessor</h1>
<table>
<th><td>Name</td><td>Wert</td></th>"

(Get-Processor).properties | %{
    "<tr><td>" + $_.name + "</td><td>" + $_.value + "</td></tr>"
}

"</table>"

Alternativ können Sie z.B. eine Liste recht einfach konvertieren lassen:

get-process `
| select processname,workingset `
| ConvertTo-Html `
   -Fragment

Umgebungsvariablen

Wenn der Report vom Worker gestartet wird, findet er eine gut vorbereitete Umgebung vor. Unter anderem gib es einige Umgebungsvariablen, die er nutzen kann. Anhand von "$reportweb" kann ein Reportmodul erkennen, ob er vom Worker oder interaktiv gestartet wird. Ich nutze diese Feature, um solche Report-Skripte flexibel zu halten und je nach Umgebung eine andere Ausgabe zu erzeugen. Siehe auch Reportweb Environment.

Testen

Natürlich kann ich so auch einfacher "testen" und die Reports komplett ohne Reportweb starten. Um Tests zu vereinfachen sollten die Module idealerweise daher auch autark arbeiten können, d.h. ein einfacher Aufruf des Skripts sollte nicht scheitern, weil das Skript auf irgendwelche Randbedingungen angewiesen ist. Die Module sollten auch voneinander unabhängig sein. Wenn ein Modul allerdings Daten generiert, die von mehreren Reports genutzt werden, so ist es durchaus denkbar, dass diese eine gemeinsame Datenablage nutzen. für die Aktualisierung dieser Ablage könnte jedes Modul selbst sorgen, wenn es glaubt die Daten sind "veraltet". Denkbar ist auch, dass Informationen von anderen Quellen aufbereitet und quasi "untergeschoben" werden und das Reportmodul nur die Aufbereitung macht. Hier ist vieles denkbar.

Performance und Optimierung

Je umfangreicher und größer eine Umgebung ist, desto länger können Auswertungen dauern. Gerade die Exchange Commandlets sind zwar elegant zu verwenden, aber durch den Einsatz von RBAC und HTTPS geht die auf die Performance (Siehe PS Performance). Es kann daher hilfreich sein, bestimmte Abfragen doch wieder selbst per ADO/ADSI durchzuführen.

Wenn mehrere Reports vergleichbare Quellen anzapfen, dann könnten die Module selbst einen Cache anlegen. Ein gutes Beispiel hierfür sind Datenbankauswertungen, bei denen die Benutzer und deren Postfachgrößen aus den Exchange Datenbanken ausgelesen werden.