Skript Adapter Erweiterung¶
Einleitung¶
Die RDS-Daten-Erweiterung sammelt Daten von den Windows Remote Desktop Systemen. Alle verfügbaren Session- und Prozessdaten werden von den angegebenen Hosts abgerufen und in den Datenspeicher integriert.
Fakten¶
Name |
Script Adapter |
Bezeichner |
|
Version |
1.1 |
Enthaltene Module |
Source |
Abschnitte |
|
Informationsblöcke |
|
Konfiguration¶
Das Modul benötigt keine Konfigurationsblock in der Serverkonfiguration. Es erwartet ein Unterverzeichnis namens adapter_scripts im Datenverzeichnis des Servers. Jede Datei mit einer .xml-Endung in diesem Verzeichnis wird als Skriptdatei gelesen. Andere Dateien, die dieser Endung nicht entsprechen, werden ignoriert.
Das folgende Beispiel zeigt, wie das Skriptverzeichnis aussehen könnte.
c:\Program Files\EducateIT\Raptor\
^- assumed server data directory
adapter_scripts\
script1.xml
script2.xml
script3.xml
Jede Skriptdatei in diesem Verzeichnis muss im gültigen XML-Format vorliegen. Dabei solltest du die Datei immer in der UTF-8 Kodierung speichern.
Das folgende Beispiel zeigt die Struktur der Skriptdatei.
1<?xml version="1.0" encoding="UTF-8" ?>
2<AdapterScript version="1">
3 <Id>...</Id>
4 <Name>...</Name>
5 <Required>
6 ...
7 </Required>
8 <Schema>
9 ...
10 </Schema>
11 <DataScript><![CDATA[
12 ...
13 ]]></DataScript>
14</AdapterScript>
Die folgenden Abschnitte erklären jeden Wert dieser Struktur im Detail.
Ersetze die Auslassungspunkte (...
) mit den tatsächlichen Werten und Inhalten, die für dein Skript erforderlich sind. Die Werte <Id>
, <Name>
, <Required>
, <Schema>
und <DataScript>
sollten durch die entsprechenden Informationen ersetzt werden, die das Skript beschreiben und definieren.
Das Tag Id
¶
Eine eindeutige ID für das Adapter-Skript. Die ID darf ausschließlich Buchstaben, Zahlen und den Unterstrich enthalten. Die Länge der ID darf 200 Zeichen nicht überschreiten.
Das Tag Name
¶
Ein für Menschen lesbarer Name, der in Fehlermeldungen innerhalb der Log-Datei angezeigt wird.
Das Tag Required
¶
Der Required
-Block enthält die Anforderungen, die erfüllt sein müssen, bevor das Skript ausgeführt werden kann. Jeder Eintrag in dieser Liste stellt eine zwingende Bedingung dar, die erfüllt sein muss.
Es kann einen ObjectType
-Eintrag geben. Der ObjectType
-Eintrag schränkt das Skript auf einen bestimmten Objekttyp ein. Der Inhalt dieses Tags muss der Name eines Objekttyps sein. Im folgenden Beispiel ist das Skript ausschließlich für Benutzerobjekte vorgesehen:
<Required>
<ObjectType>User</ObjectType>
</Required>
Du kannst beliebig viele InformationBlock
-Einträge hinzufügen. Der Inhalt des InformationBlock
-Eintrags muss ein gültiger Informationsblock-Identifier sein. Nur wenn alle angegebenen Informationsblöcke vorhanden sind, wird dem Objekt ein Block für die Adapterdaten hinzugefügt.
Wenn Daten vom Adapterblock angefordert werden, wird die Ausführung des Skripts verzögert, bis alle erforderlichen Blöcke Daten enthalten. Im Spezialfall, dass die erforderlichen Blöcke nicht bereits automatisch vom Client ausgelöst wurden, löst der Adapter eine Datenanforderung für alle diese erforderlichen Blöcke aus.
Das folgende Beispiel verlangt, dass beide Informationsblöcke ActiveDirectory
und ActiveDirectoryOR
vorhanden sind und Daten enthalten, bevor das Skript ausgeführt wird.
<Required>
<InformationBlock>ActiveDirectory</InformationBlock>
<InformationBlock>ActiveDirectoryOR</InformationBlock>
</Required>
Die Reihenfolge der Werte spielt keine Rolle. Du kannst die verschiedenen Anforderungen kombinieren, wie im nächsten Beispiel gezeigt.
<Required>
<ObjectType>User</ObjectType>
<InformationBlock>ActiveDirectory</InformationBlock>
<InformationBlock>ActiveDirectoryOR</InformationBlock>
</Required>
Das Tag Schema
¶
Mit dem Schema
-Block legst du das Schema für die Anzeige im Client fest. Du kannst beliebig viele SchemaValue
-Einträge hinzufügen. Jeder Eintrag hat das folgende Format:
<SchemaValue name="..." label="..." type="..." section="..." orderIndex="..." />
Die Bedeutung der einzelnen Attribute wird in den nächsten Abschnitten beschrieben.
Das Attribut name
¶
Dies ist der Bezeichner für den Wert. Er kann Buchstaben, Zahlen und den Unterstrich enthalten. Du verwendest diesen Bezeichner im Skript, um die Daten für diesen Wert bereitzustellen.
Das Attribut label
¶
Das für Menschen lesbare Label, das im Client angezeigt wird.
Das Attribut type
¶
Der Typ des Wertes. Der Adapter unterstützt nicht alle Raptor-Typen. Die unterstützten Typen sind String
, StringList
, Table
, Integer
und Date
.
Das Attribut section
¶
Der Bezeichner des Abschnitts, in dem der Wert platziert werden soll. Dies kann ein vorhandener Abschnitt oder ein neuer sein.
Das Attribut orderIndex
¶
Eine Ganzzahl zwischen 1 und 1000, die die Position des Wertes im Abschnitt bestimmt.
Das Tag DataScript
¶
In dieses Tag schreibst du den eigentlichen Skript welcher ausgeführt wird. Wie du Skripte für den Skript-Adapter schreibst findest du im Kapitel Skript-Adapter Skripte.
Um Probleme mit der Formatierung deiner Skripte zu vermeiden, solltest du diese immer in eine CDATA-Sektion platzieren, wie im folgenden Beispiel gezeigt:
1<?xml version="1.0" encoding="UTF-8" ?>
2<AdapterScript version="1">
3 <Id>...</Id>
4 <Name>...</Name>
5 <Required>
6 ...
7 </Required>
8 <Schema>
9 ...
10 </Schema>
11 <DataScript><![CDATA[
12 // Dein Skript....
13 ]]></DataScript>
14</AdapterScript>
Das Konfigurationsschema¶
Module
ScriptAdapter
Must not be empty.
Der Wert Directory
¶
Mit dem optionalen Wert Directory
kannst du das Unterverzeichnis wählen, worin nach Scripten für die Erweiterung gesucht wird. Lässt du diesen Wert weg, wird im Unterverzeichnis adapter_scripts
nach Scripten gesucht.
Falls du den Pfad änderst, passe die Berechtigungen so an, dass keine unbefugten Personen die Scripte anpassen können.
Skript-Adapter Skripte¶
Kurze Übersicht¶
Verfasse die Skripte, die Adapterdaten erzeugen, in JavaScript oder dem standardisierten ECMAScript. Eine Übersicht der Sprache findest du im Kapitel Qt-Script/JavaScript Übersicht.
Sofern die von dir im Tag Required
konfigurierten Bedingungen erfüllt sind, wird dein Skript ausgeführt. Da dies für jedes angeforderte Objekt bei jeder Änderung von Daten geschieht, sollte dein Skript schnell ausgeführt werden und keinesfalls den Prozess blockieren.
Innerhalb deines Skripts hast du Zugriff auf zwei globale Objekte: object
und result
. Nutze diese beiden Objekte, um alle aktuellen Daten vom Objekt zu erhalten und das Ergebnis für deinen Adapter bereitzustellen. Zudem existiert ein helper
Objekt, das weitere Funktionen zur Verfügung stellt.
Um das Ergebnis bereitzustellen, schreibst du es als Instanzvariablen in das result
-Objekt. Zum Beispiel hast du in deinem Schema den „String“-Wert example
definiert.
1<?xml version="1.0" encoding="UTF-8" ?>
2<AdapterScript version="1">
3 ...
4 <Schema>
5 <SchemaValue name="example" label="Example Script" type="String" section="exampleScript" orderIndex="10" />
6 </Schema>
7 ...
8</AdapterScript>
Am Ende deines Skripts weist du der Variable result.example
dein Resultat zu, wie im folgenden Beispiel gezeigt:
1<?xml version="1.0" encoding="UTF-8" ?>
2<AdapterScript version="1">
3 ...
4 <Schema>
5 <SchemaValue name="example" label="Example Script" type="String" section="exampleScript" orderIndex="10" />
6 </Schema>
7 <DataScript><![CDATA[
8 // Deine Berechnung des Resultats...
9 result.example = "Hello World!"
10 ]]></DataScript>
11</AdapterScript>
Für das Ergebnis kannst du native Datentypen verwenden, aber es gibt auch Klassen, die du instanziieren kannst: StringValue
und TableValue
, die eine einfache Schnittstelle bieten, um die beiden Raptor-Werttypen zu erstellen.
Lies die nächsten Kapitel für eine detaillierte Beschreibung aller oben erwähnten Variablen und Klassen.
Die Variable object
¶
Die Schnittstelle für die Variable object
wird im Kapitel Skript Objekt Interface beschrieben. Die Instanz dieser Variable ist bereits zu Beginn des Skripts mit einer Momentaufnahme der Daten des Objekts initialisiert. Auch wenn mehr Informationsblöcke verfügbar sind, als im Abschnitt „Required“ angegeben, solltest du nur auf Daten zugreifen, die du dort spezifiziert hast.
Die Variable result
¶
Die Variable result
wird zu Beginn des Skripts als leeres Objekt initialisiert. Du musst diesem Objekt Eigenschaften hinzufügen, um den Datenblock als Ergebnis aufzubauen. Die hinzugefügten Eigenschaften und die Namen der Eigenschaften werden am Ende deines Skripts in einen Datenblock konvertiert.
Du kannst verschiedene native JavaScript-Typen verwenden, um die Werte zu erstellen. Sie werden automatisch in die richtigen Werttypen konvertiert.
Siehe das folgende Beispiel für automatische Konvertierungen von nativen Werten. Einige Zieltypen unterstützen mehrere Möglichkeiten einen Wert bereitzustellen, wie Strings und String-Arrays.
result.value1 = "A text"; // Native string literal
result.value2 = new String("A text"); // String object
result.value3 = 12; // Number
result.value4 = true; // Boolean
result.value5 = ["1", "2", "3"]; // Array literal.
result.value6 = new Array("1", "2", "3"); // Array object.
Die Konvertierung von nativen Werten erfolgt wie in der folgenden Tabelle beschrieben:
JavaScript Typ |
Raptor Typ |
Notes |
---|---|---|
Native String Literal |
String |
Sonderzeichen im Text werden automatisch maskiert. |
String object |
||
Native Number |
Integer |
Der Wert wird in eine Ganzzahl konvertiert. Stellen nach dem Dezimalpunkt werden abgeschnitten. |
Native Boolean |
Boolean |
|
Array Literal |
StringList |
Das Array wird in eine StringList konvertiert, aber nur, wenn alle Werte in der Liste Strings sind oder in Strings konvertiert werden können. |
Array Object |
Es gibt spezielle Objekttypen für spezielle Formatierungen in Strings, wie Aktionen oder Links, und für Tabellen. Siehe das folgende Code-Beispiel, wie man Instanzen dieser Klassen erstellt.
result.value1 = new StringValue();
result.value2 = new TableValue();
Siehe Die StringValue Klasse und Die TableValue Klasse für Details zu den beiden speziellen Klassen und ihren Schnittstellen.
Das globale helper
Objekt¶
Das globale helper
Objekt stellt Methoden zur Verfügung, um zusätzliche Prüfungen ohne das Benutzerobjekt durchzuführen. Siehe die folgende Abbildung für die Schnittstelle dieser Klasse.

Das Interface des helper
Objekts.¶
Derzeit definiert die Schnittstelle nur zwei Methoden, die in den folgenden Abschnitten erklärt werden.
Methode doesFileExist
¶
Diese Methode überprüft, ob eine Datei an dem angegebenen Ort vorhanden ist. Die Methode gibt true
zurück, wenn der Pfad vorhanden ist und auf eine Datei verweist.
Methode doesDirectoryExist
¶
Diese Methode überprüft, ob ein Verzeichnis an dem angegebenen Ort vorhanden ist. Die Methode gibt true
zurück, wenn der Pfad vorhanden ist und auf ein Verzeichnis verweist.
Anwendungsbeispiel¶
var filePath = "\\\\example\\path\\path\\file.exe";
if (helper.doesFileExist(filePath)) {
// ...
}
var directoryPath = "C:\\exampleDirectory";
if (helper.doesDirectoryExist(directoryPath)) {
// ...
}
Die StringValue
Klasse¶
Mit dieser Klasse erstellst du einen String-Wert, der spezielle Formatierungen oder Links enthält. Sieh dir die folgende Abbildung für ein UML-Diagramm der StringValue
-Klassen-Schnittstelle an.

Die Schnittstelle der StringValue
Klasse.¶
Die folgenden Abschnitte enthalten Beschreibungen für jede Methode dieser Klasse. Siehe das folgende Beispiel für Anwendungsbeispiele dieser Klasse.
var text = new StringValue();
// Setze den String auf einen gegebenen Text
text.setText( "Beispieltext." ); // Lösche den String.
text.clear();
// Konvertiere den String in einen nativen String.
var nativeString = text.toString(); // Füge weiteren Text hinzu.
text.appendText( "Mehr Text." ); // Füge einen benutzerdefinierten Link hinzu.
text.appendLink( "http://www.example.com", "Gehe zur Beispiel-Website" );
// Füge einen Programmlink (Aktion) hinzu
text.appendProgramLink( "\"c:/my software/example.exe\" -a=xxx", "Beispiel starten" );
// Füge einen Dateilink hinzu
text.appendFileLink( "c:/documents/file.txt", "Datei öffnen" );
Methode clear
¶
Mit der clear
-Methode setzt du die String-Wert-Instanz zurück und entfernst jeglichen zuvor hinzugefügten oder gesetzten Text.
Methode toString
¶
Mit dieser Methode konvertierst du den aktuellen Inhalt der String-Wert-Instanz in einen nativen Skript-String, der alle Escape- und Formatierungstags enthält, die bereits hinzugefügt wurden.
Methode setText
¶
Mit der Methode setText
legst du den Text der Instanz fest. Escaping wird durchgeführt, um eine Formatierungsinterpretation des Textes zu verhindern.
Methode appendText
¶
Mit dieser Methode fügst du am Ende des aktuellen Strings zusätzlichen Text hinzu. Escaping wird durchgeführt, um eine Formatierungsinterpretation des angehängten Textes zu verhindern.
Methode appendLink
¶
Mit dieser Methode fügst du eine URL, die mit dem Parameter url
übergeben wird, mit dem angezeigten Text, der mit dem Parameter text übergeben wird, am Ende des aktuellen Strings hinzu. Die URL muss eine vollständige URL sein, die mit dem Schema beginnt.

Beispiel eines hinzugefügten Links.¶
Methode appendProgramLink
¶
Mit dieser Methode fügst du einen Programmlink, manchmal auch „Aktion“ im Kontext des Raptor-Clients genannt, hinzu. Er wird als Schaltfläche im Client angezeigt.
Der Parameter program
muss mit einem absoluten Pfad zur ausführbaren Datei beginnen, die vom Client gestartet werden soll. Nach diesem Pfad kannst du beliebig viele Kommandozeilenargumente durch Leerzeichen getrennt hinzufügen. Wenn der Pfad zur ausführbaren Datei Leerzeichen enthält, musst du ihn in Anführungszeichen setzen. Stelle sicher, dass du diese Anführungszeichen im Skript wie in den Anwendungsbeispielen gezeigt mit Backslash zeichen markierst.
Der Parameter text
wird als Beschriftung auf der Aktions-Schaltfläche angezeigt.

Beispiel einer hinzugefügten Programmlink-Schaltfläche.¶
Methode appendFileLink
¶
Mit dieser Methode fügst du dem aktuellen String einen Link zu einer Datei oder einem Verzeichnis hinzu. Wenn der Benutzer den Link im Client anklickt, wird entweder die verlinkte Datei in der zugeordneten Anwendung geöffnet oder der Dateibrowser zeigt den Inhalt des Verzeichnisses an.
Der erste Parameter path
muss ein absoluter Pfad zur Datei oder zum Verzeichnis sein.
Der zweite optionale Parameter text
kann übergeben werden, um den Dateilink durch einen beliebigen Text zu ersetzen.

Beispiel eines hinzugefügten Dateilinks.¶
Die TableValue
Klasse¶
Diese Klasse repräsentiert einen Tabellenwert. Siehe die folgende Abbildung für einen Tabellenwert, der im Raptor-Client angezeigt wird.

Ein Tabellenwert im Raptor-Client.¶
Die Schnittstelle der TableValue
Klasse ist in der Abbildung unten dargestellt.

Die Schnittstelle der TableValue
Klasse.¶
Um die Schnittstelle zu vereinfachen, muss die Tabelle in der folgenden Reihenfolge erstellt werden:
Erstelle eine neue Instanz der Klasse.
Füge alle Spalten mit der Methode
addColumn
hinzu.Setze alle Zellen mit der Methode
setCellValue
.
Am Ende des Skripts werden leere oder unvollständige Zeilen entfernt. Es gibt eine Begrenzung von maximal 16 Spalten und 1000 Zeilen.
Die nächsten Abschnitte beschreiben die Methoden dieser Schnittstelle.
Methode addColumn
¶
Diese Methode fügt der Tabelle eine neue Spalte hinzu. Jede Spalte benötigt ein Label, das im Client angezeigt wird, und einen festen Typ. Der Typ muss ein String mit dem case-sensitiven Typnamen sein. Die unterstützten Typen sind String
, StringList
, Table
, Integer
und Date
.
Der Spaltenindex beginnt bei Null.
Methode getColumnCount
¶
Diese Methode gibt die aktuelle Anzahl der Spalten zurück.
Methode getRowCount
¶
Diese Methode gibt die aktuelle Anzahl der Zeilen zurück. Beim Erstellen der Tabelle werden leere Zeilen gezählt und du erhältst nur die höchste Anzahl der aktuell gesetzten Zeilen. Wenn du beispielsweise eine Zelle in Zeile 100 setzt, gibt diese Methode 101 Zeilen zurück. Am Ende des Skripts werden leere oder unvollständige Zeilen entfernt. In diesem Fall kann die Zeilenzahl niedriger sein.
Methode setCellValue
¶
Mit dieser Methode setzt du die Zellen der Tabelle. Du kannst die Zellen in beliebiger Reihenfolge setzen, indem du sie über einen Zeilen- und Spaltenindex ansprichst.
Um gültige Zeilen zu erstellen, müssen alle Zellen einer Zeile mit einem Wert des richtigen Typs gesetzt werden, den du in der Methode addColumn
angegeben hast.
Das folgende Skriptbeispiel zeigt, wie man eine Tabelle erstellt.
// Erstelle eine neue Instanz von TableValue
var tabelle = new TableValue();
// Füge Spalten hinzu
tabelle.addColumn("Name", "String");
tabelle.addColumn("Alter", "Integer");
// Setze Zellenwerte
tabelle.setCellValue(0, 0, "Alice");
tabelle.setCellValue(0, 1, 30);
tabelle.setCellValue(1, 0, "Bob");
tabelle.setCellValue(1, 1, 25);
Beispiele¶
Konfigurationsbeispiel¶
1<?xml version="1.0" encoding="UTF-8" ?>
2<AdapterScript version="1">
3 <Id>profilePaths</Id>
4 <Name>Group Based Profile Paths</Name>
5 <Required>
6 <InformationBlock>ActiveDirectory</InformationBlock>
7 <InformationBlock>ActiveDirectoryOR</InformationBlock>
8 </Required>
9 <Schema>
10 <SchemaValue name="profilePaths" label="Profile Paths" type="Table" section="profilePaths" orderIndex="10"/>
11 </Schema>
12 <DataScript><![CDATA[
13 ...script, see below...
14 ]]></DataScript>
15</AdapterScript>
Skript-Beispiel¶
1// Configuration
2// ---------------------------------------------------------------------------
3// config:
4// This configures the paths, labels and the group who has to match to
5// display this path.
6// column 1: The label for the path.
7// column 2: The name of the group who has to match.
8// column 3: The path, which can contain the placeholder %USERNAME% which
9// is replaced by the name of the object.
10// Note! Don't forget to escape the backslash characters!
11//
12var config = [
13 ["CTX Farm Prod", "CitrixFarmProd", "\\\\ctx\\profile$\\%USERNAME%\\Prod"],
14 ["CTX Farm Int", "CitrixFarmInt", "\\\\ctx\\profile$\\%USERNAME%\\Int"],
15 ["CTX Farm Text", "CitrixFarmTest", "\\\\ctx\\profile$\\%USERNAME%\\Test"],
16 ["Domain Admin", "Domain Admins", "\\\\ctx\\profile$\\%USERNAME%\\Test"]
17];
18
19// actionCommand:
20// This is the action command which is displayed in the last column of the
21// table. You can use the placeholder %PATH% which is replaced with the
22// path in the table.
23var actionCommand =
24 "\"%RaptorPath%/EducateIT/AppleTreeClient/AppleTreeClient.exe\" " +
25 "-profile=profilePath " +
26 "-path=\"%PATH%\"";
27
28// actionLabel:
29// The action label is displayed as button for the action above.
30var actionLabel = "Reset Profile";
31
32// Script
33// ---------------------------------------------------------------------------
34//
35// Get the groups for this object (array of strings)
36var groups = object.AD_User_Delayed.groups;
37var user = object.name;
38
39// Prepare the table as result.
40var paths = new TableValue();
41paths.addColumn("Name", "String");
42paths.addColumn("Path", "String");
43paths.addColumn("Action", "String");
44
45// Check which of the paths matches.
46var row = 0;
47for (var i = 0; i < config.length; ++i) {
48 var configRow = config[i];
49 var name = configRow[0];
50 var group = configRow[1];
51 var path = configRow[2];
52
53 var hasMatch = false;
54 for (var x = 0; x < groups.length; ++x) {
55 if (groups[x] === group) {
56 hasMatch = true;
57 break;
58 }
59 }
60
61 if (!hasMatch) {
62 continue;
63 }
64
65 // Success, found a match prepare the final path.
66 var finalPath = path.replace("%USERNAME%", user);
67
68 // Check if the path exists
69 if (!helper.doesDirectoryExist(finalPath)) {
70 continue; // Skip this profile
71 }
72
73 // Prepare the other values
74 var finalAction = actionCommand.replace("%PATH%", finalPath);
75 var pathValue = new StringValue();
76 pathValue.appendFileLink(finalPath);
77 var actionValue = new StringValue();
78 actionValue.appendProgramLink(finalAction, actionLabel);
79
80 // Add the values to the table.
81 paths.setCellValue(row, 0, name);
82 paths.setCellValue(row, 1, pathValue);
83 paths.setCellValue(row, 2, actionValue);
84 row++;
85}
86
87// Add the table to the result.
88result.profilePaths = paths;