Syntax und Bedeutung der primären Sektionen eines opsi-script Skriptes [W/L/M]

Wie bereits in Abschnitt Primäre und sekundäre Unterprogramme des opsi-script Skriptes dargestellt, zeichnen sich die Actions-Sektion dadurch aus, dass sie den globalen Ablauf der Abarbeitung eines opsi-script-Skriptes beschreiben und insbesondere die Möglichkeit des Aufrufs von Unterprogrammen, sekundärer oder geschachtelter primärer Sektionen bieten.

Diese Unterprogramme heißen Sub-Sektionen – welche wiederum in der Lage sind, rekursiv weitere Sub-Sektionen aufzurufen.

Der vorliegende Abschnitt beschreibt den Aufbau und die Verwendungsweisen der primären Sektionen des opsi-script Skriptes.

Die primären Sektionen [W/L/M]

In einem Skript können vier Arten primärer Sektionen vorkommen:

  • eine Initial-Sektion zu Beginn des Skriptes (kann entfallen),

  • danach eine Actions-Sektion sowie

  • (beliebig viele) Sub-Sektionen.

  • eine ProfileActions Sektion

Initial- und Actions-Sektion sind bis auf die Reihenfolge gleichwertig (Initial sollte an erster Stelle stehen). In der Initial Sektion sollten statische Einstellungen und -werte bestimmt werden (wie z.B. der Loglevel). Inzwischen empfehlen wir, die Initial Sektion aus gründen der Übersichtlichkeit weg zulassen. In der Actions-Sektion ist die eigentliche Abfolge der vom Skript gesteuerten Programmaktionen beschrieben ist und kann als Hauptprogramm eines opsi-script Skriptes gesehen werden.

Sub-Sektionen sind syntaktisch mit der Initial- und der Actions-Sektion vergleichbar, werden aber über die Actions-Sektion aufgerufen. In ihnen können auch wieder weitere Sub-Sektionen aufgerufen werden.

Der Name von Sub-Sektionen muss mit 'Sub' beginnen. Der nachfolgende Namensbestandteil kann frei gewählt werden, z.B. Sub_InstallBrowser. Der Name dient dann (in gleicher Weise wie bei den sekundären Sektionen) als Funktionsaufruf. Der Inhalt der Funktion bestimmt sich durch den Inhalt einer Sektion betitelt mit dem Namen (in unserem Beispiel: [Sub_InstallBrowser]).

Sub-Sektionen zweiter oder höherer Anforderung (Sub von Sub usw.) können keine weiteren inneren Sektionen beinhalten, aber es können externe Unterprogramme aufgerufen werden (siehe dazu Abschnitt "Aufrufe von Unterprogrammen").
Wenn (geschachtelte) Sub-Sektionen in externe Dateien ausgelagert werden, müssen die aufgerufenen Sekundären Sektionen üblicherweise in der Datei untergebracht werden, aus der sie aufgerufen werden. Je nach verwendeter Komplexität des Syntax müssen sie evtl. zusätzlich auch in der Hauptdatei untergebracht werden.

Die ProfileActions Sektion kann in einem normalen Installationsskript als Sub-Sektion mit speziellen Syntax Regeln dienen. Existiert diese Sektion in einem Script das als 'userLoginScript' aufgerufen wurde, so ist diese Sektion der Programmstart (statt Actions). Siehe Kapitel 'User Profile Management' im opsi-manual sowie Kommandos für userLoginScripts / User Profile Management [W]

Parametrisierungsanweisungen für den opsi-script [W/L/M]

Festlegung der Protokollierungstiefe

Die alte Funktion LogLevel= ist ab opsi-script Version 4.10.3 nicht mehr empfohlen, verwenden Sie stattdess SetLogLevel. Um Rückwärtskompatibilität zu alten Skripten zu gewährleisten wird zu dem hiermit gesetzten Loglevel nochmal 4 hinzuaddiert.

Es gibt zwei ähnliche Varianten, um den Loglevel zu spezifizieren:

SetLogLevel = <Zahl>

SetLogLevel = <STRINGAUSDRUCK>

SetLogLevel definiert die Tiefe der Protokollierung der Operationen. Im ersten Fall kann die Nummer als Integer Wert oder als String-Ausdruck (vgl. String-Werte, String-Ausdrücke und String-Funktionen) angegeben werden. Im zweiten Fall versucht der opsi-script den String-Ausdruck als Nummer auszuwerten.

Es sind zehn Detaillierungsgrade wählbar von 0 bis 9

0 = nothing (absolut nichts)
1 = essential ("unverzichtbares")
2 = critical (unerwartet Fehler die zu einem Programmabbruch führen)
3 = error (Fehler, die kein laufendes Programm abbrechen)
4 = warning (das sollte man sich nochmal genauer anschauen)
5 = notice (wichtige Aussagen zu dem Programmverlauf)
6 = info (zusätzlich Informationen)
7 = debug (wichtige debug Meldungen)
8 = debug2 (mehr debug Informationen und Daten)
9 = confidential (Passwörter und andere sicherheitsrelevante Daten)
  • Auf Loglevel 6 wird geloggt:
    Alle Programmanweisungen, alle Wertzuweisungen zu Stringvariablen, die Ergebnisse kompletter boolscher Ausdrücke (hinter if)

  • Auf Loglevel 7 wird geloggt:
    Alle Zuweisungen zu String-Listen-Variablen, die Ausgaben von externen Prozessen, soweit diese nicht einer String-Liste zugewiesen werden, die Ergebnisse der Teilauswertung boolscher Ausdrücke (hinter if)

  • Auf Loglevel 8 wird geloggt:
    String-Listen, die von Funktionen erzeugt werden, die Ausgaben von externen Prozessen, wenn diese einer String-Liste zugewiesen werden

Der Default ist "7".
siehe auch : opsi-script-configs_default_loglevel siehe auch : opsi-script-configs_force_min_loglevel

Logdatei im Append-Mode senden

  • forceLogInAppendMode = <boolean value> //since 4.12.3.6 (default=false);
    Wenn true wird eine Logdatei, so sie über den Service an den Server gesendet wird, im Append-Mode gesendet.

Benötigte opsi-script Version [W/L/M]

Die Anweisung

requiredOpsiscriptVersion <RELATIONSSYMBOL> <ZAHLENSTRING>
seit: 4.12.3.6

z.B.

requiredOpsiscriptVersion >= "4.12.3.6"

lässt den opsi-script überprüfen, ob die geforderte Versionseigenschaften vorliegt. Wenn nicht erscheint ein Fehlerfenster oder ein Fehler wird in das Log geschrieben und das Skript als 'failed' gekennzeichnet..

Es gibt keinen Default.

Eine ältere und noch unterstützte Form lautet (seit 4.3):

requiredWinstVersion <RELATIONSSYMBOL> <ZAHLENSTRING>

Reaktion auf Fehler [W/L/M]

Zu unterscheiden sind zwei Sorten von Fehlern, die unterschiedlich behandelt werden müssen:

  1. fehlerhafte Anweisungen, die der opsi-script nicht "versteht", d.h. deren Interpretation nicht möglich ist (syntaktischer Fehler),

  2. aufgrund von "objektiven" Fehlersituationen scheiternde Anweisungen (Ausführungsfehler).

Normalerweise führen syntaktische Fehler neben einem Logeintrag zu einem 'failed' Status des Skript, Ausführungsfehler werden in einer Log-Datei protokolliert und können später analysiert werden.

Das Verhalten des opsi-script bei einem syntaktischen Fehler wird über die Konfiguration bestimmt.

  • ScriptErrorMessages = <Wahrheitswert>
    Wenn der Wert true ist (Default), werden Syntaxfehler bzw. Warnhinweise zum Skriptes als Message-Fenster auf dem Bildschirm angezeigt.
    Für <Wahrheitswert> kann außer 'true' bzw. 'false' hier zwecks einer intuitiveren Bezeichnung auch 'on' bzw. 'off' eingesetzt werden.
    Default=true
    siehe auch: opsi-script-configs_ScriptErrorMessages

  • FatalOnSyntaxError = <Wahrheitswert>

    • 'true' = (default) Bei einem Syntaxfehler wird das Script abgebrochen und 'failed' zurückgeliefert. Dem Server wird die Meldung 'Syntax Error' übergeben.

    • 'false' = Bei einem Syntaxfehler wird das Script nicht abgebrochen.
      Der Syntaxfehler wird in jedem Fall als 'Critical' in die Logdatei übernommen.
      In jedem Fall wird der Errorcounter um 1 erhöht.
      Seit 4.11.3.2
      In älteren Versionen wird weder gelogged noch abgebrochen.

  • FatalOnRuntimeError = <Wahrheitswert>
    Ein RuntimeError ist ein Fehler in der Scriptlogik der zu einer verbotenen Operation führt. Ein Beispiel ist von einer String-Liste welche 2 Strings hat den 5. String zu fordern.

    • 'true' = Bei einem RuntimeError wird das Script abgebrochen und 'failed' zurückgeliefert. Dem Server wird die Meldung 'Runtime Error' übergeben.

    • 'false' = (default) Bei einem Syntaxfehler wird das Script nicht abgebrochen. Der RuntimeError wird als 'Error' in die Logdatei übernommen und wird der Errorcounter um 1 erhöht.
      Seit 4.11.4.3

Die beiden folgenden Einstellungen steuern die Reaktion auf Fehler bei der Ausführung des Skriptes.

  • ExitOnError = <Wahrheitswert>
    Mit dieser Anweisung wird festgelegt, ob bei Auftreten eines Fehlers die Abarbeitung des Skriptes beendet wird. Wenn <Wahrheitswert> 'true' oder 'yes' oder 'on' gesetzt wird, terminiert das Programm, andernfalls werden die Fehler lediglich protokolliert (default).

  • TraceMode = <Wahrheitswert>
    Wird TraceMode eingeschaltet (Default ist false), wird jeder Eintrag ins Protokoll zusätzlich in einem Message-Fenster auf dem Bildschirm angezeigt und muss mit einem OK-Schalter bestätigt werden.

Vordergrund (StayOnTop) [W]

  • StayOnTop = <Wahrheitswert>

Mittels StayOnTop = true (oder = on) kann bestimmt werden, dass im Batchmodus das opsi-script Fenster den Vordergrund des Bildschirms in Beschlag nimmt, sofern kein anderer Task den selben Status beansprucht. Im Dialogmodus hat der Wert der Variable keine Bedeutung.

Nach Programmiersystem-Handbuch soll der Wert nicht im laufenden Betrieb geändert werden. Zur Zeit sieht es so aus, als wäre ein einmaliges (Neu-) Setzen des Wertes möglich, ein Rücksetzen auf den vorherigen Wert während des Programmlaufs dann aber nicht mehr.

StayOnTop steht per Default auf false damit verhindert wird das Fehlermeldungen eventuell nicht sichtbar sind, weil der opsi-script im Vordergrund läuft.

Fenster Modus / Skin / Aktivitätsanzeige

  • SetSkinDirectory <skindir> // [W/L/M]
    Setzt das zu verwendende SkinDirectory und lädt den Skin. Wird bei diesem Befehl ein leerer oder ungültiger Pfad angegeben, so wird der Defaultpfad verwendet.
    Der Defaultpfad ist %OpsiScriptDir%\skin.

Beispiel:

SetSkinDirectory "%ScriptPath%\testskin"
sleepseconds 1
SetSkinDirectory ""

siehe auch: Skinnable opsi-script

  • NormalizeWinst
    setzt das opsi-script Fenster auf 'normal' Modus.

  • IconizeWinst
    setzt das opsi-script Fenster auf 'minimierten' Modus.

  • MaximizeWinst
    setzt das opsi-script Fenster auf 'maximierten' Modus. // since 4.11.5.1

  • RestoreWinst
    setzt das opsi-script Fenster auf den letzten Modus.

  • AutoActivityDisplay = <boolean value> //since 4.11.4.7
    (default=false);
    Wenn true wird während des Laufs von externen Prozessen (winbatch,ShellScript,execwith Sektionen) ein (marquee) Fortschrittsbalken (der Endlos durch läuft) angezeigt.
    siehe auch: opsi-script-configs_AutoActivityDisplay

Neueinlesen der Produktliste [W/L/M]

  • reloadProductList //since 4.12.6.1
    Lädt die Produktliste vom opsi-Server nach Durchführung des Skriptes in opsi-script neu ein. Ist die Produktliste nicht leer, wird sie erneut vom opsi-script abgearbeitet. reloadProductList kann überall in der Actions-Sektion des Skriptes stehen. Die Empfehlung ist aber, der Logik entsprechend, den Befehl ans Ende der Sektion zu setzen.

String-Werte, String-Ausdrücke und String-Funktionen [W/L/M]

Ein String-Ausdruck kann

  • ein elementarer String-Wert

  • ein verschachtelter String-Wert

  • eine String-Variable

  • eine Verknüpfung von String-Ausdrücken oder

  • ein stringbasierter Funktionsaufruf sein.

Elementare String-Werte

Ein elementarer String-Wert ist jede Zeichenfolge, die von doppelten – " – oder von einfachen – ' – Anführungszeichen umrahmt ist:

'"<Zeichenfolge>"'

oder

''<Zeichenfolge>''

Zum Beispiel:

DefVar $BeispielString$
Set $BeispielString$ = "mein Text"

Strings in Strings (geschachtelte String-Werte)

Wenn in der Zeichenfolge Anführungszeichen vorkommen, muss zur Umrahmung die andere Variante des Anführungszeichens verwendet werden.

DefVar $citation$
Set $citation$ = 'he said "Yes"'

Zeichenfolgen, innerhalb derer möglicherweise bereits Schachtelungen von Anführungszeichen vorkommen, können mit
EscapeString: <Abfolge von Buchstaben>
gesetzt werden. Z.B. bedeutet

DefVar $Meta_citation$
Set $Meta_citation$ = EscapeString: Set $citation$ = 'he said "Yes"'

dass auf der Variablen $Meta_citation$ am Ende exakt die Folge der Zeichen nach dem Doppelpunkt von EscapeString (inklusive des führenden Leerzeichens) steht, also
Set $citation$ = 'he said "Yes"'

String-Verknüpfung

Strings können mit dem Pluszeichen ("+") verknüpft werden.

<String expression> + <String expression>

Beispiel:

DefVar $String1$
DefVar $String2$
DefVar $String3$
DefVar $String4$
Set $String1$ = "Mein Text"
Set $String2$ = "und"
Set $String3$ = "dein Text"
Set $String4$ =  $String1$ + " " + $String2$ + " " + $String3$

$String4$ hat dann den Wert "Mein Text und dein Text".

String-Ausdrücke

Eine String-Variable der primären Sektion "beinhaltet" einen String-Wert. Ein String-Ausdruck kann einen elementaren String vertreten. Wie ein String gesetzt und definiert wird findet sich in Abschnitt String- (oder Text-) Variable.

Die folgenden Abschnitte zeigen die Variationsmöglichkeiten von String-Funktionen.

String-Funktionen (Betriebssystem ermitteln)

  • GetOS [W/L/M]
    Die Funktion ermittelt das laufende Betriebssystem. Derzeit liefert sie einen der folgenden Werte:

    • "Windows_NT" (bei Windows NT - Windows 10)

    • "Linux"

    • "macOS"

  • GetNtVersion [W]
    (abgekündigt: use GetMSVersionInfo)
    Für ein Betriebssystem mit Windows_NT ist eine Type-Nummer und eine Sub Type-Nummer charakteristisch. GetNtVersion gibt den genauen Sub Type-Namen aus. Mögliche Werte sind
    "NT3"
    "NT4"
    "Win2k" (Windows 5.0)
    "WinXP" (Windows 5.1)
    "Windows Vista" (Windows 6)

Bei höheren (als 6.*) Windows-Versionen werden die Versionsnummern (5.2, …​ bzw. 6.0 ..) ausgegeben. Z.B. für Windows Server 2003 R2 Enterprise Edition erhält man
"Win NT 5.2" (Windows Server 2003)
In dem Fall, dass kein NT-Betriebssystem vorliegt, liefert die Funktion als Fehler-Wert:
"Kein OS vom Typ Windows NT"

  • GetMsVersionInfo [W]
    gibt für Windows Systeme die Information über die interne Version aus, z.B. produziert ein Windows 7 System das Ergebnis: "6.1". Window 11 liefert "10.0"
    siehe daher auch GetMsVersionName

Tabelle 1. Windows-Versionen
GetMsVersionInfo Windows-Version

5.0

Windows 2000

5.1

Windows XP (Home, Prof)

5.2

XP 64 Bit, 2003, Home Server, 2003 R2

6.0

Vista, 2008

6.1

Windows 7, 2008 R2

6.2

Windows 8, 2012

6.3

Windows 8.1, 2012 R2

10.0

Windows 10, Windows 11, 2016, 2019, 2022

siehe auch GetMSVersionMap

  • GetMsVersionName [W] // since 4.12.4.35
    gibt für Windows Systeme die Information über die marketing Version aus, z.B. produziert ein Windows 7 System das Ergebnis: "7.0". Window 11 liefert "11.0".

Tabelle 2. Windows Versionen
GetMsVersionName Windows Version

5.0

Windows 2000

5.1

Windows XP (Home, Prof)

5.2

XP 64 Bit, 2003, Home Server, 2003 R2

6.0

Vista, 2008

7.0

Windows 7, 2008 R2

8.0

Windows 8, 2012

8.1

Windows 8.1, 2012 R2

10.0

Windows 10, 2016, 2019

11.0

Windows 11, 2022

siehe auch GetMSVersionMap
siehe auch GetMsVersionInfo

  • getLinuxDistroType [L]
    liefert den Typ der laufenden Linuxdistribution. Mögliche Werte:

    • 'debian' (Debian / Ubuntu → use apt-get)

    • 'redhat' (RedHat / CentOs → use yum)

    • 'suse' (→ use zypper) (siehe auch getLinuxVersionMap)

  • getMacosVersionInfo : string //macOS Version Information //since 4.12.1.0 [M]
    siehe auch: getMacosVersionMap

  • GetSystemType [W/L/M]
    prüft die Architektur des installierten Betriebssystems. Im Fall eines 64 Bit-Betriebssystems ist der ausgegebene Wert '64 Bit System' ansonsten ist der Rückgabewert 'x86 System'.

  • getOSArchitecture // OS Architecture //since 4.12.4.17 prüft die Prozessor Architektur des installierten Betriebssystems. Mögliche Werte sind:

    • x86_32 (Intel / AMD X86 Architecture with 32 Bit)

    • x86_64 (Intel / AMD X86 Architecture with 64 Bit)

    • arm_64 (ARM Architecture with 64 Bit e.g Apple M1)

String-Funktionen zur Ermittlung von Umgebungs- und Aufrufparametern [W/L/M]

  • EnvVar ( <string>`)` [W/L/M]
    Die Funktion liefert den aktuellen Wert einer Umgebungsvariablen. Z.B. wird durch EnvVar ("Username") der Name des eingeloggten Users ermittelt.

  • ParamStr [W/L/M]
    Die Funktion gibt den String aus, der im Aufruf von opsi-script nach dem optionalen Kommandozeilenparameter /parameter folgt. Ist der Kommandozeilenparameter nicht verwendet, liefert ParamStr den leeren String.

  • getLastExitCode [W/L/M]
    Die String-Funktion getLastExitCode gibt den ExitCode des letzten Prozessaufrufs der vorausgehenden 'WinBatch' / 'ShellScript' / 'ExecWith' Sektion aus.
    Der Aufruf anderer opsi-script Befehle ( wie z.B. einer 'Files' Sektion) verändert den gefundenen ExitCode nicht.
    Bei 'ShellScript' und 'ExecWith' Sektionen erhalten wir den Exitcode des Interpreters. Daher muss in der Regel der gewünschte Exitcode in der Sektion explizit übergeben werden.

Beispiel:

ShellScript_exit1
set $ConstTest$ = "1"
set $CompValue$ = getLastExitCode
if ($ConstTest$ = $CompValue$)
	comment "ShellScript / ShellScript  exitcode passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "ShellScript / ShellScript  exitcode failed"
endif

[ShellScript_exit1]
rem create an errolevel= 1
VERIFY OTHER 2> NUL
echo %ERRORLEVEL%
exit %ERRORLEVEL%

  • GetUserSID(<Windows Username>`)` [W]
    gibt die SID für den übergebenen Benutzer an (möglich mit der Domäne als Vorspann in Form von DOMAIN\USER).

  • GetUsercontext [W]
    Die Funktion gibt den String aus, der im Aufruf von opsi-script nach dem optionalen Kommandozeilenparameter /usercontext folgt. Ist der Kommandozeilenparameter nicht verwendet, liefert GetUsercontext den leeren String.

Werte aus der Windows-Registry lesen und für sie aufbereiten [W]

  • getRegistryValue (<keystr>, <varstr> ) : string //since 4.12.0.16 [W]
    versucht in der Registry den als <keystr> übergebenen String-Wert als Registrykey zu öffnen und dort den Wert <varstr> zu lesen und als String zurückzugeben.
    Wenn <keystr> bzw. die Variable <varstr> nicht existieren, wird eine Warnung in das Logfile geschrieben und der Leerstring als Defaultwert zurückgegeben.
    Wenn der übergebene <varstr> leer ist, so wird der Standardwert des Keys ausgelesen.
    Die Zugriffsart ist per Default sysnative. Über den optionalen dritten Parameter kann die Zugriffsart auch explizit angegeben werden. Dabei muss der übergebene <access str> einer der folgenden Werte sein: 32bit, sysnative, 64bit.
    (siehe auch: Kapitel 64 Bit-Unterstützung)

Beispiele:

getRegistryValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell")

getRegistryValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell","64bit")

  • GetRegistryStringValue (<string>`)`
    Die Verwendung ist nicht mehr empfohlen, bitte stattdessen getRegistryValue verwenden : [getRegistryValue]
    versucht den übergebenen String-Wert als einen Ausdruck der Form
    '[KEY] X'
    zu interpretieren; im Erfolgsfall liest die Funktion den (String-) Wert zum Variablennamen 'X' des Schlüssels 'KEY' der Registry aus. Wird 'X' nicht übergeben so wird der Standardwert des Keys ausgelesen.
    Wenn KEY bzw. die Variable X nicht existieren, wird eine Warnung in das Logfile geschrieben und der Leerstring als Defaultwert zurückgegeben.

Zum Beispiel ist

GetRegistryStringValue ("[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon] Shell")

üblicherweise "Explorer.exe", das default Windows Shell Programm (aber es könnten auch andere Programme als Shell eingetragen sein.)

Zum Beispiel liefert

Set  $CompValue$ = GetRegistryStringValue32 ("[HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\test-4.0]")

wenn der Key vorher mit dem Standardeintrag 'standard entry' erzeugt wurde, den folgenden Logeintrag:

Registry started with redirection (32 Bit)
Registry key [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\test-4.0]  opened
Key closed
The value of the variable "$CompValue$" is now: "standard entry"

  • RegString(<string>`)`
    wird vor allem benötigt, um Dateinamen in die Form zu wandeln, in der sie in die Registry eingetragen werden, das heißt, jeder Backslash des Arguments der Funktion wird verdoppelt. Z.B. liefert

RegString ("c:\windows\system\")

den Wert
'"c:\\windows\\system\\"'

  • which(<command string>`) : string` //since 4.12.3.6 [W/L/M]
    Liefert den vollständigen Pfad zum Befehl <command string>, wenn dieser Befehl im gesetzten Suchpfad liegt.
    Analog dem Unix Befehl 'which'.

Werte aus Ini-Dateien lesen [W/L/M]

Es gibt – aus historischen Gründen – zwei Funktionen, um Werte aus Ini-Dateien zu lesen.

Als Ini-Datei wird dabei jede in "Sektionen" gegliederte Textdatei der Form

[Sektion1]
Varname1=Wert1
Varname2=Wert2
...
[Sektion2]
...

bezeichnet.

Die allgemeinste Funktion liest den Key-Wert aus einer Sektion der ini-Datei aus. Jeder Parameter kann als ein willkürlicher String-Ausdruck ausgegeben werden:

  • GetValueFromInifile (<file path>, <section>, <key>, <default value>, OPTIONAL <encoding>`)` : string [W/L/M]
    Die Funktion öffnet die Ini-Datei <file path> und sucht in deren Sektion <section> den <key> (auch 'Variable' genannt). Wenn diese Operation erfolgreich ist, wird der zum key gehörende Wert zurückgegeben, andernfalls <default value>.
    Ab opsi-script 4.12.6.0 unterstützt GetValueFromInifile einen fünften, optionalen Parameter <encoding>, der dabei hilft, die Ini-Datei in der richtigen Kodierung einzulesen. Wir empfehlen die Verwendung im Falle von speziellen Codierungen.

GetValueFromInifile("myfile","mysec","mykey","")
GetValueFromInifile("myfile","mysec","mykey","", "utf16-le")
  • GetIni ( <Stringausdruck> [ <character sequence> ] <character sequence> )
    (abgekündigt, bitte verwenden: GetValueFromInifile)
    Diese Funktion unterstützt eine Schreibweise, die sehr eng an die Schreibweise der Ini-Datei selbst angelehnt ist. Dabei kann allerdings nur der Dateiname durch einen String-Ausdruck dargestellt werden, die anderen Größen müssen explizit angegeben sein:
    Der <Stringausdruck> wird als Dateiname ausgelesen, der Erste <character sequence> als Sektionsname, der Zweite als Schlüsselname.
    'GetIni("MEINEINIDATEI"[meinesektion] meinkey)'
    gibt diese selben Werte zurück wie
    'GetValueFromInifile("MEINEINIDATEI","meinesektion","meinkey","")'

Produkt Properties auslesen [W/L/M]

  • GetProductProperty ( <PropertyName>, <DefaultValue>`)` [W/L/M]
    wobei <PropertyName> und <DefaultValue> String-Ausdrücke sind. Die Funktion liefert die client-spezifischen Property-Werte für das aktuell installierte Produkt aus.
    Dabei werden die aktuellen Werte beim opsi-server abgefragt.
    Kann der aktuelle Wert des Properies nicht vom opsi-server ermittelt werden (z.B. weil das Skript nicht im Kontext des opsi-service läuft), so wird der zurückzugebende Wert wie folgt ermittelt:
    Seit 4.12.4.32 wird zunächst geprüft ob sich im %ScriptPath% eine Datei properties.conf befindet. Wenn ja, wird versucht aus dieser Datei den Wert des Properties zu lesen. Dabei wird die Datei properties.conf als Liste von key=value Paaren erwartet. Im Falle eines Strings wird hier ein Eintrag vom Muster <property name>=<string value> erwartet. Beispiel: myproperty=myentry.
    Wird die Datei properties.conf nicht gefunden oder enthält den gesuchten Eintrag nicht, so wird der <default value> zurückgegeben.
    Auf diese Weise können PC-spezifische Varianten einer Installation konfiguriert werden.
    Außerhalb des opsi-service Kontextes oder wenn aus anderen Gründen der Aufruf fehlschlägt, wird der angegebene Defaultwert zurückgegeben.

Auf diese Weise können PC-spezifische Varianten einer Installation konfiguriert werden.
So wurde beispielsweise die opsi UltraVNC Netzwerk Viewer Installation mit folgenden Produkt Properties konfiguriert:

  • viewer = <yes> | <no>

  • policy = <factory_default> |

Innerhalb des Installationsskript werden die ausgewählten Werte wie folgt abgerufen

GetProductProperty("viewer", "yes")
GetProductProperty("policy", "factory_default")

Ab 4.12.4.32 ist bei Existenz der folgenden %ScriptPath%\properties.conf Datei:

propstr = from file
proplist = ["from file",huhu"]

das folgende Skript ausserhalb des opsi-service Kontextes erfolgreich:

[Actions]
DefStringList $list$
DefVar $str$

set $str$ = GetProductProperty('propstr','')
if $str$ = "from file"
	comment "got it"
else
	comment "failed"
endif

set $list$ = GetProductPropertyList('proplist','')
if takeString(0,$list$) = "from file"
	comment "got it"
else
	comment "failed"
endif

  • GetConfidentialProductProperty ( <PropertyName>, <DefaultValue>`)` //since 4.11.5.2
    verhält sich wie GetProductProperty nur das der resultierende Wert als confidential string behandelt und damit nicht gelogged wird.
    Sinnvoll um z.B. Passwörter aus einem Produktproperty abzufragen. Siehe auch: SetConfidential
    Siehe auch: asConfidential (string)
    Siehe auch: asConfidential (list)

  • IniVar(<PropertyName>`)`
    (abgekündigt: use GetProductProperty)

Informationen aus etc/hosts entnehmen [W/L/M]

  • GetHostsName(<string>`)` [W/L/M]
    liefert den Host-Namen zu einer gegebenen IP-Adresse entsprechend den Angaben in der Host-Datei (die, falls das Betriebssystem laut Environment-Variable OS "Windows_NT" ist, im Verzeichnis "%systemroot%\system32\drivers\etc\" gesucht wird, andernfalls in "C:\Windows\").

  • GetHostsAddr(<string>`)` [W/L/M]
    liefet die IP-Adresse zu einem gegebenen Host- bzw. Aliasnamen entsprechend der Auflösung in der Host-Datei.

String-Verarbeitung [W/L/M]

  • ExtractFilePath(<string>`)` [W/L/M]
    interpretiert den übergebenen String als Datei- bzw. Pfadnamen und gibt den Pfadanteil (den String-Wert bis einschließlich des letzten “\“ zurück).

Examples:

set $ConstTest$ = "C:\program files\test\"
Set $tmp$ = "C:\program files\test\test.exe"
set $CompValue$ = ExtractFilePath($tmp$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • ExtractFileExtension (<path>`) : string` //since 4.12.1 [W/L/M]
    interpretiert den übergebenen String als Datei- bzw. Pfadnamen und gibt vom Dateianteil die Extension zurück. (den String-Wert nach dem letzten “.“, mit dem Punkt).

Examples:

set $ConstTest$ = ".exe"
Set $tmp$ = "C:\program files\test\test.exe"
set $CompValue$ = ExtractFileExtension($tmp$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • ExtractFileName (<path>`) : string` //since 4.12.1 [W/L/M]
    interpretiert den übergebenen String als Datei- bzw. Pfadnamen und gibt den Dateianteil zurück. (den String-Wert nach dem letzten Pfadtrenner, ohne diesen).

Examples:

set $ConstTest$ = "test.exe"
Set $tmp$ = "C:\program files\test\test.exe"
set $CompValue$ = ExtractFileName($tmp$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • forcePathDelims (<path string>`) : <path string>` // since 4.12.4.21 [W/L/M]
    interpretiert den übergebenen String als Pfadnamen und setzt alle Pfadtrenner auf den für das laufende Betriebssystem typische Zeichen (Windows: '\', Linux und macOS: '/').

  • resolveSymlink (<file name>`) : <file name>` // since 4.12.4.21 [W/L/M]
    Ist die angegebene Datei <file name> ein symbolischer Link, so wird (rekursiv) ermittelt auf welche Datei dieser zeigt und das Ergenis zurückgegeben. Ansonsten wird der übergebene <file name> zurückgegeben.

  • [FileExists]

  • [FileOrFolderExists]

  • [DirectoryExists]

  • [fileIsSymlink]

  • StringSplit (`STRINGWERT1, STRINGWERT2, INDEX)`
    (abgekündigt: use splitString / takestring)
    siehe auch: splitString
    siehe auch: takeString

  • takeString(<index>,<list>`)` [W/L/M]
    liefert aus der String-Liste <list> den String mit dem Index <index>.
    Häufig verwendet in Kombination mit splitString : takeString(<index>, splitString(<string1>, <string2>`)`
    (String-Listenverarbeitung).
    Das Ergebnis ist, dass <string1> in Stücke zerlegt wird, die jeweils durch <string2> begrenzt sind, und das Stück mit <index> (Zählung bei 0 beginnend) genommen wird.

Zum Beispiel ergibt

takeString(3, splitString ("\\server\share\directory",  "\"))

den Wert '"share"',
denn mit '\' zerlegt sich der vorgegebene String Wert in die Folge:
Index 0 - "" (Leerstring), weil vor dem ersten "\" nichts steht
Index 1 - "" (Leerstring), weil zwischen erstem und zweitem "\" nichts steht
Index 2 - "server"
Index 3 - "share"
Index 4 - "directory"

takestring zählt abwärts, wenn der Index negativ ist, beginnend mit der Zahl der Elemente.

Deswegen bedeutet

takestring(-1, $list1$)

das letzte Element der String-Liste $list1$.
siehe auch: setStringInListAtIndex

  • SubstringBefore(<string1>, <string2>`)`
    (abgekündigt: use splitString / takestring) liefert das Anfangsstück von <string1>, wenn <string2> das Endstück ist. Z.B. hat

SubstringBefore ("C:\programme\staroffice\program\soffice.exe", "\program\soffice.exe")

den Wert '"C:\programme\staroffice"'.

  • getIndexFromListByContaining(<list> : stringlist,<search string> : string`)` : <number> : string //since 4.12.0.13 [W/L/M]
    Liefert den Index (als String) von dem ersten String in <list> in dem <search string> vorkommt. Wird <search string> nicht gefunden so wird ein Leerstring geliefert.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.
    see also : [takeFirstStringContaining]

  • takeFirstStringContaining(<list>,<search string>`)` [W/L/M]
    Liefert den ersten String einer Liste der <search string> enthält. Liefert einen leeren String, wenn kein passender String gefunden wird.
    see also : [getIndexFromListByContaining]

  • Trim(<string>`)` [W/L/M]
    Schneidet Leerzeichen am Anfang und Ende des <string> ab.

  • lower(<string>`)` [W/L/M]
    liefert <string> in Kleinbuchstaben

  • upper(<string>`)` [W/L/M]
    liefert <string> in Großbuchstaben

  • contains(<str>, <substr>`)` [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn <substr> in <str> enthalten ist. Die Funktion arbeitet case sensitive.
    Seit 4.11.3
    Beispiel:

set $ConstTest$ = "1xy451Xy451XY45"
set $CompValue$ ="xy"
if contains($ConstTest$, $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $CompValue$ ="xY"
if not(contains($ConstTest$, $CompValue$))
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • stringReplace(<string>, <oldPattern>, <newPattern>`)` [W/L/M]
    Liefert einen String in dem in <string>, <oldPattern> durch <newPattern> ersetzt ist. Die Funktion arbeitet nicht case sensitive. Die Funktion ersetzt alle Vorkommen von <oldPattern>.
    Seit 4.11.3
    Beispiel:

set $ConstTest$ = "123451234512345"
set $CompValue$ = stringReplace("1xy451Xy451XY45","xy","23")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • strLength(<string>`)` [W/L/M]
    Liefert Anzahl der Zeichen in <string>
    Seit 4.11.3
    Beispiel:

set $tmp$ = "123456789"
set $ConstTest$ = "9"
set $CompValue$ = strLength($tmp$)
if $ConstTest$ = $CompValue$
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • strPos(<string>, <sub string>`)` [W/L/M]
    Liefert die Position des ersten Vorkommens von <sub string> in <string>. Wird <sub string> nicht gefunden so liefert die Funktion "0". Die Funktion arbeitet case sensitive.
    Seit 4.11.3
    Beispiel:

set $tmp$ = "1xY451Xy451xy45"
set $ConstTest$ = "7"
set $CompValue$ = strPos($tmp$,"Xy")
if $ConstTest$ = $CompValue$
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $tmp$ = lower("1xY451Xy451xy45")
set $ConstTest$ = "2"
set $CompValue$ = strPos($tmp$,lower("xy"))
if $ConstTest$ = $CompValue$
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • strPart(<string>, <start pos>, <number of chars>`)` [W/L/M]
    Liefert einen Teilstring von <string> beginnend mit <start pos> und <number of chars> lang. Wenn ab <str pos> weniger als <number of chars> vorhanden sind, so wird der String bis zum Ende geliefert.
    Die Zählung der Zeichen beginnt mit 1.
    Seit 4.11.3
    Beispiel:

set $tmp$ = "123456789"
set $ConstTest$ = "34"
set $CompValue$ = strPart($tmp$,"3","2")
if $ConstTest$ = $CompValue$
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $tmp$ = "123456789"
set $ConstTest$ = "56789"
set $CompValue$ = strPart($tmp$, strPos($tmp$,"56"),strLength($tmp$))
if $ConstTest$ = $CompValue$
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • unquote(<string>,<quote-string>`)` [W/L/M]
    Wenn <string> mit dem Anführungszeichen <quote-string> versehen ist so liefert diese Funktion <string> ohne Anführungszeichen
    Von <quote-string> wird nur das erste Zeichen berücksichtigt, wobei führende Whitespaces ignoriert werden.
    Seit 4.11.2.1
    see also : [unquote2]

set $ConstTest$ = "b"
		set $CompValue$ = unquote("'b'", "'")
		comment "compare values"
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		comment "double quote"
		set $ConstTest$ = "b"
		set $CompValue$ = unquote('"b"', '"')
		comment "compare values"
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		comment "quote string will be trimmed and then only the first char is used"
		comment "note: brackets are different chars"
		set $ConstTest$ = "b]"
		set $CompValue$ = unquote("[b]", " [{ ")
		comment "compare values"
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		comment "not usable to remove brackets"
		set $ConstTest$ = "b]"
		set $CompValue$ = unquote("[b]", "[")
		set $CompValue$ = unquote($CompValue$,"]")
		set $CompValue$ = unquote("[b]", "]")
		set $CompValue$ = unquote($CompValue$,"[")
		set $CompValue$ = unquote(unquote("[b]", "["),"]")
		comment "compare values"
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		comment "if string not quoted it will be come back without changes"
		set $ConstTest$ = "b"
		set $CompValue$ = unquote("b", "'")
		comment "compare values"
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif

unquote2(<string>,<quote-string>) // since 4.11.5.2 [W/L/M]
Funktioniert wie unquote(<string>,<quote-string>) mit folgenden Unterschieden:
Wenn <quote-string> ein Zeichen lang ist, wird diese Zeichen als erwartetes 'Quote Zeichen' für den Anfang und das Ende von <string> genommen. Wenn <quote-string> zwei Zeichen lang ist, wird das erste Zeichen als erwartetes 'Quote Zeichen' für den Anfang und das zweite Zeichen als erwartetes 'Quote Zeichen' für den Ende von <string> genommen. Beispiel: "()"
Die Funktion liefert <string> unverändert zurück, wenn nicht sowohl für Anfang und Ende die erwarteten 'Quote Zeichen' gefunden werden.
see also : [unquote]

  • HexStrToDecStr(<string>`)` [W/L/M]
    wandelt einen String mit einem hexadezimalen Zahlwert in einen String mit dem entsprechenden decimalen Wert um. Enthält der Eingabe String führende Zeichen wie '0x' oder '$' werden diese ignoriert.
    Im Fehlerfall: Leerstring

  • DecStrToHexStr ( <decstring>, <hexlength>`)` [W/L/M]
    liefert einen <hexlength> langen String mit der hexadezimalen Darstellung von <decstring> zurück, wenn dieser die dezimale Darstellung eines Intergerwertes war. Im Fehlerfall: Leerstring

message "DecStrToHexStr"
set $ConstTest$ = "0407"
set $tmp$ = "1031"
set $CompValue$ = DecStrToHexStr($tmp$,"4")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

message "DecStrToHexStr"
set $ConstTest$ = "407"
set $tmp$ = "1031"
set $CompValue$ = DecStrToHexStr($tmp$,"2")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • base64EncodeStr(<string>`)` [W/L/M]
    liefert einen String mit dem base64 encodedten Wert von <string>.

  • base64DecodeStr(<string>`)` [W/L/M]
    liefert einen String mit dem base64 decodedten Wert von <string>.

message "base64EncodeStr"
set $ConstTest$ = "YWJjZGVm"
set $tmp$ = "abcdef"
set $CompValue$ = base64EncodeStr($tmp$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

comment ""
comment "------------------------------"
comment "Testing: "
message "base64DecodeStr"
set $ConstTest$ = "abcdef"
set $tmp$ = "YWJjZGVm"
set $CompValue$ = base64DecodeStr($tmp$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • encryptStringBlow(<keystring>,<datastring>`) : string` //since 4.11.6 [W/L/M]
    Verschlüsselt <datastring> mit dem Key <keystring> unter Verwendung von Blowfish und liefert den verschlüsselten Wert zurück.

  • decryptStringBlow(<keystring>,<datastring>`) : string` //since 4.11.6 [W/L/M]
    Entschlüsselt <datastring> mit dem Key <keystring> unter Verwendung von Blowfish und liefert den entschlüsselten Wert zurück.

set $ConstTest$ = "This string is very secret"
set $ConstTest$ = encryptStringBlow("linux123",$ConstTest$)
set $ConstTest$ = decryptStringBlow("linux123",$ConstTest$)
set $CompValue$ = "This string is very secret"
if ($ConstTest$ = $CompValue$)
	comment "cryptStringBlow passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing cryptStringBlow failed"
endif

  • md5sumFromFile(<path to file>`) : string` //since 4.11.6 [W/L/M]
    Liefert die md5summe der unter <path to file> gefundenen Datei zurück.
    Im Fehlerfall ist der Rückgabewert ein Leerstring.

set $ConstTest$ = md5sumFromFile("%ScriptPath%\test-files\crypt\dummy.msi")
set $CompValue$ = strLoadTextFile("%ScriptPath%\test-files\crypt\dummy.msi.md5")
if ($ConstTest$ = $CompValue$)
	comment "md5sumFromFile passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing md5sumFromFile failed"
endif

  • hashFromFile ( <FileName>, <Hashing Algorithm>`)` : string [W/L/M]
    Dies ist eine plattformunabhängige Hashing-Dateifunktion, die 80 Hashing-Algorithmen unterstützt.
    Folgende Werte können für <Hashing Algorithm> verwendet werden: 'Gost', 'Grindahl256', 'Grindahl512', 'HAS160', 'Haval_3_128', 'Haval_4_128', 'Haval_5_128', 'Haval_3_160', 'Haval_4_160', 'Haval_5_160', 'Haval_3_192', 'Haval_4_192', 'Haval_5_192', 'Haval_3_224', 'Haval_4_224', 'Haval_5_224', 'Haval_3_256', 'Haval_4_256', 'Haval_5_256', 'MD2', 'MD4', 'MD5', 'Panama', 'RadioGatun32', 'RadioGatun64', 'RIPEMD', 'RIPEMD128', 'RIPEMD160', 'RIPEMD256', 'RIPEMD320', 'SHA0', 'SHA1', 'SHA2_244', 'SHA2_256', 'SHA2_384', 'SHA2_512', 'SHA2_512_224', 'SHA2_512_256', 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', 'Shake_128', 'Shake_256', 'Snefru_8_128', 'Snefru_8_256', 'Tiger_3_128', 'Tiger_4_128', 'Tiger_5_128', 'Tiger_3_160', 'Tiger_4_160', 'Tiger_5_160', 'Tiger_3_192', 'Tiger_4_192', 'Tiger_5_192', 'Tiger2_3_128', 'Tiger2_4_128', 'Tiger2_5_128', 'Tiger2_3_160', 'Tiger2_4_160', 'Tiger2_5_160', 'Tiger2_3_192', 'Tiger2_4_192', 'Tiger2_5_192', 'WhirlPool', 'Blake2B', 'Blake2S', 'Keccak_224', 'Keccak_256', 'Keccak_288', 'Keccak_384', 'Keccak_512', 'GOST3411_2012_256', 'GOST3411_2012_512', 'Blake2XS', 'Blake2XB', 'Blake3_256', 'Blake3XOF', 'Blake2BP', 'Blake2SP'

encoding=utf8

[Actions]

DefVar $OS$
DefVar $FilePath$
DefVar $HashResult$
DefVar $CompValue$

; This online tool can be used to double check hash results : https://emn178.github.io/online-tools/

Set $OS$ = GetOS

switch $OS$
	case "Windows_nt"
		comment "We are running on Windows"
		Set $FilePath$ = "C:\opsi\crypt\dummy.msi"
	endcase
	case "Linux"
		comment "We are running on Linux"
		Set $FilePath$ = "/home/opsi/crypt/dummy.msi"
	endcase
	case "macos"
		comment "We are running on macOS"
		Set $FilePath$ = "/home/opsi/crypt/dummy.msi"
	endcase
endswitch

if FileExists($FilePath$)

    comment "Testing HashFromFile - MD5"
    Set $HashResult$ = HashFromFile($FilePath$, "MD5")
    Set $CompValue$ = md5sumFromFile($FilePath$)
    if ($HashResult$ = $CompValue$)
        comment "Testing HashFromFile - MD5 passed"
    else
        LogWarning "Testing HashFromFile - MD5 failed"
    endif

else
	LogWarning "File not found"
endif

  • strLoadTextFile ( <filename> ) //since 4.11.4.6 [W/L/M]
    liefert die erste Zeile von <filename> als String.
    siehe auch : [strLoadTextFileWithEncoding]

  • GetShortWinPathName(<longpath string>) //since 4.11.5.2 [W]
    Liefert den Shortpath (8.3) von <longpath string>. Lässt sich für <longpath string> kein Shortpath finden, so liefert die Funktion einen leeren String. + Beispiel: GetShortWinPathName("C:\Program Files (x86)") liefert "C:\PROGRA~2"

Weitere String-Funktionen

  • RandomStr [W/L/M]
    liefert Zufallsstrings (der Länge 10), die aus Klein- und Großbuchstaben sowie Ziffern bestehen. Genauer: 2 Kleinbuchstaben, 2 Großbuchstaben, 2 Sonderzeichen und 4 Ziffern. Die möglichen Sonderzeichen sind:
    '!','$','(',')','*','+','/',';','=','?','[',']','{','}','ß','~','§','°'

  • RandomStrWithParameters (<minLength>, <nLowerCases>, <nUpperCases>,<nDigits>,<nSpecialChars>): string [W/L/M]
    liefert Zufallsstring (z.B. um Passwörter zu generieren), dessen Eigenschaften sich durch die mitgegebenen Paramter wie folgt konfigurieren lässt:

    • <minLength>: Länge des Strings,

    • <nLowerCases>: Anzahl der Kleinbuchstaben,

    • <nUpperCases>: Anzahl der Großbuchstaben,

    • <nDigits>: Anzahl der Ziffern,

    • <nSpecialChars>: Anzahl der Sonderzeichen.
      Mögliche Sonderzeichen sind: '!','$','(',')','*','+','/',';','=','?','[',']','{','}','ß','~','§','°'

  • RandomIntStr(<number str>) : string [W/L/M]
    liefert eine zufällige Zahl zwischen 0 und <number str> als String.

  • CompareDotSeparatedNumbers(<string1>, <string2>) [W/L/M]
    vergleicht zwei Strings vom Typ <zahl>[.<zahl>[.<zahl>[.<zahl>]]] und liefert "0" bei Gleichheit, "1" wenn string1 größer ist und "-1" wenn string1 kleiner ist.
    siehe auch boolsche funktion CompareDotSeparatedNumbers : [CompareDotSeparatedNumbers_bool]
    see also: [CompareDotSeparatedStrings_str]

Beispiel:
Der Code:

	comment "Testing: "
	message "CompareDotSeparatedNumbers"
	set $string1$ = "1.2.3.4.5"
	set $string2$ = "1.2.3.4.5"
	set $ConstTest$ = "0"
	set $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is equal to "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.2.31.4.5"
	set $string2$ = "1.2.13.4.5"
	set $ConstTest$ = "1"
	set $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is higher then "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.2.3.4.5"
	set $string2$ = "1.2.13.4.5"
	set $ConstTest$ = "-1"
	set $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is lower then "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	comment ""
	comment "------------------------------"
	comment "Testing: "
	message "CompareDotSeparatedStrings"
	set $string1$ = "1.a.b.c.3"
	set $string2$ = "1.a.b.c.3"
	set $ConstTest$ = "0"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is equal to "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

liefert folgenden Log:

comment: Testing:
message CompareDotSeparatedNumbers

Set  $string1$ = "1.2.3.4.5"
  The value of the variable "$string1$" is now: "1.2.3.4.5"

Set  $string2$ = "1.2.3.4.5"
  The value of the variable "$string2$" is now: "1.2.3.4.5"

Set  $ConstTest$ = "0"
  The value of the variable "$ConstTest$" is now: "0"

Set  $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "0"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.2.3.4.5 is equal to 1.2.3.4.5

Else
EndIf

Set  $string1$ = "1.2.31.4.5"
  The value of the variable "$string1$" is now: "1.2.31.4.5"

Set  $string2$ = "1.2.13.4.5"
  The value of the variable "$string2$" is now: "1.2.13.4.5"

Set  $ConstTest$ = "1"
  The value of the variable "$ConstTest$" is now: "1"

Set  $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.2.31.4.5 is higher then 1.2.13.4.5

Else
EndIf

Set  $string1$ = "1.2.3.4.5"
  The value of the variable "$string1$" is now: "1.2.3.4.5"

Set  $string2$ = "1.2.13.4.5"
  The value of the variable "$string2$" is now: "1.2.13.4.5"

Set  $ConstTest$ = "-1"
  The value of the variable "$ConstTest$" is now: "-1"

Set  $CompValue$ = CompareDotSeparatedNumbers($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "-1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.2.3.4.5 is lower then 1.2.13.4.5

Else
EndIf

  • CompareDotSeparatedStrings (<string1>, <string2>`)` [W/L/M]
    vergleicht zwei Strings vom Typ <string>.<string>[.<string>[.<string>]] und liefert "0" bei Gleichheit, "1" wenn string1 größer ist und "-1" wenn string1 kleiner ist. Der Vergleich ist nicht Case sensitive.
    siehe auch boolsche funktion CompareDotSeparatedStrings : [CompareDotSeparatedStrings_bool]
    see also : [CompareDotSeparatedNumbers_bool]

Beispiel:
Der Code:

	comment "Testing: "
	message "CompareDotSeparatedStrings"
	set $string1$ = "1.a.b.c.3"
	set $string2$ = "1.a.b.c.3"
	set $ConstTest$ = "0"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is equal to "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.a.b.c.3"
	set $string2$ = "1.A.B.C.3"
	set $ConstTest$ = "0"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is equal to "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.a.cb.c.3"
	set $string2$ = "1.a.b.c.3"
	set $ConstTest$ = "1"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is higher then "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.a.ab.c.3"
	set $string2$ = "1.a.b.c.3"
	set $ConstTest$ = "-1"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is lower then "+$string2$
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.2.13.4.5"
	set $string2$ = "1.2.3.4.5"
	set $ConstTest$ = "-1"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is lower then "+$string2$
		comment "using CompareDotSeparatedStrings give wrong results on numbers"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $string1$ = "1.2.3.4.5"
	set $string2$ = "1.2.13.4.5"
	set $ConstTest$ = "1"
	set $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
	if ($ConstTest$ = $CompValue$)
		comment "passed"
		comment $string1$+" is higher then "+$string2$
		comment "using CompareDotSeparatedStrings give wrong results on numbers"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

liefert folgenden Log:

comment: Testing:
message CompareDotSeparatedStrings

Set  $string1$ = "1.a.b.c.3"
  The value of the variable "$string1$" is now: "1.a.b.c.3"

Set  $string2$ = "1.a.b.c.3"
  The value of the variable "$string2$" is now: "1.a.b.c.3"

Set  $ConstTest$ = "0"
  The value of the variable "$ConstTest$" is now: "0"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "0"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.a.b.c.3 is equal to 1.a.b.c.3

Else
EndIf

Set  $string1$ = "1.a.b.c.3"
  The value of the variable "$string1$" is now: "1.a.b.c.3"

Set  $string2$ = "1.A.B.C.3"
  The value of the variable "$string2$" is now: "1.A.B.C.3"

Set  $ConstTest$ = "0"
  The value of the variable "$ConstTest$" is now: "0"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "0"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.a.b.c.3 is equal to 1.A.B.C.3

Else
EndIf

Set  $string1$ = "1.a.cb.c.3"
  The value of the variable "$string1$" is now: "1.a.cb.c.3"

Set  $string2$ = "1.a.b.c.3"
  The value of the variable "$string2$" is now: "1.a.b.c.3"

Set  $ConstTest$ = "1"
  The value of the variable "$ConstTest$" is now: "1"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.a.cb.c.3 is higher then 1.a.b.c.3

Else
EndIf

Set  $string1$ = "1.a.ab.c.3"
  The value of the variable "$string1$" is now: "1.a.ab.c.3"

Set  $string2$ = "1.a.b.c.3"
  The value of the variable "$string2$" is now: "1.a.b.c.3"

Set  $ConstTest$ = "-1"
  The value of the variable "$ConstTest$" is now: "-1"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "-1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.a.ab.c.3 is lower then 1.a.b.c.3

Else
EndIf

Set  $string1$ = "1.2.13.4.5"
  The value of the variable "$string1$" is now: "1.2.13.4.5"

Set  $string2$ = "1.2.3.4.5"
  The value of the variable "$string2$" is now: "1.2.3.4.5"

Set  $ConstTest$ = "-1"
  The value of the variable "$ConstTest$" is now: "-1"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "-1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.2.13.4.5 is lower then 1.2.3.4.5
  comment: using CompareDotSeparatedStrings give wrong results on numbers

Else
EndIf

Set  $string1$ = "1.2.3.4.5"
  The value of the variable "$string1$" is now: "1.2.3.4.5"

Set  $string2$ = "1.2.13.4.5"
  The value of the variable "$string2$" is now: "1.2.13.4.5"

Set  $ConstTest$ = "1"
  The value of the variable "$ConstTest$" is now: "1"

Set  $CompValue$ = CompareDotSeparatedStrings($string1$, $string2$)
  The value of the variable "$CompValue$" is now: "1"

If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
  comment: 1.2.3.4.5 is higher then 1.2.13.4.5
  comment: using CompareDotSeparatedStrings give wrong results on numbers

Else
EndIf

  • getDiffTimeSec [W/L/M]
    liefert einen String mit dem ganzahligen Wert der vergangenen Sekunden seit dem letzten Aufruf von marktime.
    Seit Version 4.11.3.1

  • timeStampAsFloatStr : string (Floating Number - format: 'days.decimal days') //since 4.11.6 [W/L/M]
    Liefert einen aktuellen Timestamp als Fließkommazahlstring. Dabei ist Zahl vor dem Komma die Tage seit dem 30. Dezember 1899. Nach dem Komma kommt die Zeit in Bruchteilen des Tages.
    Just for Fun: Warum nicht der 31. Dezember 1899: ?
    siehe http://www.delphibasics.co.uk/RTL.asp?Name=TDateTime

  • SidToName(<well known sid>`)` [W]
    liefert einen String mit dem lokalisierten Namen der mit <well known sid> bezeichneten Gruppe. Zum Beispiel für 'S-1-5-32-544' je nach Lokalisierung des Betriebsystems 'Administratoren' oder 'Administrators'.
    Seit Version 4.11.3.1

  • GetMyIpByTarget(<target ip addr>`)` [W/L/M]
    liefert einen String mit der IP-Adresse des Interfaces, welches das Betriebssystem verwenden wird, wenn es versucht <target ip addr> zu erreichen. Diese Funktion liefert sicherer den korrekten Wert als die Verwendung der Konstante %IPAddress%.
    Seit Version 4.11.3.1
    Beispiel:

set $CompValue$ = getMyIpByTarget("%opsiServer%")

siehe auch : [GetIpByName]
siehe auch : IPAddress

  • GetIpByName(<ip addr / ip name>`)` [W/L/M]
    liefert die IP-Adresse des mit <ip addr / ip name> angegebenen Rechners
    Seit Version 4.11.3.2

set $ConstTest$ = "%IPAddress%"
		set $string1$ = "%IPAddress%"
		set $CompValue$ = getIpByName($string1$)
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		set $CompValue$ = getIpByName("%HostID%")
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif
		set $CompValue$ = getIpByName("%PCName%")
		if ($ConstTest$ = $CompValue$)
			comment "passed"
		else
			set $TestResult$ = "not o.k."
			LogWarning "failed"
		endif

siehe auch : [GetMyIpByTarget]

  • stringinput(< message str>,< boolstr confidential>`) : string` //since 4.12.1.2 [W/L/M]
    Interaktive Funktion.
    Fragt interaktiv unter Ausgabe von < message str> einen String ab und liefert diesen zurück.
    Wenn < boolstr confidential> = "true" ist, so wird die interaktive Eingabe mit "*" maskiert. Im grafischen Modus gipt es einen Button mit einem 'Auge' Symbol, der die Eingabe lesbar macht.
    Wenn < boolstr confidential> = "true" ist, so ist die Eingabe unmaskiert.
    Im grafischen Modus erfolgt die Abfrage im Rahmen eines modalen Fensters, ansonsten auf der Kommandozeile.

  • replaceOpsiConstants(<string>`) : string` //since 4.12.3.6 [W/L/M]
    Ersetzt alle Vorkommen von opsi Konstanten in '<string>' durch ihre Werte und gibt der resultierenden String zurück.
    siehe auch : [replaceOpsiConstants_list]

(String-) Funktionen für die Lizenzverwaltung [W/L/M]

  • DemandLicenseKey(`poolId [, productId [,windowsSoftwareId]])`
    Über die opsi-Webservicefunktion getAndAssignSoftwareLicenseKey wird vom opsi Service abgefragt, ob es für den Computer eine reservierte Lizenz gibt.

Die Datenbasis auf Grund deren die Lizenzen vergeben werden, kann die Computer ID sein, die Produkt ID oder die Windows Software ID (diese Möglichkeiten bestehen, wenn diese Vorgaben in der Lizenzkonfiguration definiert ist).

poolId, productId, windowsSoftwareId sind Strings (bzw. String-Ausdrücke). Wenn die licensePoolId nicht explizit gesetzt ist, bleibt der erste Parameter ein leerer String "". Das gilt auch für die anderen IDs – sofern diese nicht näher definiert werden.

Die Funktion gibt den Lizenzschlüssel zurück, der aus der Datenbasis ausgewählt wurde.

Beispiele:

set $mykey$ = DemandLicenseKey ("pool_office2007")
set $mykey$ = DemandLicenseKey ("", "office2007")
set $mykey$ = DemandLicenseKey ("", "", "{3248F0A8-6813-11D6-A77B}")

  • FreeLicense(`poolId [, productId [,windowsSoftwareId]]])`
    Über die Funktion freeSoftwareLicense des opsi Services wird die aktuell belegte Lizenz frei gegeben. Diese Syntax ist analog zum Syntax DemandLicenseKey zu sehen: Beispiel:

DefVar $opsiresult$
set $opsiresult$ = FreeLicense("pool_office2007")

'$opsiresult$' wird zu einem leeren String umgesetzt, wenn kein Fehler auftritt und wenn eine Fehler auftritt, wird der Fehlertext ausgegeben.

Abrufen der Fehlerinformationen von Serviceaufrufen [W/L/M]

  • getLastServiceErrorClass
    liefert einen String zurück, welcher den Namen der Fehlerklasse des letzten Serviceaufrufs zurück. Wenn der letzte Serviceaufruf keine Fehlermeldung verursacht hat, gibt die Funktion den Wert "None" zurück.

  • getLastServiceErrorMessage
    liefert einen String zurück, welcher die Fehlermeldung des letzten Serviceaufrufs entspricht. Wenn der letzte Serviceaufruf keine Fehlermeldung verursacht hat, gibt die Funktion den Wert "None" zurück.

Da die Nachrichtenstrings sich immer mal wieder ändern, wird für die Logik des Grundskriptes die Verwendung des Klassennamen empfohlen.

Beispiel:

if getLastServiceErrorClass = "None"
    comment "kein Fehler aufgetreten"
endif

Verarbeitung von String-Listen [W/L/M]

Eine String-Liste (oder ein String-Listenwert) ist eine Abfolge von String-Werten. Der Wert einer String-Liste umfasst also alle Strings dieser Liste. Für diese Werte gibt es die Variable der String-Listen. Seit 4.12.4.32 können auch optional initiale Werte mitgegeben werden. Sie werden wie folgt definiert

DefStringList <VarName> [= <inital value>]

Ein String-Listenwert wird einer String-Listenvariable zugeteilt:

Set <VarName> = <StringListValue>

String-Listenwert (string list expressions) können auf unterschiedliche weise entstehen:

  • Aus einer Funktion welche eine String-Liste liefert

  • Aus einer String-Liste Variable

  • Seit 4.12.4.32 aus einem String im json style, welche als String-Liste gelesen werden kann

Für die folgenden Beispiele sei generell eine String-Listen-Variable '$list1$' definiert:

DefStringList $list1$

Seit 4.12.4.32 ist die einfachste Methode die Verwendung eines Strings im json style, welche als String-Liste gelesen werden kann:
["<string>"]
Beispiel:
set $list1$ = '["ab","cd","de"]'

Das selbe Ergebnis kann mit der Funktion CreateStringlist erreicht werden:
set $list1$ = createstringlist("ab","cd","de")

String-Listen können auf vielfältige Weise erzeugt bzw. „eingefangen“ werden. Sie werden in String-Listen-Ausdrücken verarbeitet. Der einfachste String-Listen-Ausdruck ist das Setzen eines (String-Listen-) Wertes auf eine (String-Listen-) Variable.

Diese Variable ($list1$) lässt sich auf ganz unterschiedliche Weise mit Inhalten füllen: Wenn wir Variablen mit <String0>, <StringVal>, .. benennen bedeutet das, dass diese für jeden belieben String-Ausdruck stehen können.

Wir beginnen mit einer speziellen und sehr hilfreichen Art von String-Listen: Funktionen – also aufgerufene Hashes oder zugehörige Arrays – welche aus einer Zeile von dem Aufruf 'KEY=VALUE' stammen. Tatsache ist, dass jede Funktion eine Funktion ermitteln sollte, welche einen VALUE mit einem KEY assoziiert. Jeder KEY sollte in dem ersten Abschnitt einer Zeile auftreten (während verschiedene KEYs mit identischen VALUE verbunden sein können).

Info Maps

  • getHWBiosInfoMap //since 4.11.4 [L/W]
    Liefert Infos zur Hardware aus dem BIOS Keys sind (mit Beispiel Werten):

bios.Vendor=Award Software International, Inc.
bios.Version=F9b
bios.Start Segment=E000
bios.ReleaseDate=07/08/2010
bios.RomSize=1024 k
sysinfo.Manufacturer=Gigabyte Technology Co., Ltd.
sysinfo.Product Name=GA-MA78GM-UD2H
sysinfo.Version=
sysinfo.Serial Number=
sysinfo.UUID=303032343144323730434336FFFFFFFF
sysinfo.SKU Number=
sysinfo.Family=
board.Manufacturer=Gigabyte Technology Co., Ltd.
board.Product=GA-MA78GM-UD2H
board.Version=x.x
board.Serial Number=
board.Asset Tag=
board.Feature Flags=01101001
board.Location in Chassis=
board.Chassis Handle=6261
board.Board Type=79 Unknown
board.Number of Contained Object Handles=116
enclosure.Manufacturer=Gigabyte Technology Co., Ltd.
enclosure.Version=
enclosure.Serial Number=
enclosure.Asset Tag Number=
enclosure.Type=Desktop
enclosure.Power Supply State=Unknown
enclosure.BootUp State=Unknown

  • getMacosVersionMap : stringlist //macOS Version map //since 4.12.1.0 [M]

Beispiel:

Set  $macOSinfomap$ = getMacosVersionMap

ergibt (zum Beispiel) folgenden log:

The value of the variable "$macOSinfomap$" is now:
(string   0)Release=11.0
(string   1)Build=20A5364e
(string   2)kernel name=Darwin
(string   3)node name=vmmac1100onmm1.uib.local
(string   4)kernel release=20.1.0
(string   5)kernel version=Darwin Kernel Version 20.1.0: Fri Aug 28 20:45:30 PDT 2020; root:xnu-7195.40.65.0.2~61/RELEASE_X86_64
(string   6)machine=x86_64
(string   7)processor=i386
(string   8)operating system=macOS

  • getLinuxVersionMap //since 4.11.4 [L]
    Keys sind (mit Beispiel Werten):

Distributor ID=Ubuntu
Description=Ubuntu 12.04.2 LTS
Release=12.04
Codename=precise
kernel name=Linux
node name=detlefvm05
kernel release=3.2.0-40-generic-pae
kernel version=#64-Ubuntu SMP Mon Mar 25 21:44:41 UTC 2013
machine=i686
processor=athlon
hardware platform=i386
operating system=GNU/Linux
SubRelease

  • getMSVersionMap [W]
    fragt die Betriebssysteminformationen lokal ab und schreibt die Informationen in eine String-Liste.

siehe auch GetMsVersionInfo siehe auch GetMsVersionName

Im Moment existieren folgende Schlüssel

  • major_version

  • minor_version

  • build_number

  • platform_id

  • csd_version

  • service_pack_major

  • service_pack_minor

  • suite_mask

  • product_type_nr

  • 2003r2

  • ReleaseID

  • prodInfoText

  • prodInfoNumber

Die Ergebnisse von suite_mask und product_type_nr sind Zahlen, die aus bitweisen-or-Verknüpfungen der folgenden Werte gebildet sein können.

product_type_nr

0x0000001 (VER_NT_WORKSTATION)
0x0000002 (VER_NT_DOMAIN_CONTROLLER)
0x0000003 (VER_NT_SERVER)

SuiteMask

0x00000001 (VER_SUITE_SMALLBUSINESS)
0x00000002 (VER_SUITE_ENTERPRISE)
0x00000004 (VER_SUITE_BACKOFFICE)
0x00000008 (VER_SUITE_COMMUNICATIONS)
0x00000010 (VER_SUITE_TERMINAL)
0x00000020 (VER_SUITE_SMALLBUSINESS_RESTRICTED)
0x00000040 (VER_SUITE_EMBEDDEDNT)
0x00000080 (VER_SUITE_DATACENTER)
0x00000100 (VER_SUITE_SINGLEUSERTS)
0x00000200 (VER_SUITE_PERSONAL)
0x00000400 (VER_SUITE_SERVERAPPLIANCE)
  • ReleaseID. Der dazugehörige Wert gibt die Release von 'Windows 10' an wie z.B. '1511'.
    Leerstring wenn nicht vorhanden.
    Der Wert kommt aus der Registry: "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ReleaseID"

  • prodInfoText.Der dazugehörige Wert gibt die verwendeten Windows Edition als String an wie z.B. 'PRODUCT_PROFESSIONAL'.

  • prodInfoNumber.Der dazugehörige Wert gibt die verwendeten Windows Edition als Zahl an wie z.B. '48'.

ProdInfoNumber und ProdInfoText

DecNum

HexNum

Text

00

00

An unknown product

01

01

Ultimate Edition"

02

02

Home Basic Edition

03

03

Home Premium Edition

04

04

Enterprise Edition

05

05

Home Basic Edition

06

06

Business Edition

07

07

Server Standard Edition (full installation)

08

08

Server Datacenter Edition (full installation)

09

09

Small Business Server

10

0A

Server Enterprise Edition (full installation)

11

0B

Starter Edition

12

0C

Server Datacenter Edition (core installation)

13

0D

Server Standard Edition (core installation)

14

0E

Server Enterprise Edition (core installation)

15

0F

Server Enterprise Edition for Itanium-based Systems

16

10

Business Edition

17

11

Web Server Edition (full installation)

18

12

Cluster Server Edition

19

13

Home Server Edition

20

14

Storage Server Express Edition

21

15

Storage Server Standard Edition

22

16

Storage Server Workgroup Edition

23

17

Storage Server Enterprise Edition

24

18

Server for Small Business Edition

25

19

Small Business Server Premium Edition

26

1A

PRODUCT_HOME_PREMIUM_N

27

1B

PRODUCT_ENTERPRISE_N

28

1C

PRODUCT_ULTIMATE_N

29

1D

PRODUCT_WEB_SERVER_CORE

30

1E

Windows Essential Business Server Management Server

31

1F

Windows Essential Business Server Security Server

32

20

Windows Essential Business Server Messaging Server

33

21

Server Foundation

34

22

PRODUCT_HOME_PREMIUM_SERVER

35

23

PRODUCT_SERVER_FOR_SMALLBUSINESS_V

36

24

Server Standard Edition without Hyper-V (full installation)

37

25

Server Datacenter Edition without Hyper-V (full installation)

38

26

Server Enterprise Edition without Hyper-V (full installation)

39

27

Server Datacenter Edition without Hyper-V (core installation)

40

28

Server Standard Edition without Hyper-V (core installation)

41

29

Server Enterprise Edition without Hyper-V (core installation)

48

30

PRODUCT_PROFESSIONAL

49

31

PRODUCT_PROFESSIONAL_N

50

32

PRODUCT_SB_SOLUTION_SERVER

51

33

PRODUCT_SERVER_FOR_SB_SOLUTIONS

52

34

PRODUCT_STANDARD_SERVER_SOLUTIONS

53

35

PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE

54

36

PRODUCT_SB_SOLUTION_SERVER_EM

55

37

PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM

56

38

PRODUCT_SOLUTION_EMBEDDEDSERVER

57

39

PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE

59

3B

PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT

60

3C

PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL

61

3D

PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC

62

3E

PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC

63

3F

PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE

64

40

PRODUCT_CLUSTER_SERVER_V

65

41

PRODUCT_EMBEDDED

66

42

PRODUCT_STARTER_E

67

43

PRODUCT_HOME_BASIC_E

68

44

PRODUCT_HOME_PREMIUM_E

69

45

PRODUCT_PROFESSIONAL_E

70

46

PRODUCT_ENTERPRISE_E

71

47

PRODUCT_ULTIMATE_E

72

48

PRODUCT_ENTERPRISE_EVALUATION

84

54

PRODUCT_ENTERPRISE_N_EVALUATION

98

62

PRODUCT_CORE_N

99

63

PRODUCT_CORE_COUNTRYSPECIFIC

100

64

PRODUCT_CORE_SINGLELANGUAGE

101

65

PRODUCT_CORE

121

79

PRODUCT_EDUCATION

122

7A

PRODUCT_EDUCATION_N

125

7D

Windows Enterprise 2015 LTSB

126

7E

Windows Enterprise 2015 LTSB N

129

81

Windows Enterprise 2015 LTSB Evaluation

130

82

Windows Enterprise 2015 LTSB N Evaluation

Beispiel:
Der Code

DefStringList $INST_Resultlist$
DefStringList $INST_Resultlist2$

message "getMSVersionMap"
comment "get value by winst function"
set $INST_Resultlist$ = getMSVersionMap

Liefert z.B. im Log:

message getMSVersionMap
comment: get value by winst function

Set  $INST_Resultlist$ = getMSVersionMap
    retrieving strings from getMSVersionMap [switch to loglevel 7 for debugging]
        (string   0)major_version=5
        (string   1)minor_version=1
        (string   2)build_number=2600
        (string   3)platform_id=2
        (string   4)csd_version=Service Pack 3
        (string   5)service_pack_major=3
        (string   6)service_pack_minor=0
        (string   7)suite_mask=256
        (string   8)product_type_nr=1
        (string   9)2003r2=false

  • getFileInfoMap( <file name> ) : stringlist [W]

  • getFileInfoMap32( <file name> ) : stringlist //since 4.11.6.6 [W]

  • getFileInfoMap64( <file name> ) : stringlist //since 4.11.6.6 [W]

  • getFileInfoMapSynative( <file name> ) : stringlist //since 4.11.6.6 [W]

findet die Versionsinformationen, die im FILENAME verborgen sind und schreibt sie in eine String-Listen Funktion.

Zur Zeit existieren folgende Schlüssel,

  • Comments

  • CompanyName

  • FileDescription

  • FileVersion

  • InternalName

  • LegalCopyright

  • LegalTrademarks

  • OriginalFilename

  • PrivateBuild

  • ProductName

  • ProductVersion

  • SpecialBuild

  • Language name <index>

  • Language ID <index>

  • file version with dots

  • file version

  • product version

Verwendung: Wenn wir folgendes Skriptteil definieren und aufrufen

DefStringList FileInfo
DefVar $InterestingFile$
Set $InterestingFile$ = "c:\program files\my program.exe"
set  FileInfo = getFileInfoMap($InterestingFile$)

bekommen wir die Werte, die zum Schlüssel "FileVersion" dazugehören, über den Aufruf

DefVar $result$
set $result$ = getValue("FileVersion", FileInfo)

ausgegeben (für die Funktion getValue vgl. Abschnitt (Wieder-) Gewinnen von Einzelstrings aus String-Listen oder Dateien).

Beispiel:
Der Code:

set $InterestingFile$ = "%OpsiScriptDir%\winst.exe"
if not (FileExists($InterestingFile$))
	set $InterestingFile$ = "%OpsiScriptDir%\winst32.exe"
endif
set $INST_Resultlist$ = getFileInfoMap($InterestingFile$)

liefert z.B. im Log

Set  $InterestingFile$ = "N:\develop\delphi\winst32\trunk\winst.exe"
  The value of the variable is now: "N:\develop\delphi\winst32\trunk\winst.exe"

If
    Starting query if file exist ...
  FileExists($InterestingFile$)   <<< result true
  not (FileExists($InterestingFile$))   <<< result false
Then
EndIf

Set  $INST_Resultlist$ = getFileInfoMap($InterestingFile$)
    retrieving strings from getFileInfoMap [switch to loglevel 7 for debugging]
        (string   0)Language name 0=Deutsch (Deutschland)
        (string   1)Language ID 0=1031
        (string   2)file version=1125942857039872
        (string   3)file version with dots=4.10.8.0
        (string   4)product version=1125942857039872
        (string   5)Comments=
        (string   6)CompanyName=uib gmbh (www.uib.de)
        (string   7)FileDescription=opsi.org
        (string   8)FileVersion=4.10.8.0
        (string   9)InternalName=
        (string  10)LegalCopyright=uib gmbh under GPL
        (string  11)LegalTrademarks=opsi
        (string  12)OriginalFilename=
        (string  13)PrivateBuild=
        (string  14)ProductName=opsi-script
        (string  15)ProductVersion=4.0
        (string  16)SpecialBuild=

  • getLocaleInfoMap [W]
    fragt die Systeminformationen lokal ab und schreibt die Informationen in eine String-Liste.

Im Moment existieren folgende Schlüssel

  • language_id_2chars (eine „Zwei-Buchstaben“ Namensangabe der default Systemsprache)

  • language_id (eine „Drei-Buchstaben“ Namensangabe der default Systemsprache inklusive der Sprachenuntertypen)

  • localized_name_of_language

  • English_name_of_language

  • abbreviated_language_name

  • native_name_of_language

  • country_code

  • localized_name_of_country

  • English_name_of_country

  • abbreviated_country_name

  • native_name_of_country

  • default_language_id

  • default_language_id_decimal

  • default_country_code

  • default_oem_code_page

  • default_ansi_code_page

  • default_mac_code_page

  • system_default_language_id Hexadecimal Windows locale Id

  • system_default_posix Sprache_Region (Posix Style)

  • system_default_lang_region Sprache-Region (BCP 47 Style)

Die system_default Keys geben Informationen über die Sprache des installierten Betriebssystems. Die anderen Keys geben Informationen über die Lokalisierung der GUI.

Beispiel:
Der Code:

message "Locale Infos"
set  $INST_Resultlist$ = getLocaleInfoMap

liefert z.B. folgendes Log:

message Locale Infos

Set  $INST_Resultlist$ = getLocaleInfoMap
    retrieving strings from getLocaleInfoMap [switch to loglevel 7 for debugging]
        (string   0)language_id_2chars=DE
        (string   1)language_id=DEU
        (string   2)localized_name_of_language=Deutsch (Deutschland)
        (string   3)English_name_of_language=German
        (string   4)abbreviated_language_name=DEU
        (string   5)native_name_of_language=Deutsch
        (string   6)country_code=49
        (string   7)localized_name_of_country=Deutschland
        (string   8)English_name_of_country=Germany
        (string   9)abbreviated_country_name=DEU
        (string  10)native_name_of_country=Deutschland
        (string  11)default_language_id=0407
        (string  12)default_language_id_decimal=1031
        (string  13)default_country_code=49
        (string  14)default_oem_code_page=850
        (string  15)default_ansi_code_page=1252
        (string  16)default_mac_code_page=10000
        (string  17)system_default_language_id=0407
        (string  18)system_default_posix=de_DE
        (string  19)system_default_lang_region=de-DE

Verwendung: Wenn wir den Aufruf wie folgt definieren

DefStringList $languageInfo$
set  $languageInfo$ = getLocaleInfoMap

bekommen wir den Wert mit dem KEY "language_id_2chars" über den Aufruf

DefVar $result$
set $result$ = getValue("language_id_2chars", $languageInfo$)

(für die Funktion getValue vgl. Abschnitt (Wieder-) Gewinnen von Einzelstrings aus String-Listen oder Dateien). Wir können nun Skripte mit folgender Konstruktion verwenden

if getValue("language_id_2chars", languageInfo) = "DE"
    ; installiere deutsche Version
else
   if getValue("language_id_2chars", languageInfo) = "EN"
    ; installiere englische Version
   endif
endif

Die Funktion GetLocaleInfoMap ersetzt die ältere GetLocaleInfo, da diese Werte ausliest, die schwierig zu interpretieren sind:

  • getLocaleInfo
    (abgekündigt): Bitte GetLocaleInfoMap verwenden.

  • getProductMap // since 4.11.2.4 [W/L/M]
    liefert eine info map über das opsi product welches gerade installiert wird.
    Die Funktion arbeitet nur korrekt, wenn opsi-script im opsi service mode aufgerufen wird.
    keys sind: id, name, description, advice, productversion, packageversion, priority, installationstate, lastactionrequest, lastactionresult, installedversion, installedpackage, installedmodificationtime, actionrequest

Beispiel:

set $INST_Resultlist$ = getProductMap
set $string1$ = getValue("id", $INST_Resultlist$)

liefert z.B. folgenden log:

Set  $INST_Resultlist$ = getProductMap
    retrieving strings from getProductMap [switch to loglevel 7 for debugging]
        (string   0)id=opsi-script-test
        (string   1)name=opsi-script test
        (string   2)description=Test  and example script for opsi-script
        (string   3)advice=
        (string   4)productversion=4.11.2
        (string   5)packageversion=1
        (string   6)priority=0
        (string   7)installationstate=unknown
        (string   8)lastactionrequest=setup
        (string   9)lastactionresult=successful
        (string  10)installedversion=4.11.2
        (string  11)installedpackage=1
        (string  12)installedmodificationtime=
        (string  13)actionrequest=setup


Set  $string1$ = getValue("id", $INST_Resultlist$)
    retrieving strings from $INST_Resultlist$ [switch to loglevel 7 for debugging]
        (string   0)id=opsi-script-test
        (string   1)name=opsi-script test
        (string   2)description=Test  and example script for opsi-script
        (string   3)advice=
        (string   4)productversion=4.11.2
        (string   5)packageversion=1
        (string   6)priority=0
        (string   7)installationstate=unknown
        (string   8)lastactionrequest=setup
        (string   9)lastactionresult=successful
        (string  10)installedversion=4.11.2
        (string  11)installedpackage=1
        (string  12)installedmodificationtime=
        (string  13)actionrequest=setup

  The value of the variable "$string1$" is now: "opsi-script-test"

  • editmap(< strlist>`) : stringlist` //since 4.12.1.2 [W/L/M]
    Interaktive Funktion.
    Zeigt die übergebene < strlist> als <key>=<value> Paare in Form einer Liste an und gibt die Möglichkeit die Werte (values) zu ändern. Nach Abschluß des Editiervorgangs wird die editierte Variante von < strlist> zurückgegeben.
    Im grafischen Modus erfolgt die Abfrage im Rahmen eines modalen Fensters, ansonsten auf der Kommandozeile.

  • getListFromWMI(<wmi namespace str>,<wmi class str>,<property list>,<condition str>`) : stringlist` //since 4.12.1.0 [W]
    Liefert eine info map der Werte die aus der WMI Klasse <wmi class str> ermittelt wurden. Diese info map kann begrenzt werden auf die Liste der Eigenschaften aus <property list> und durch die Bedingung aus <condition str>. Wenn <property list> leer ist, so werden die Werte für alle Eigenschaften der Klasse zurückgegeben.
    Achtung: Wenn <property list> eine Eigenschaft enthält, welche nicht in der Klasse <wmi class str> enthalten ist, so schlägt die Abfrage fehl.
    Abfragen mit Angabe von Eigenschaften <property list> sind schneller als Abfragen ohne.
    Wenn der Namespace <wmi namespace str> leer ist, so wird als Default root\cimv2 verwendet.
    Bei einem Fehler wird eine leere Liste zurückgegeben.

Beispiel:

; this is valid because both properties are valid
set $list1$ = createStringList ('Model','Manufacturer')
set $str1$ = 'root\cimv2'
set $str2$ = 'Win32_ComputerSystem'
set $str3$ = ''
set $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)

produziert z.B. folgenden Log:

Set  $list1$ = createStringList ('Model','Manufacturer')
  The value of the variable "$list1$" is now:
  (string   0)Model
  (string   1)Manufacturer
Set  $str1$ = 'root\cimv2'
  The value of the variable "$str1$" is now: "root\cimv2"
Set  $str2$ = 'Win32_ComputerSystem'
  The value of the variable "$str2$" is now: "Win32_ComputerSystem"
Set  $str3$ = ''
  The value of the variable "$str3$" is now: ""
Set  $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)
  The value of the variable "$resultlist$" is now:
  (string   0)Model=HP Pavilion Desktop PC 570-p0xx
  (string   1)Manufacturer=HP

Beispiel:

comment "Testing for os architecture"
set $ConstTest$ = GetSystemType
set $list1$ = createStringList ('systemtype')
set $str1$ = ''
set $str2$ = 'Win32_ComputerSystem'
set $str3$ = ''
set $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)

produziert z.B. folgenden Log:

comment: Testing for os architecture
Set  $ConstTest$ = GetSystemType
  The value of the variable "$ConstTest$" is now: "64 Bit System"
Set  $list1$ = createStringList ('systemtype')
  The value of the variable "$list1$" is now:
  (string   0)systemtype
Set  $str1$ = ''
  The value of the variable "$str1$" is now: ""
Set  $str2$ = 'Win32_ComputerSystem'
  The value of the variable "$str2$" is now: "Win32_ComputerSystem"
Set  $str3$ = ''
  The value of the variable "$str3$" is now: ""
Set  $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)
  The value of the variable "$resultlist$" is now:
  (string   0)systemtype=x64-based PC

Beispiel:

comment "Testing for freespace"
;wmic LogicalDisk "%Systemdrive%" get freespace
set $list1$ = createStringList ('freespace')
set $str1$ = 'root\cimv2'
set $str2$ = 'Win32_LogicalDisk'
set $str3$ = 'where Name="%Systemdrive%"'
markerrornumber
set $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)
if errorsOccuredSinceMark = 0
	set $CompValue$ = getValue("freespace", $resultlist$)
	set $CompValue$ = calculate($CompValue$+ '-1')
	if (HasMinimumSpace ("%Systemdrive%", $CompValue$))
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif
	set $CompValue$ = calculate($CompValue$+ '+10')
	if (HasMinimumSpace ("%Systemdrive%", $CompValue$))
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	else
		comment "passed"
	endif
endif

produziert z.B. folgenden Log:

comment: Testing for freespace
Set  $list1$ = createStringList ('freespace')
  The value of the variable "$list1$" is now:
  (string   0)freespace
Set  $str1$ = 'root\cimv2'
  The value of the variable "$str1$" is now: "root\cimv2"
Set  $str2$ = 'Win32_LogicalDisk'
  The value of the variable "$str2$" is now: "Win32_LogicalDisk"
Set  $str3$ = 'where Name="C:"'
  The value of the variable "$str3$" is now: "where Name="C:""
Marked error number 1
Set  $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)
  The value of the variable "$resultlist$" is now:
  (string   0)freespace=235092250624
If
  errorsOccuredSinceMark = 0   <<< result true
Then
  Set  $CompValue$ = getValue("freespace", $resultlist$)
    The value of the variable "$CompValue$" is now: "235092250624"
  Set  $CompValue$ = calculate($CompValue$+ '-1')
    The value of the variable "$CompValue$" is now: "235092250623"
  If
      Free on Disk C:: 235.092.250.624 bytes  This is more than the required amount of 235.092.250.623 bytes
    HasMinimumSpace ("C:", $CompValue$)   <<< result true
    (HasMinimumSpace ("C:", $CompValue$))   <<< result true
  Then
    comment: passed
  Else
  EndIf
  Set  $CompValue$ = calculate($CompValue$+ '+10')
    The value of the variable "$CompValue$" is now: "235092250633"
  If
      Free on Disk C:: 235.092.250.624 bytes  This is less than the required amount of 235.092.250.633 bytes
    HasMinimumSpace ("C:", $CompValue$)   <<< result false
    (HasMinimumSpace ("C:", $CompValue$))   <<< result false
  Then
  Else
    comment: passed
  EndIf
EndIf

Beispiel:

comment "Testing for drive count"
;wmic LogicalDisk "%Systemdrive%" get name
set $list1$ = createStringList ('Name')
set $str1$ = ''
set $str2$ = 'Win32_LogicalDisk'
set $str3$ = ''
set $resultlist$ = getListFromWMI($str1$,$str2$,$list1$,$str3$)
set $CompValue$ = count($resultlist$)
set $resultlist$ = powershellCall('get-psdrive -psprovider filesystem | select-object -expand Name')
set $ConstTest$ = count($resultlist$)
if ($ConstTest$ = $CompValue$)
	comment "getListFromWMI passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing getListFromWMI failed"
endif

produziert z.B. folgenden Log:

comment: Testing for drive count
  The value of the variable "$list1$" is now:
  (string   0)Name
  The value of the variable "$str1$" is now: ""
  The value of the variable "$str2$" is now: "Win32_LogicalDisk"
  The value of the variable "$str3$" is now: ""
  The value of the variable "$resultlist$" is now:
  (string   0)Name=C:
  (string   1)Name=D:
  (string   2)Name=E:
  (string   3)Name=F:
  (string   4)Name=L:
  (string   5)Name=N:
  (string   6)Name=R:
  (string   7)Name=S:
  (string   8)Name=W:
  (string   9)Name=Y:
  (string  10)Name=Z:
  The value of the variable "$CompValue$" is now: "11"
PowershellCall Executing: get-psdrive -psprovider filesystem | select-object -expand Name ; mode: sysnative
ShellCall Executing: "C:\WINDOWS\system32\\cmd.exe" /C "powershell.exe get-executionpolicy"
Powershell excution policy = Bypass
ShellCall Executing: "C:\WINDOWS\system32\\cmd.exe" /C "powershell.exe set-executionpolicy ByPass"

Execution of tmp-internal powershell.exe winst /sysnative
  Save to file with encoding: system
  ExitCode 0
The file: c:\opsi.org\tmp\_opsiscript_N97cDr97Km.ps1 has been deleted
ShellCall Executing: "C:\WINDOWS\system32\\cmd.exe" /C "powershell.exe set-executionpolicy Bypass"
  The value of the variable "$resultlist$" is now:
  (string   0)C
  (string   1)D
  (string   2)E
  (string   3)F
  (string   4)L
  (string   5)N
  (string   6)R
  (string   7)S
  (string   8)W
  (string   9)Y
  (string  10)Z
  The value of the variable "$ConstTest$" is now: "11"
If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: getListFromWMI passed
Else
EndIf

Sie funktioniert ähnlich wie die oben beschriebene Funktion getListFromWMI.

Die Benutzeroberfläche von 'opsi-wmi-test' gliedert sich in zwei Bereiche.

Im oberen Bereich ('Connection to WMI service') werden die Daten abgefragt, die benötigt werden um eine Verbindung zum WMI Service aufzubauen. Benötigt wird der Computername ('Computer') der angesprochen werden soll, der WMI Namensraum ('NameSpace') der zu verwendenden WMI Klasse, sowie eventuell Benutzername ('User') und Password ('Password'). Beim Start von opsi-wmi-test.exe sind hierfür schon Standardwerte ('Computer' = localhost, 'NameSpace' = \root\cimv2, 'User' = < > , 'Password' = < >) angegeben mit der auf den lokalen WMI Service und den am meisten verwendeten WMI Klassen zugegriffen werden kann.
Es gibt auch die Möglichkeit auf entfernte Computer zuzugreifen. Dann muss der entsprechende Netzwerkname unter dem der Computer zu erreichen ist und eventuell Benutzername und Password angegeben werden.

opsi-wmitestgui-start
Abbildung 1. GUI von opsi-wmi-test. Im oberen Bereich ('Connection to WMI service') können die Parameter eingegben werden die benötigt werden um eine Verbindung zum WMI Service aufzubauen. Im unteren Bereich ('Request to WMI service') werden die Daten abgefragt die benötigt werden um die gewünschte Anfrage an den WMI Service zu stellen.

Im unteren Bereich ('Request to WMI service') werden die Daten abgefragt die benötigt werden um die gewünschte Anfrage an den WMI Service zu stellen. Benötigt wird hierbei die WMI Klasse ('Class') bzw. ihr Alias ('Alias') und die Eigenschaften ('WMI Properties') die abgefragt werden sollen. Die WMI Klasse kann entweder direkt im entsprechendem Feld ('Class' oder 'Alias') eingegeben oder über eine Liste ausgewählt werden (Abbildung 9.2). Nachdem die Klasse ausgewählt ist werden ihre Eigenschaften in dem Feld 'Available WMI Properties' angezeigt.

opsi-wmitestgui-2

Verfügbare Eigenschaften können ausgewählt und dann mittels drag & drop oder der Schaltfläche

opsi-wmitestgui-button-pfeil-rechts

nach 'Selected WMI Properties' verschoben werden (Abbildung 9.3) .
Anmerkung: Dies geht auch umgekehrt. Eigenschaften können von 'Selected WMI Properties' wieder nach 'Available WMI Properties' per drag & drop oder der Schaltfläche

opsi-wmitestgui-button-pfeil-links

verschoben werden.

opsi-wmitestgui-3
opsi-wmitestgui-4
Abbildung 2. Nachdem sich Eigenschaften im Feld 'Selected WMI Properties' befinden, kann durch anklicken der Schaltfläche 'Execute' die Anfrage an den WMI Service gestellt werden. In dem Feld 'Condition' kann die Abfrage noch mittels SQL Anweisungen verfeinert werden.

Nachdem sich Eigenschaften im Feld 'Selected WMI Properties' befinden, kann durch anklicken der Schaltfläche 'Execute' die Anfrage an den WMI Service gestellt werden. In dem Feld 'Condition' kann die Abfrage noch mittels SQL Anweisungen verfeinert werden, z.B. where <property> = <value>.

Die endgültige Abfrage wird im 'Query' Feld angezeigt. Sie kann von dort kopiert werden aber dort nicht verändert werden. Das Ergebnis der Anfrage wird in einem extra Fenster ausgegeben. Dabei kann es sich auch um eine Fehlermeldung handeln falls die Anfrage nicht bearbeitet werden konnte.

opsi-wmitestgui-resultwindow
Abbildung 3. Das Ergebnis der Anfrage wird in einem extra Fenster ausgegeben

In einem dritten Fenster haben Sie nun alle Daten Ihrer Abfrage : 'Namespace', 'Selected Class', 'Properties list', 'Selected Properties' and 'All available Properties'. Sie können diese Daten von hier aus per cut&paste in Ihr opsi-script übertragen

opsi-wmitestgui-querywindow
Abbildung 4. In einem dritten Fenster haben Sie nun alle Daten Ihrer Abfrage : 'Namespace', 'Selected Class', 'Properties list', 'Selected Properties' and 'All available Properties'.

Erzeugung von String-Listen aus vorgegebenen String-Werten [W/L/M]

  • createStringList (`Stringwert0, Stringwert1 ,…​ `) [W/L/M]
    erzeugt eine neue Liste aus den aufgeführten einzelnen String-Werten, z.B. liefert

set $list1$ = createStringList ('a','b', 'c', 'd')

die ersten vier Buchstaben des Alphabets.

  • splitString (`Stringwert1, Stringwert2)` [W/L/M]
    erzeugt die Liste der Teilstrings von String-Wert1, die jeweils durch String-Wert2 voneinander getrennt sind. Z.B. bildet

set $list1$ = splitString ("\\server\share\directory",  "\")

die Liste
'"", "", "server", "share", "directory"'
Ist der übergebene String confidential, so werden es die hier enstehenden Teile auch sein.

  • splitStringOnWhiteSpace (<string>`)` [W/L/M]
    zerlegt <string> in die durch "leere" Zwischenräume definierten Abschnitte. Das heißt z.B.

set $list1$ = splitStringOnWhiteSpace("Status   Lokal     Remote         Netzwerk")

liefert die Liste
'"Status", "Lokal", "Remote", "Netzwerk"'
unabhängig davon, wie viele Leerzeichen oder ggf. Tabulatorzeichen zwischen den "Wörtern" stehen.
Ist der übergebene String confidential, so werden es die hier entstehenden Teile auch sein.

Laden der Zeilen einer Textdatei in eine String-Liste

  • loadTextFile (`Dateiname)` [W/L/M]
    liest die Zeilen der Datei des (als String) angegebenen Namens ein und generiert aus ihnen eine String-Liste.

  • LoadTextFileWithEncoding( <file name> , <encoding>`)` [W/L/M]
    Liefert eine Stringliste mit dem Inhalt von <file name> welcher beim Einlesen von <encoding> in das laufende Encoding des Systems konvertiert wurde.

  • loadUnicodeTextFile (`Dateiname)` [W/L/M]
    liest die Zeilen der Unicode-Datei des (als String) angegebenen Namens ein und generiert aus ihnen eine String-Liste.
    Die Strings in der String-Liste werden dabei (gemäß den Betriebssystem-Defaults) in 8 Bit-Code konvertiert.

  • getSectionNames (`Dateiname)` [W/L/M]
    liest die ausgewählte Datei als eine ini-Datei aus, durchsucht alle Zeilen nach dem Begriff
    '[<SectionName>]' und gibt die einfachen Sektionsnamen (ohne Klammern) aus.

  • GetSectionFromInifile(<Sektion>,<INI-Datei>): stringlist [W/L/M]
    Sucht <Sektion> in der INI-Datei und gibt den kompletten Inhalt der Sektion (mit Sektionsbezeichnung) als Stringliste zurück.

(Wieder-) Gewinnen von Einzelstrings aus String-Listen oder Dateien [W/L/M]

  • composeString (<StringListe>, <LinkString>`)` [W/L/M]
    Mit dieser Funktion lässt sich die Zerlegung eines Strings in einer String-Liste z.B. nach vorheriger Transformation (s. den Abschnitt „Transformation von String-Listen“) – rückgängig machen.
    Zum Beispiel:
    Wenn $list1$ für die Liste 'a', 'b', 'c', 'd', 'e' steht, erhält die String-Variable line mittels $line$ = composeString ($list1$, " | ") den Wert '"a | b | c | d | e".'

  • takeString(<index>,<list>`)` [W/L/M]
    liefert aus der String-Liste <list> den String mit dem Index <index>
    zum Beispiel liefert (wenn $list1$ wie eben die Liste der ersten fünf Buchstaben des Alphabets ist) takeString (2, list1)
    den String 'c' (der Index beruht auf einer mit 0 beginnenden Nummerierung der Listenelemente).
    Hat Index einen negative Wert, werden die Werte ausgehend vom Ende der Liste gelesen, z.B. gibt
    takeString (-1, list1)
    das letzte Listenelement zurück; das ist 'e'.
    siehe auch : setStringInListAtIndex
    siehe auch : takeString

  • takeFirstStringContaining(<list>,<search string>`)` [W/L/M]
    Liefert den ersten String einer Liste der <search string> enthält. Liefert einen leeren String wenn kein passender String gefunden wird.
    siehe auch : takeFirstStringContaining

  • getValue(<key>, <list>`)` [W/L/M]
    Diese Funktion versucht eine String-Liste <list> als eine Liste aus Zeilen der Form
    'key=value'
    auszulesen.
    Dazu sucht die Funktion die erste Zeile, wo der String-Key vor dem Gleicheitszeichen erscheint und gibt den Rest der Zeile zurück (der String, der nach dem Gleicheitszeichen folgt). Wenn es keinen passende Zeile gibt, wird der Wert 'NULL' zurückgegeben.
    Die Funktion ist z.B. hilfreich für die Nutzung von Info maps wie sie von Funktionen wie getLocaleInfoMap, getFileVersionMap, geliefert werden. siehe auch: Info Maps.

  • getValueBySeparator(<key string>,<separator string>,<hash string list> ) //since 4.11.2.1 [W/L/M]
    arbeitet wie getValue aber der Trenner zwischen 'key' und 'value' (<separator string>) muss angegeben werden so das mit maps gearbeitet werden kann wie
    'key:value'

  • setValueByKey(<key>, <value>, <targetlist> ) : stringlist [W/L/M]
    Setzt in der String-Liste <targetlist> den Wert des String-Key <key> auf den Wert <value>. Dafür muss die String-Liste <targetlist> eine Key/Value-Liste sein, das heißt jeder Eintrag ist von der Form
    'key=value'.
    Sind die Key/Value-Paare in <targetlist> nicht durch = getrennt sondern durch einen anderen Seperator, dann muss dieser der Funktion als Argument mitgegeben werden.
    Beispiel:

Set $KeyValueList$ = createStringList('key1=value1','key2=value2')
Set $NewList$ = setValueByKey('key2','newvalue',$KeyValueList$)
; then $NewList$ = ['key1=value1','key2=newvalue']

Set $KeyValueListWithDifferentSeperator$ = createStringList('key1:value1','key2:value2')
Set $NewListWithDifferentSeperator$ = setValueByKey('key2','newvalue',$KeyValueListWithDifferentSeperator$,':')
; then $NewListWithDifferentSeperator$ = ['key1:value1','key2:newvalue']

  • getValueFromFile(<key string>, <file name>`)` //since 4.11.4.4 [W/L/M]
    Sucht in <file name> nach einem key/value Paar mit dem key <key string> und separator string '=' und liefert den gefundenen value. Wenn <key string> nicht gefunden wird, liefert die Funktion einen leeren string.

  • getValueFromFileBySeparator(<key string>,<separator string>, <file name>`)` //since 4.11.4.4 [W/L/M]
    Sucht in <file name> nach einem key/value Paar mit dem key <key string> und separator string <separator string> und liefert den gefundenen value. Wenn <key string> nicht gefunden wird, liefert die Funktion einen leeren string.

  • count (<list>`) : string` [W/L/M]
    Die Funktion zählt die Elemente einer String-Liste <list>; das Resultat wird in einen String gewandelt. Ist $list1$ z.B.
    'a', 'b', 'c', 'd', 'e'
    so hat count ($list1$) den Wert "5".

String-Listen-Erzeugung mithilfe von Sektionsaufrufen

  • retrieveSection (`Sektionsname)` [W/L/M]
    gibt die Zeilen einer aufgerufene Sektion aus.

  • getOutStreamFromSection (`Sectionname)` [W/L/M]
    „fängt“ – derzeit bei ShellScript (ShellInAnIcon),ExecWith und ExecPython Aufrufen – die Ausgabe der Kommandozeilenprogramme in der Form einer String-Liste ein. Z.B. liefert der Ausdruck getOutStreamFromSection ('ShellScript_netstart')
    wenn die aufgerufene Sektion definiert ist durch

set $list$ = getOutStreamFromSection ('ShellScript_netstart')

[ShellScript_netstart]
net start

eine Reihe von Zeilen, die u.a. die Auflistung aller laufenden Dienste enthalten und dann weiter bearbeitet werden können.
siehe auch : getReturnListFromSection
siehe auch: executeSection

Seit 4.11.4.2 gibt es für einfache Befehle und besonders (aber nicht nur) für den Einsatz unter Linux folgende 'Abkürzung', welche unter Windows im 'sysnative' mode läuft:

  • shellCall (<command string>`) : stringlist (output)` //since 4.11.4.2 [W/L/M]

set $list$= shellCall('net start')

ist eine Abkürzung von:

set $list$ = getOutStreamFromSection ('ShellScript_netstart winst /sysnative')

[ShellScript_netstart]
net start

siehe auch: shellCall_list

  • shellCall (<command string>`) : noresult` //since 4.11.6.1 [W/L/M]

shellCall('net start')

Is a shortcut for this expression:

ShellScript_netstart winst /sysnative

[ShellScript_netstart]
net start

siehe auch: shellCall

  • shellCall (<command string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M]

set $exitcode$ = shellCall('net start')

Is a shortcut for this expression:

ShellScript_netstart winst /sysnative
set $exitcode$ = getLastExitcode

[ShellScript_netstart]
net start

siehe auch: shellCall_str

  • getReturnListFromSection ( Sectionname ) [W/L/M]
    In Sektionen bestimmter Typen – derzeit implementiert nur für XMLPatch-und opsiServiceCall-Sektionen – existiert eine spezifische Return-Anweisung, die ein Ergebnis der Sektion als String-Liste zur Verfügung stellt.

XMLPatch Beispiel:
Die Anweisung
set $list1$ =getReturnListFromSection ('XMLPatch_mime "c:\mimetypes.rdf"')
liefert eine spezifisch selektierte Liste von Knoten der XML-Datei mimetypes.rdf. Näheres zu XMLPatch-Sektionen ist der Dokumentation im Kapitel opsi-script-xmlpatch zu entnehmen.

OpsiServiceCall Beispiel:

DefStringList $result$
Set $result$=getReturnListFromSection("opsiservicecall_clientIdsList")

[opsiservicecall_clientIdsList]
"method":"getClientIds_list"
"params":[]

siehe auch: getOutStreamFromSection siehe auch: executeSection

String-Listen aus der Registry [W]

  • getRegistryKeyList32(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Keys direkt unterhalb von <regkey>.
    32 Bit Modus (mit Redirection). Seit 4.11.3

  • getRegistryKeyList64(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Keys direkt unterhalb von <regkey>.
    64 Bit Modus (ohne Redirection). Seit 4.11.3

  • getRegistryKeyListSysnative(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Keys direkt unterhalb von <regkey>.
    Modus abhängig von der Architektur des Betriebssystems. Seit 4.11.3

  • getRegistryKeyList(<regkey>, <access str>`)`
    Fasst die vorigen drei Funktionen zusammen, das heißt, die Funktion liefert eine Liste mit dem Namen aller Keys direkt unterhalb von <regkey>, wobei der Modus (32bit, 64bit, sysnative) als <access str> mitgegeben wird. Seit 4.12.5.0

  • getRegistryVarList32(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Werte direkt unterhalb von <regkey>.
    32 Bit Modus (mit Redirection). Seit 4.11.3

  • getRegistryVarList64(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Werte direkt unterhalb von <regkey>.
    64 Bit Modus (ohne Redirection). Seit 4.11.3

  • getRegistryVarListSysnative(<regkey>`)`
    Liefert eine Liste mit dem Namen aller Werte direkt unterhalb von <regkey>.
    Modus abhängig von der Architektur des Betriebssystems. Seit 4.11.3

  • getRegistryVarList(<regkey>, <access str>`)`
    Fasst die vorigen drei Funktionen zusammen, das heißt, die Funktion liefert eine Liste mit dem Namen aller Werte direkt unterhalb von <regkey>, wobei der Modus (32bit, 64bit, sysnative) als <access str> mitgegeben wird. Seit 4.12.5.0

  • getRegistryVarMap32(<regkey>`)`
    Liefert eine Map mit den Namen=Value Paaren aller Werte direkt unterhalb von <regkey>.
    32 Bit Modus (mit Redirection). Seit 4.11.3

  • getRegistryVarMap64(<regkey>`)`
    Liefert eine Map mit den Namen=Value Paaren aller Werte direkt unterhalb von <regkey>.
    64 Bit Modus (ohne Redirection). Seit 4.11.3

  • getRegistryVarMapSysnative(<regkey>`)`
    Liefert eine Map mit den Namen=Value Paaren aller Werte direkt unterhalb von <regkey>.
    Modus abhängig von der Architektur des Betriebssystems. Seit 4.11.3

  • getRegistryVarMap(<regkey>, <access str>`)`
    Fasst die vorigen drei Funktionen zusammen, das heißt, die Funktion liefert eine Map mit den Namen=Value Paaren aller Werte direkt unterhalb von <regkey>, wobei der Modus (32bit, 64bit, sysnative) als <access str> mitgegeben wird. Seit 4.12.5.0

Beispiel:
Wir erzeugen Registryeinträge mit folgender Sektion durch den Aufruf von:

Registry_createkeys /32Bit

[Registry_createkeys]
openkey [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test]
set "var1" = "value1"
set "var2" = REG_SZ:"value2"
set "var3" = REG_EXPAND_SZ:"value3"
set "var4" = REG_DWORD:444
; REG_QWORD wird unterstützt seit 4.12.6
set "var5" = REG_QWORD:18446744073709551615
set "var6" = REG_BINARY:05 05 05 0F 10
set "var7" = REG_MULTI_SZ:"value6|value7|de"
openkey [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\key1]
openkey [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\key2]
openkey [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\key3]
openkey [HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\key4]

Dann liefern uns:

set $list$ = getRegistryVarList32("hklm\software\opsi.org\opsi-script-test")

beziehungsweise

set $list$ = getRegistryVarList("hklm\software\opsi.org\opsi-script-test","32bit")

folgenden Log:

Registry started with redirection (32 Bit)
    The value of the variable "$list$" is now:
    (string   0)var1
    (string   1)var2
    (string   2)var3
    (string   3)var4
    (string   4)var5
    (string   5)var6

Dann liefern uns:

set $list$ = getRegistryVarMap32("hklm\software\opsi.org\opsi-script-test")

beziehungsweise

set $list$ = getRegistryVarMap("hklm\software\opsi.org\opsi-script-test","32bit")

folgenden Log:

Registry started with redirection (32 Bit)
	The value of the variable "$list$" is now:
    (string   0)var1=value1
    (string   1)var2=value2
    (string   2)var3=value3
    (string   3)var4=444
    (string   4)var5=05 05 05 0F 10
    (string   5)var6=value6

Dann liefern uns:

set $list$ = getRegistryKeyList32("hklm\software\opsi.org\opsi-script-test")

beziehungsweise

set $list$ = getRegistryKeyList("hklm\software\opsi.org\opsi-script-test","32bit")

folgenden Log:

Registry started with redirection (32 Bit)
	The value of the variable "$list$" is now:
    (string   1)key1
    (string   2)key2
    (string   3)key3
    (string   4)key4

String-Listen aus Produkt Properties [W/L/M]

  • getProductPropertyList(<propname>,<default value>`)` [W/L/M] // seit 4.11.3
    Liefert eine Liste mit den aktiven Werten des multivalue Properties <propname>.
    Die Funktion GetProductProperty würde in diesem Fall die einzelnen Werte als einen kommaseparierten String zurückliefern. Dieses Vorgehen ist aber problematisch wenn Kommas auch in der Werten vorkommen.
    Kann der aktuelle Wert des Properies nicht vom opsi-server ermittelt werden (z.B. weil das Skript nicht im Kontext des opsi-service läuft), so wird der zurückzugebende Wert wie folgt ermittelt:
    Seit 4.12.4.32 wird zunächst geprüft ob sich im %ScriptPath% eine Datei properties.conf befindet. Wenn ja, wird versucht aus dieser Datei den Wert des Properties zu lesen. Dabei wird die Datei properties.conf als Liste von key=value Paaren erwartet. Im Falle einer Stringliste wird hier ein Eintrag vom Muster <property name>=<list value> erwartet. Beispiel: myproperty=["entry1","entry2","entry3"].
    Wird die Datei properties.conf nicht gefunden oder enthält den gesuchten Eintrag nicht, so wird der <default value> zurückgegeben.
    <default value> kann bei getProductPropertyList (seit 4.11.5.6) sowohl ein Stringausdruck sein, welcher das erste Element der einer Liste beschreibt, oder eine Liste.
    Seit 4.12.4.32 kann die Liste auch als Zeichenkette angegeben werden. Beispiel '["ab","cd","de"]'
    Die als <default value> angebene Liste wird zurückgegeben, wenn der die aktuellen Werte des Servers nicht verfügbar sind.

Beispiel:

DefStringList $list$
;Property "dummymulti" has the values: ("ab", "cd", "ef", "g,h")
set $list$ = GetProductPropertyList ("dummymulti","True")
if not ("" = takeFirstStringContaining($list$,"g,h"))
	comment "GetProductPropertyList passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "GetProductPropertyList failed"
endif

set $ConstTest$ = "ab,cd,ef,g,h"
set $CompValue$ = GetProductProperty ("dummymulti","True")
if ($ConstTest$ = $CompValue$)
	comment "GetProductProperty passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "GetProductProperty failed"
endif

;;;;;;another Example to get a list as default-property

DefStringList $list$
DefStringList $propertyList$
Set $propertyList$ = createStringList('ab','cd','de')
Set $list$ = GetProductPropertyList ("dummymulti",$propertyList$)

;;;;;; since 4.12.4.32 also possible:
Set $list$ = GetProductPropertyList ("dummymulti",'["ab","cd","de"]')

Ab 4.12.4.32 ist bei Existenz der folgenden %ScriptPath%\properties.conf :

propstr = from file
proplist = ["from file",huhu"]

das folgende Skript ausserhalb des opsi-service Kontextes erfolgreich:

[Actions]
DefStringList $list$
DefVar $str$

set $str$ = GetProductProperty('propstr','')
if $str$ = "from file"
	comment "got it"
else
	comment "failed"
endif

set $list$ = GetProductPropertyList('proplist','')
if takeString(0,$list$) = "from file"
	comment "got it"
else
	comment "failed"
endif

siehe auch : [asConfidential_list]

Sonstige String-Listen [W/L/M]

  • getProfilesDirList [W/L/M]
    Liefert eine Liste der Pfade zu den lokalen Profilen.
    [W] : Profile welche die folgenden Worte enthalten, werden nicht berücksichtigt:

  • 'localservice'

  • 'networkservice'

  • 'systemprofile'

Das Profil des 'Default Users' ist Bestandteil der Liste.
All User oder Public sind nicht Bestandteil der Liste.

[L] : Es werden die Heimatverzeichnisse der user mit einer UID >= 1000 geliefert, sofern das Verzeichnis auch existiert.

Beispiel:

set $list1$ = getProfilesDirList

ergibt folgenden Log:

Set  $list1$ = getProfilesDirList
Registry started with redirection (32 Bit)
    retrieving strings from getProfilesDirList [switch to loglevel 7 for debugging]
        (string   0)C:\Users\Administrator
        (string   1)C:\Users\Default

  • GetProcessList //since 4.11.1.2; gives list of exename;pid;dom/user [W/L/M]
    Liefert eine Liste der laufenden Prozesse.
    Für jeden Prozess gibt es eine Zeile mit den folgenden ';' separierten Prozessinformationen:

    • [W]: 'Prozess Name'. [L]: 'Kurzname des Prozesses'

    • [W/L/M]: 'PID'

    • [W]: 'Domain/User'. [L]: 'User'

    • [L]: 'Komplette Kommandozeile des laufenden Prozesses'

  • listFiles (<Pfad>, <Suchmaske>, <DurchsucheUnterordner>, [<Umleitung>]) : stringlist [W/L/M]

Liefert eine Stringliste aller gefundenen Dateien im <Pfad> (z.B: "C:\Windows\system32") zurück, die der angegebenen <Suchmaske> (z.B: "*.dll") entsprechen. <Suchmaske> kann mehrere durch Semikolon getrennte Elemente enthalten.
Wird <DurchsucheUnterordner> auf "True" gesetzt werden bei der Suche auch die Unterverzeichnisse mit einbezogen. Ist der Wert "False" werden Unterordner nicht einbezogen.

[W] Das Setzen des optionalen Parameters <Umleitung> auf "64bit" oder "SysNative" durchsucht auch (System)ordner die ansonsten aufgrund von Umleitung von 32-bit Programmen auf 64-bit Systemen nicht durchsuchbar wären (nur 64bit Windows). Siehe hierzu auch 64 Bit-Unterstützung unter Windows [W]

Beispiel:

message "Test of function listFiles"

DefVar $Path$
DefStringList $Files$
Set $Path$ = "%System%"
Set $Files$ = listFiles($Path$,"*.Devices.*.dll","False")

ergibt folgenden Log:

message Test of function listFiles
(created string list $Files$)
Set $Path$ = "C:\Windows\system32"
  The value of the variable "$Path$" is now: "C:\Windows\system32"
Set  $Files$ = listFiles($Path$,"*.Devices.*.dll*","False")
  The value of the variable "$Files$" is now:
  (string   0)C:\Windows\system32\Windows.Devices.AllJoyn.dll
  (string   1)C:\Windows\system32\Windows.Devices.Background.dll
  (string   2)C:\Windows\system32\Windows.Devices.Background.ps.dll
  (string   3)C:\Windows\system32\Windows.Devices.Bluetooth.dll
  (string   4)C:\Windows\system32\Windows.Devices.Custom.dll
  (string   5)C:\Windows\system32\Windows.Devices.Custom.ps.dll
  (string   6)C:\Windows\system32\Windows.Devices.Enumeration.dll
  (string   7)C:\Windows\system32\Windows.Devices.Haptics.dll
  (string   8)C:\Windows\system32\Windows.Devices.HumanInterfaceDevice.dll
  (string   9)C:\Windows\system32\Windows.Devices.Lights.dll
  (string  10)C:\Windows\system32\Windows.Devices.LowLevel.dll
  (string  11)C:\Windows\system32\Windows.Devices.Midi.dll
  (string  12)C:\Windows\system32\Windows.Devices.Perception.dll
  (string  13)C:\Windows\system32\Windows.Devices.Picker.dll
  (string  14)C:\Windows\system32\Windows.Devices.PointOfService.dll
  (string  15)C:\Windows\system32\Windows.Devices.Portable.dll
  (string  16)C:\Windows\system32\Windows.Devices.Printers.dll
  (string  17)C:\Windows\system32\Windows.Devices.Printers.Extensions.dll
  (string  18)C:\Windows\system32\Windows.Devices.Radios.dll
  (string  19)C:\Windows\system32\Windows.Devices.Scanners.dll
  (string  20)C:\Windows\system32\Windows.Devices.Sensors.dll
  (string  21)C:\Windows\system32\Windows.Devices.SerialCommunication.dll
  (string  22)C:\Windows\system32\Windows.Devices.SmartCards.dll
  (string  23)C:\Windows\system32\Windows.Devices.SmartCards.Phone.dll
  (string  24)C:\Windows\system32\Windows.Devices.Usb.dll
  (string  25)C:\Windows\system32\Windows.Devices.WiFi.dll
  (string  26)C:\Windows\system32\Windows.Devices.WiFiDirect.dll
  (string  27)C:\Windows\system32\Windows.Internal.Devices.Sensors.dll

  • replaceOpsiConstants(<string list>`) : stringlist` //since 4.12.3.6 [W/L/M]
    Ersetzt alle Vorkommen von opsi Konstanten in '<string list>' durch ihre Werte und gibt die resultierende Stringliste zurück.
    siehe auch : replaceOpsiConstants (string)

Transformation von String-Listen [W/L/M]

  • getSubList (<Startindex> : <Endindex>, <list> ) [W/L/M]
    Liefert eine Teilliste einer vorgegebenen Liste.
    Funktion:
    Wenn $list$ z.B. für die Liste der Buchstaben 'a', 'b', 'c', 'd', 'e' steht, so liefert

set $list1$ = getSubList(1 : 3, $list$)

'b', 'c', 'd' (Startindex und Endindex sind die Nummer des Listenelements, wenn mit 0 beginnend gezählt wird).
Defaultwert des Startindex ist 0, des Endindex der letzte Index der Liste. Z.B. ergibt mit obiger Festlegung für $list$

set $list1$ = getSubList(1 : , $list$)

'b', 'c', 'd', 'e'.

set $list1$ = getSubList(:, $list$)

ist genau eine Kopie der ursprünglichen Liste.

Es besteht die Möglichkeit den Endindex mit Rückwärtszählung zu bestimmen:

set $list1$ = getSubList(1 : -1, $list$)

ist die Teilliste der Elemente vom 1. bis zum letzten Element der ursprünglichen Liste – im obigen Beispiel also wieder 'b', 'c', 'd','e'.

set $list1$ = getSubList(1 : -2, $list$)

ist die Teilliste der Elemente vom 1. bis zum vorletzten Element der ursprünglichen Liste – im obigen Beispiel also wieder 'b', 'c', 'd'.

Seit Version 4.12.0.35 können neben Zahlen auch Stringausdrücke verwendet werden, also Strings, Stringvariablen und Funktionen, welche einen String zurückliefern.

set $tmp1$ = "1"
set $tmp2$ = "3"
set $list1$ = getSubList( $tmp1$ : $tmp2$ , $list1$)

set $list2$ = createStringList("","-1","0","1","2","3","4","5","6",)
set $list1$ = getSubList(takestring(3,$list2$):takestring(5,$list2$), $list1$)

  • getListContaining(<list>,<search string>`) : stringlist` [W/L/M]
    Liefert eine Teilliste mit allen Strings, welche den <search string> enthalten.

  • getListContainingList(<list1>,<list2>`) : stringlist` //since 4.11.3.7 [W/L/M]
    Liefert die Schnittmenge von list1 und list2

  • getSubListByMatch (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von <target list> mit allen Strings, welche mit dem <search string> identisch sind.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getSubListByMatch (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von <target list> mit allen Strings, welche mit einem der Strings aus <search list> identisch sind.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getSubListByContaining ( <search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von <target list> mit allen Strings, in welchen <search string> vorkommt.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getSubListByContaining (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von <target list> mit allen Strings, in denen einer der Strings aus <search list> vorkommt.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getSubListByKey (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von <target list> mit allen Strings, welche mit '<search string>=' anfangen.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getSubListByKey (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert eine Teilliste von der Key/Value Paar Liste <target list> mit allen Strings, deren Key in <search list> vorkommt.
    Die Überprüfung auf Gleichheit ist nicht Case Sensitive.

  • getKeyList (<list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    Liefert von einer Liste von Key/Value Paaren im Format Key=Value die Liste aller Keys. Ist ein Eintrag in <list> nicht im Format Key=Value, so wird der komplette String zurückgeliefert.

  • takeFirstStringContaining(<list>,<search string>`)` [W/L/M]
    Liefert den ersten String von <list> welcher den <search string> enthält.
    Liefert einen Leerstring wenn <search string> nicht gefunden wird.

  • addtolist(<list>,<string>`)` [W/L/M]
    Hängt den String <string> an die Liste <list> an.

  • addlisttolist(<list1>,<list2>`)` [W/L/M]
    Hängt die Liste <list2> an die Liste <list1> an.

  • reverse (<list>`)` [W/L/M]
    kehrt die Reihenfolge der Aufzählung um – aus 'a', 'b', 'c', 'd', 'e' wird mit

set $list1$ = reverse ($list$)

also 'e', 'd', 'c', 'b', 'a'.

  • emptylist (<list>`)` //since 4.11.3.7 [W/L/M]
    Leert die Liste.

  • reencodestrlist(<list>, <from>, <to>`)` //since 4.11.4.2 [W/L/M]
    liefert die Stringliste <list> mit dem Encoding <to> zurück. Dabei wird davon ausgangen, dass <list> gemäß <from> encoded war. <from> und <to> sind dabei Encodings wie sie im Kapitel opsi-script encoding aufgelistet sind.

  • removeFromListByContaining(<search string>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M]
    Liefert eine Kopie von <target list> bei der alle Zeilen entfernt sind in denen <search string> vorkommt. Der Vergleich ist case insensitiv.

  • removeFromListByContaining(<search list>`,` <target list>`) : stringlist` [W/L/M]
    Liefert eine Kopie von <target list> bei der alle Zeilen entfernt sind in denen ein String aus <search list> vorkommt. Der Vergleich ist case insensitiv.

Beispiele:

File "%Scriptpath%\test-files\encoding\10lines.txt" is:

line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
line 9
line 10

Code von opsi-script-test:

comment ""
comment "------------------------------"
comment "Testing: "
message "removeFromListByContaining"
set $string1$ = "%Scriptpath%\test-files\encoding\10lines.txt"
set $list1$ = loadTextFileWithEncoding($string1$, "cp1252")
comment "search with string"
comment "search with string constant"
set $ConstTest$ = "9"
set $list2$ = removeFromListByContaining("line 5", $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

set $ConstTest$ = "9"
set $list2$ = removeFromListByContaining("LINE 5", $list1$)
comment "the match is case insensitive"
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif


set $ConstTest$ = "0"
set $list2$ = removeFromListByContaining("line", $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

set $ConstTest$ = "8"
comment "searchstr 1 will found in 'line 1' and 'line 10'"
set $list2$ = removeFromListByContaining("1", $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

comment "search with string function"
set $ConstTest$ = "9"
set $list2$ = removeFromListByContaining(trim(" line 5 "), $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

comment "search with string variable"
set $string1$ = "line 5"
set $ConstTest$ = "9"
set $list2$ = removeFromListByContaining($string1$, $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

comment "search with string list"
comment "search with string list variable"
set $list3$ = createStringList ('1', '2', '3', '4', '5')
comment "searchstr 1 will found in 'line 1' and 'line 10'"
set $ConstTest$ = "4"
set $list2$ = removeFromListByContaining($list3$, $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

comment "search with string list variable"
comment "searchstr 1 will found in 'line 1' and 'line 10'"
set $ConstTest$ = "4"
set $list2$ = removeFromListByContaining(createStringList ('1', '2', '3', '4', '5'), $list1$)
set $CompValue$ = count($list2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • setStringInListAtIndex(<newstring>,<list>,<indexstr>`) : stringlist` //since 4.11.6 [W/L/M]
    Liefert eine Kopie von <list>, bei der der String an der Stelle <indexstr> durch <newstring> ersetzt ist. Wenn <indexstr> zu groß ist, wird <newstring> angehängt.
    Im Fehlerfall ist das Ergebnis eine leere Liste.
    see also : [takeString]

  • areListsEqual(<strlist1>, <strlist2>, <flag>) : boolean
    Vergleicht die beiden Stringlisten <strlist1> und <strlist2> und gibt wahr (true) zurück wenn sie gleich sind. Dabei steuert der Parameter <flag> wie verglichen wird:
    flag=FLAG_AUTOMODE: case-insensitiver Vergleich. Die Stringlisten können Schlüssel/Wert-Stringlisten (Schlüssel1=Wert1) oder einfache Stringlisten sein
    flag=FLAG_AUTO_CS: case-sensitiver Vergleich. Die Stringlisten können Schlüssel/Wert-Stringlisten (Schlüssel1=Wert1) oder einfache Stringlisten sein
    flag=FLAG_STRING_CS: case-sensitiver Vergleich von einfachen Stringlisten (d.h. ein Schlüssel/Wert-Format wird nicht berücksichtigt).

Iteration durch String-Listen [W/L/M]

Eine besonders wichtige Anwendung von String-Listen beruht auf der Möglichkeit, die Elemente einer String-Liste zu durchlaufen und für jedes Element eine vorgegebenes Anweisungsschema auszuführen:

Die Syntax für eine solche Iteration („Wiederholungsanweisung“) lautet:

  • for %s% in <list> do <eine Anweisung>

Dabei wird %s% durch diesen Ausdruck und nur für diese Stelle als String-Variable deklariert und ist danach wieder unbekannt. Innerhalb der Anweisung wird jedes Vorkommen von %s% (oder wie auch immer eine entsprechende Variable benannt ist) der Reihe nach durch die verschiedenen Elemente der Liste ersetzt.

Die Ersetzung ist (wie bei Systemkonstanten) rein textuell, d.h. genau die Zeichenfolge %s% wird z.B. durch die Werte a b c - ersetzt. Sind die Strings 'a','b','c' gemeint, muss in der auszuführenden Anweisung %s% von Anführungszeichen eingeschlossen sein.

Ein Beispiel: Wenn $list1$ für 'a', 'b', 'c', 'd', 'e' steht und $line$ als String-Variable deklariert ist, so bedeutet:

for %s% in $list1$ do   set $line$ = $line$ + "%s%"

der Reihe nach

$line$ = $line$ + "a"
$line$ = $line$ + "b"
$line$ = $line$ + "c"
$line$ = $line$ + "d"
$line$ = $line$ + "e"

so dass am Ende $line$ den Wert 'abcde' trägt. Wenn wir die einfachen Anführungszeichen um das %s% weglassen würden, bekämen wir bei jedem Schritt der Iteration einen Syntaxfehler gemeldet.

opsiservicecall und JSON Funktionen [W/L/M]

Diese Funktionen dienen dazu JSON Ausdrücke auf String oder Stringlisten zu analysieren und zu modifizieren. Notwendig ist hierfür, die Struktur des zu bearbeitenden JSON-Ausdrucks zu kennen und zu verstehen.
Diese Funktionen können auch hilfreich sein um opsiservicecall Sektionen zu verwenden.

  • jsonIsValid(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    Liefert 'true' zurück wenn, <jsonstr> einen gültigen JSON Ausdruck enthält.

  • jsonIsArray(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    Liefert 'true' zurück wenn, <jsonstr> ein gültiges JSON Array enthält.

  • jsonIsObject(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    Liefert 'true' zurück wenn, <jsonstr> ein gültiges JSON Object enthält.

  • jsonAsObjectHasKey(<jsonstr>,<keystr>`) : boolean` //since 4.11.6: [W/L/M]
    Liefert 'true' zurück wenn, <jsonstr> ein gültiges JSON Object welches <keystr> als key enthält.
    Folgendes Beispiel würde 'true' zurückliefern:

jsonAsObjectHasKey('{"productVersion" : "4.4.1","packageVersion" : "2","productId" : "jedit"}','productId')

  • jsonAsArrayCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M]
    Wenn <jsonstr> ein gültiges JSON Array enthält ist der Rückgabewert ein String mit der Zahl der Elemente des Arrays.
    Im Fehlerfall = '"0"'

  • jsonAsObjectCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M]
    Wenn <jsonstr> ein gültiges JSON Objkt enthält ist der Rückgabewert ein String mit der Zahl der Elemente des Objektes.
    Im Fehlerfall = '"0"'

  • jsonAsArrayGetElementByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6: [W/L/M]
    Liefert vom JSON Array <jsonstr> das Element mit dem Index <indexstr>
    Der Index beginnt bei 0.
    Im Fehlerfall = '""'

  • jsonAsObjectGetValueByKey(<jsonstr>, <keystr>`) : valuestring` //since 4.11.6: [W/L/M]
    Liefert vom JSON Object <jsonstr> den Wert des Key <keystr>
    Im Fehlerfall = '""'

  • jsonAsObjectSetValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M]
    Liefert einen String mit dem in <jsonstr> übergebenen JSON Object bei dem für den Key <keystr> der Wert <valuestring> gesetzt ist. Ist der Key nicht vorhanden, so wird er erzeugt.
    Wenn <valuestring> als Stringwert erzeugt werden soll (also in doppelten Anführungszeichen), dann verwenden Sie besser die folgende Funktion: [jsonAsObjectSetStringtypeValueByKey].
    Im Fehlerfall = '""'

  • jsonAsObjectSetStringtypeValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M]
    Liefert einen String mit dem in <jsonstr> übergebenen JSON Object bei dem für den Key <keystr> der Wert <valuestring> als String (also in doppelten Anführungszeichen) gesetzt ist. Ist der Key nicht vorhanden, so wird er erzeugt.
    Wenn <valuestring> nicht als Stringwert erzeugt werden soll , dann verwenden Sie besser die vorherige Funktion: [jsonAsObjectSetValueByKey].
    Im Fehlerfall = '""'

  • jsonAsObjectDeleteByKey(<jsonstr>, <keystr>`) : jsonstring` //since 4.11.6.4: [W/L/M]
    Liefert einen String mit dem in <jsonstr> übergebenen JSON Object bei dem das key-value Paar mit dem Key <keystr> entfernt wurde.

  • jsonAsArrayPutObjectByIndex(<jsonstr>, <indexstr>, <objectstr>`) : jsonstring` //since 4.11.6: [W/L/M]
    Liefert einen String mit dem in <jsonstr> übergebenen JSON Array bei dem am Index <indexstr> das Object <objectstr> gesetzt ist.
    Im Fehlerfall = '""'

  • jsonAsArrayDeleteObjectByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6.4: [W/L/M]
    Liefert einen String mit dem in <jsonstr> übergebenen JSON Array bei dem das Objekt am Index <indexstr> entfernt wurde.
    Im Fehlerfall = '""'

  • jsonAsArrayToStringList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M]
    Liefert eine Stringliste mit dem in <jsonstr> übergebenen JSON Array als Stringliste mit einem Arrayelement pro Zeile.

  • jsonStringListToJsonArray(<strlist>`) : jsonstr` //since 4.11.6: [W/L/M]
    Liefert einen String mit einem JSON Array der die Zeilen der Stringliste <strlist> als Elemente enthält.

  • jsonAsObjectGetKeyList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M]
    Liefert eine Stringliste mit den Keys der im JSON Object <jsonstr> vorhandnen Keys.

Beispiel:
Lese productOnClients Objekte aus einer Datei, ändere die clientId auf den Wert der aktuellen Maschine und schreibe die Objekte über den opsi-webservice zurück.

DefVar $poc_file$
DefVar $objectStr$
DefVar $ArrayStr$
DefVar $pid$

DefStringlist $resultlist$
DefStringlist $resultlist1$
DefStringlist $productIdList$
DefStringlist $pocList$


Message "Delete productOnClient from opsi backend ..."
set $resultlist$ = getReturnListFromSection("opsiservicecall_getPOC")
Set $ArrayStr$ = takestring(0, $resultlist$)
if not(jsonIsValid($ArrayStr$))
	LogError "got no valid json from Service"
	isFatalError
endif
if not(jsonIsArray($ArrayStr$))
	LogError "got no json Array from Service"
	isFatalError
endif
comment "extract productIds ..."
comment "clean target list"
set $productIdList$ = emptylist($productIdList$)
comment "get stringlist "
set $pocList$ = jsonAsArrayToStringList($ArrayStr$)
for %aktpoc% in $pocList$ do sub_fill_product_ids
for %aktProductId% in $productIdList$ do opsiServiceCall_del_productOnClient

Message "Restore productOnClient from file ..."
comment " get Restore data from file ..."
Set $ArrayStr$ = strLoadTextFile($poc_file$)
if not(jsonIsValid($ArrayStr$))
	LogError "got no valid json from file"
	isFatalError
endif
if not(jsonIsArray($ArrayStr$))
	LogError "got no json Array from file"
	isFatalError
endif

comment "get list from array"
set $pocList$ = jsonAsArrayToStringList($ArrayStr$)
comment "loop over list"
for %pocindex% = "0" to calculate(count($pocList$)+"-1") do sub_set_clientid_in_poclist
comment "convert modified list to jason array"
set $ArrayStr$ = jsonStringListToJsonArray($pocList$)
set $ArrayStr$ = unquote2($ArrayStr$,"[]")
comment "write back"
opsiServiceCall_updatePOC

[sub_fill_product_ids]
set $objectstr$ = '%aktpoc%'
set $pid$ = jsonAsObjectGetValueByKey($objectstr$, "productId" )
set $productIdList$ = addToList($productIdList$,$pid$)

[sub_set_clientid_in_poclist]
set $objectStr$ = takeString("%pocindex%", $poclist$)
set $objectStr$ = jsonAsObjectSetStringtypeValueByKey(($objectStr$, "clientId","%opsiserviceUser%")
set $poclist$ = setStringInListAtIndex($objectStr$,$poclist$,"%pocindex%")

[opsiServiceCall_updatePOC]
"method": "productOnClient_updateObjects"
"params": [
					'$ArrayStr$',
					]

[opsiservicecall_getPOC]
	"method": "productOnClient_getObjects"
	"params":[
           "[]",
           '{"clientId":"%opsiserviceUser%","productType":"LocalbootProduct"}'
           ]

[opsiServiceCall_del_productOnClient]
"method": "productOnClient_delete"
"params": [
					'%aktProductId%',
					'%opsiserviceuser%',
					]

Umgang mit Zahlen [W/L/M]

Es gibt im opsi-script keine speziellen Variablen für Zahlen. Es gibt allerdings einige Funktionen welche beim Umgang mit Zahlen helfen.

  • calculate(<str>`)` [W/L/M]
    Stringfunktion welch den arithmetischen Ausdruck im String <str> berechnet und als gerundeten integer string zurückgibt.
    Intern werden die Berechnungen mit reellen Zahlen durchgeführt. Die Funktion kennt derzeit die Operatoren +, -, , / sowie Klammern (,).
    Im Fehlerfall wird ein leerer String zurückgegeben und der Errorcounter um eins erhöht Enthält der übergebene String Zeichen die keine Zahlen oder gültige Operatoren sind, so ist dies ein Fehler.
    Fehlt der zweite Operator, so wird hierfür der erste verwendet: 5+ = 10 ; 5
    = 25. Daher sollte beim Zusammensetzen des übergebenen strings verwendete Variablen z.B. mit der Funktion isNumber auf Gültigkeit geprüft werden.
    Seit 4.11.3.5
    siehe auch : [isNumber]

Beispiele:

set $ConstTest$ = "0"
set $CompValue$ = calculate("-1+1")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $ConstTest$ = "1"
set $CompValue$ = calculate("0+1")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $ConstTest$ = "-1"
set $CompValue$ = calculate("0-1")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "5"
set $ConstTest$ = "25"
set $CompValue$ = calculate($string1$+"*"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "5"
set $ConstTest$ = "1"
set $CompValue$ = calculate($string1$+"/"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "0"
set $ConstTest$ = ""
comment " expecting devision by zero error and empty string result"
set $CompValue$ = calculate($string1$+"/"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "9"
set $string2$ = "10"
set $ConstTest$ = "1"
comment "result 0.9 is rounded to 1 "
set $CompValue$ = calculate($string1$+"/"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "10"
set $string2$ = "9"
set $ConstTest$ = "1"
comment "result 1.1111 is rounded to 1 "
set $CompValue$ = calculate($string1$+"/"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "5"
set $ConstTest$ = "55"
comment " rule * before +"
set $CompValue$ = calculate($string1$+"+"+$string2$+"*10")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "5"
set $ConstTest$ = "100"
comment "brackets before  rule * before + "
set $CompValue$ = calculate("("+$string1$+"+"+$string2$+")*10")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "ten"
set $ConstTest$ = ""
comment "invalid char error"
set $CompValue$ = calculate($string1$+"*"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = ""
set $ConstTest$ = "25"
comment "5* is interpreted as 5*5"
set $CompValue$ = calculate($string1$+"*")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = ""
set $ConstTest$ = "10"
comment "5+ is interpreted as 5+5"
set $CompValue$ = calculate($string1$+"+")
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "nothing"
set $string2$ = "foo"
set $ConstTest$ = ""
comment "invalid char error"
set $CompValue$ = calculate($string1$+"*"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
set $string1$ = "5"
set $string2$ = "foo"
set $ConstTest$ = ""
comment "invalid char error"
set $CompValue$ = calculate($string1$+"/"+$string2$)
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

Für weitere Beispiele beachten Sie das Produkt 'opsi-script-test' und dort den Bereich '$Flag_calculate$ = "on"'

Es gibt einen Vergleichsausdruck um zwei Strings wie (integer) Zahlen zu vergleichen. Wenn einer der Werte nicht in eine Zahl übertragen werden kann, wird ein Fehler ausgegeben.
Diese Zahlenvergleichsausdrücke haben die gleich Form wie die String-Vergleichsausdrücke, allerdings wird dem dem Vergleichszeichen ein INT vorangestellt:
<STRINGAUSDRUCK> INT<Vergleichszeichen> <STRINGAUSDRUCK>
So können Ausdrücke wie

if $Name1$ INT<= $Name2$

oder

if $Number1$ INT>= $Number2$

gebildet werden.

siehe auch: Boolesche Ausdrücke

  • isNumber(<str>`)` [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn <str> einen ganzahligen Wert (integer) representiert.
    Seit 4.11.3
    see also : [calculate]

XML2 Funktionen [W/L/M]

Die XML2 Implementierung ist derzeit (4.2019 Version 4.12.1) neu. Das bedeutet das die Implementierung noch unvollständig ist. Daher werden sich bestimmt einige Dinge in den nächsten Releses hinzugefügt werden. Wenn Sie Probleme finden oder Featurewünsche haben, so scheuen Sie nicht uns zu kontaktieren.
Diese neue 'XML2' Sektion und die 'XML2' Funktionen ersetzen die alte und nur für Windows verfügbare XMLPatch Sections.

Für die in diesem Kapitel verwendeten Begrifflichkeiten (wording) lesen Sie bitte das Kapitel XML Struktur und Begriffe

Encoding

XML Dateien sind in der Regel im encoding UTF-8 verfasst.
Dies wird von den 'XML2' Funktionen so vorausgesetzt.
Bei der XML2 Sektion gibt es die Möglichkeit auch andere Encodings anzugeben.

getXml2DocumentFromFile(<path to xml file>`) : xml2stringlist` //since 4.12.1
Liest die in <path to xml file> gegebene xml Datei und liefert eine Stringliste zurück vom Format xml2stringlist welche in anderen xml2 Funktionen weiterverwendet werden kann.
Für Beispiele siehe 'XML2 Sektionen' / 'Beispiele' XML2 Beispiele

getXml2Document(<stringlist with xml>`) : xml2stringlist` //since 4.12.1
Wenn die <stringlist with xml> gültiges xml enthält, so liefert die Funktion eine Stringliste zurück vom Format xml2stringlist welche in anderen xml2 Funktionen weiterverwendet werden kann.

xml2GetFirstChildNodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1.
Sucht in der übergebenen <xml2stringlist> das erste Vorkommen eines node mit dem Namen <node name str> und liefert diesen node (mit allen child nodes) als xml2stringlist zurück.
Für Beispiele siehe 'XML2 Sektionen' / 'Beispiele' XML2 Beispiele

getXml2UniqueChildnodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1.
Sucht in der übergebenen <xml2stringlist> nach Vorkommen eines node mit dem Namen <node name str> prüft ob dieser <node name str> nur einmal vorkommt und liefert diesen node (mit allen child nodes) als xml2stringlist zurück.
Wird kein Vorkommen oder mehrere gefunden, wird eine leere liste zurückgegeben.

getXml2AttributeValueByKey(<xml2stringlist>, <attr name str>`) : string` //since 4.12.1.
Sucht in der übergebenen <xml2stringlist> den ersten node und in diesem node nach einem attribut mit dem Namen <attr name str> und liefert den Wert dieses Attributes als string zurück.
Wenn das Attribute nicht gefunden wird oder bei einem anderen Fehler wird ein leerer String zurückgeliefert.
Für Beispiele siehe 'XML2 Sektionen' / 'Beispiele' XML2 Beispiele

getXml2Text(<xml2stringlist>`) : string` //since 4.12.1.
Liefert die als <xml2stringlist> übergebenen xml Daten als einzeilen String zurück.

siehe auch : XML related functions (XML2)
siehe auch : XML2 Sektion

Funktionen um TOML Dateien zu bearbeiten [W/L/M]

Ab opsi-script v. 4.12.5 unterstützt opsi-script die Handhabung von TOML-Dateien.

opsi-script unterstützt derzeit nicht die Behandlung von Kommentaren innerhalb von TOML-Dateien. Beim Einfügen von Daten in Tabellen/Bereichen mit Kommentaren gehen diese evtl. verloren.
Die offiziellen TOML-Spezifikationen finden sie unter https://toml.io/en/
Encoding

TOML-Dateien sind normalerweise in UTF-8 codiert. Die 'TOML'-Funktionen erwarten also, dass die angegebenen TOML-Dateien in UTF-8 vorliegen.

Ein vollständiges Beispiel-Skript mit allen TOML-Funktionen ist weiter unten zu finden.

  • LoadTOMLFile(<TOMLfilePath: String>`) : StringList` //seit 4.12.5.0
    Liest die TOML-Datei <TOMLfilePath> ein und gibt den Dateiinhalt als Stringliste zurück.

  • ReadTOMLFile(<TOMLfilePath: String>`) : String` //seit 4.12.5.0
    Liest die TOML-Datei <TOML-Dateipfad> ein und gibt den Dateiinhalt als String zurück.
    Dieser String wird zum Manipulieren von TOML-Dateien in den kommenden Funktionen verwendet.

Bitte beachten Sie, dass diese Funktion keine Kommentare speichert.

  • GetTOMLAsStringList(<TOMLcontents: String>`) : StringList` //seit 4.12.5.0
    Parst den TOML-String-Inhalt <TOMLcontents> und gibt eine Stringliste des geparsten TOML-Inhalts zurück.

  • GetTOMLAsString(<TOMLcontents: String>`) : String` //seit 4.12.5.0
    Parst den TOML-String-Inhalt <TOMLcontents> und gibt einen String des geparsten TOML-Inhalts zurück.

  • GetTOMLKeys(<TOMLcontents: String>`) : StringList` //seit 4.12.5.0
    Sucht im angegebenen <TOMLcontents>-String nach allen Keys und gibt eine StringListe der gefundenen Keys zurück.
    Wenn kein Key gefunden wird, wird eine leere Stringliste zurückgegeben.

Diese Funktion gibt nur die Keys des angegebenen Strings zurück, die als root tabelle analysiert wurden, einschließlich der Namen ihrer Untertabellen. Sie enthält nicht die Keys irgendeiner Untertabelle.

  • GetTOMLTableNames(<TOMLcontents: String>`) : StringList` //seit 4.12.5.0
    Sucht in der angegebenen <TOMLcontents>-String nach allen Tabellen der Stammtabelle und gibt eine Stringliste mit den Namen der gefundenen Tabellen zurück.
    Wenn keine Tabelle gefunden wird, wird eine leere Stringliste zurückgegeben.

  • GetTOMLTable(<TOMLcontents: String> , <table name : String>`) : StringList` //seit 4.12.5.0
    Sucht in den angegebenen <TOMLcontents>-String nach einer Tabelle mit dem angegebenen <table name> und gibt eine Stringliste des gefundenen Tabelleninhalts zurück.

  • GetTOMLTableAsString(<TOMLcontents: String> , <table name : String>`) : String` //seit 4.12.5.0.
    Sucht in den angegebenen <TOMLcontents>-String nach einer Tabelle mit dem angegebenen <table name> und gibt einen String des gefundenen Tabelleninhalts zurück.

  • GetValueFromTOML(<TOMLcontents: String> , <keyPath: String> , <defaultValue: String>`) : String` //seit 4.12.5.0
    Sucht in der angegebenen <TOMLcontents>-String nach dem Key, der mit <keyPath> definiert ist, also:

    • Ein einfacher Key, wenn sich der Key in der Stammtabelle befindet.

    • Ein zusammengesetzter Key-Path: Abfolge der Tabellennamen, die das gesuchte Key-Value-Paar enthalten. Zum Beispiel: "Tabelle.Untertabelle.Key"
      und gibt einen String mit dem entsprechenden Value zurück, falls gefunden.

Wenn der angegebene Key nicht gefunden wird oder der angegebene Key-Path falsch oder unvollständig ist oder kein Value gefunden wurde, wird die Eingabezeichenfolge <defaultValue> zurückgegeben.

Diese Funktion gibt den genauen Value als String-Ausgabe zurück. Wenn also beispielsweise der gesuchte Value ein String mit dem Inhalt "opsi" ist, dann ist das Ergebnis dieser Funktion: '"opsi"'

  • ModifyTOML(<TOMLcontents: String> , <command: String> , <keyPath: String> , <value: String>`) : String` //seit 4.12.5.0
    Diese Funktion ermöglicht es, den als Eingabe angegebenen <TOMLcontents>-String mithilfe von 4 Befehlen zu ändern:

    • 'ADD' : Fügt das Eingabepaar <keyPath>-<value> hinzu, wenn der Key nicht existiert. Es gibt einen neuen modifizierten TOMLcontens-String zurück.
      Wenn der <keyPath> existiert, nimmt diese Funktion keine Änderungen vor. Derselbe Eingabe-String <TOMLcontents> wird zurückgegeben.

    • 'SET' : Legt ein neues <keyPath>-<value>-Paar fest, unabhängig davon ob der Key existiert oder nicht. Mit <Value> wird der entsprechende Value geändert.
      Die Funktion gibt den neuen modifizierten TOMLcontens-String zurück.

    • 'CHANGE ' : Ändert den entsprechenden Value im <keyPath> auf den angegebenen <value>. Es gibt einen neuen modifizierten TOMLcontens-String zurück.
      Wenn der KeyPath/Key nicht existiert, wird nichts getan. Derselbe Eingabe-String <TOMLcontents> wird zurückgegeben.

    • 'DEL' : Löscht den <keyPath> und den dazugehörigen Value. Es gibt einen neuen modifizierten TOMLcontens-String zurück.
      Wenn der keyPath nicht existiert, wird nichts getan. Derselbe Eingabe-String <TOMLcontents> wird zurückgegeben.

Wenn eine Behandlungsausnahme auftritt, wird der selbe Eingabe-<TOMLcontents>-String zurückgegeben.
Wenn ein Fehler auftritt, wird ein leerer String zurückgegeben.

Beachten Sie, dass beim Hinzufügen von Werten die TOML-Notation innerhalb des Eingabe-String-Parameters gemäß der offiziellen Spezifikation berücksichtigt werden muss (siehe https://toml.io/en/).

Zum Beispiel:

  • Wenn Sie einen Value vom Typ String mit dem Inhalt "Neuer Wert" hinzufügen möchten, sollte er wie folgt zwischen doppelten Anführungszeichen geschrieben werden:
    <Value> = ' "Neuer Value" '

  • Wenn Sie einen Value vom Typ Boolean mit dem Inhalt True hinzufügen möchten, sollte er wie folgt geschrieben werden:
    <Value> = 'True'

  • Wenn Sie einen Value vom Typ Zahl mit dem Inhalt 1.1 hinzufügen möchten (Floats werden mit einem . geschrieben, nicht mit einem , ), sollte er wie folgt geschrieben werden:
    <Value> = ' 1.1 '

  • Wenn Sie einen Value vom Typ Array mit dem Inhalt ["erster Value", "zweiter Value"] hinzufügen möchten, sollte er wie folgt geschrieben werden:
    <Value> = ' ["erster Value", "zweiter Value"] '

  • Wenn Sie einen Datumstypwert mit dem Inhalt 2022-02-02T16:16:00Z-16:16 hinzufügen möchten, sollte er wie folgt geschrieben werden:
    <Value> = ' 2022-02-02T16:16:00Z-16:16 '

Alle Beispiele sind im Skript-Beispiel weiter unten enthalten.

  • DeleteTableFromTOML(<TOMLcontents: String> , <tablePath: String>`) : String` //seit 4.12.5.0
    Löscht den gesamten angegebenen <tablePath> mit seinen Key-Value-Paaren und Untertabellen, sofern vorhanden, aus dem angegebenen <TOMLcontents>-String.
    Wenn der angegebene <tablePath> nicht gefunden wird, werden keine Änderungen vorgenommen und derselbe Eingabe-String <TOMLcontents> wird zurückgegeben.

  • SaveToTOMLFile(<TOMLcontents: String> , <TOML file Path: String>`) : boolean` //seit 4.12.5.0
    Speichert den <TOMLcontents>-String im TOML-Format im angegebenen <TOML file path>.
    Läuft das Speichern der Datei fehlerfrei, wird „True“ zurückgegeben.
    Wenn Fehler auftreten, wird "False" zurückgegeben.

  • ConvertTOMLtoJSON(<TOMLcontents: String>`) : String` //seit 4.12.5
    Konvertiert den angegebenen <TOMLcontents> String in einen JSON-formatierten String.

  • ConvertTOMLfileToJSONfile(<TOMLfilePath: String> , <JSONfilePath: String>`) : boolean` //seit 4.12.5.0
    Diese Funktion konvertiert den Inhalt der angegebenen TOML-Datei <TOMLfilePath> in einen JSON-String und speichert ihn unter dem angegbenen <JSONfilePath>.
    Läuft das Speichern der Datei fehlerfrei, wird „True“ zurückgegeben.
    Wenn Fehler auftreten, wird "False" zurückgegeben.

Beispiel:

Datei "TOMLfile.toml" ist:

# This is a TOML document.
title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
server = "192.168.1.1"
ports = [ 8000, 8001, 8002 ]
connection_max = 5000
enabled = true

[servers]
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [ ["gamma", "delta"], [1, 2] ]
hosts = [
  "alpha",
  "omega"
]
comment "Testing TOML functions"

DefVar $TOMLFile$
DefVar $TOMLString$
DefStringList $TOMLlist$
DefVar $TOMLdata$
Set $TOMLFile$ = $HomeTestFiles$ + "TOMLfile.toml"
Set $TOMLlist$ = LoadTOMLFile($TOMLFile$)
Set $TOMLString$ = ReadTOMLFile($TOMLFile$)
Set $TOMLlist$ = GetTOMLKeys($TOMLString$)
Set $TOMLlist$ = GetTOMLTableNames($TOMLString$)

Set $TOMLlist$ = GetTOMLTable($TOMLString$, "owner")
Set $TOMLdata$ = GetTOMLTableAsString($TOMLString$, "owner")
Set $TOMLdata$ = GetTOMLTableAsString($TOMLString$, "servers")
Set $TOMLlist$ = GetTOMLTableNames($TOMLdata$)

Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "" , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "    " , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "key" , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "title" , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "owner.name" , "defaultValue")
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "servers.alpha.ip" , "defaultValue")

Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "servers.beta.key" , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "clients.data " , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "database.ports" , "defaultValue" )
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "database.connection_max" , "defaultValue")
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "database.enabled" , "defaultValue")
Set $TOMLdata$ = GetValueFromTOML( $TOMLString$ , "servers.beta" , "defaultValue")

Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'title',  '"newADDvalueInRootTable"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newADDkeyInRootTable', '"newADDvalueInRootTable"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'servers.alpha.a.newADDkeyInAlphaA', '"newADDvalueInAlphaA"')

Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newADDtableKey', '"newADDtableValue"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newStringKey', '"newStringValue"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newIntegerKey', '1')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newFloatKey', '10.1')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newDateKey', '2022-02-02T16:16:00Z-16:16')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'ADD', 'newTable.newArray', '[ "a", "b", "c" ]')

Set $TOMLString$ = ModifyTOML($TOMLString$, 'SET',' newADDkeyInRootTable', '"newSETValueInRootTable"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'SET', 'newSETkeyInRootTable', '"newSETValueInRootTable"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'SET', 'servers.alpha.a.newADDkeyInAlphaA', '"newSETValueInAlphaA"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'SET', 'newTable.newADDtableKey', '"newSETtableValue"'

Set $TOMLString$ = ModifyTOML($TOMLString$, 'CHANGE', 'newCHANGEkeyInRootTable', ' "newCHANGEValueInRootTable" ')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'CHANGE', 'newSETkeyInRootTable', '"newCHANGEValueInRootTable"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'CHANGE', 'servers.alpha.a.newADDkeyInAlphaA', '"newCHANGEValueInAlphaA"')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'CHANGE', 'newCHANGETable.newCHANGEtableKey', ' "newCHANGEtableValue" '

Set $TOMLString$ = ModifyTOML($TOMLString$, 'DEL', 'newSETkeyInRootTable', '')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'DEL', 'DELkeyInRootTable', '')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'DEL', 'servers.alpha.a.newADDkeyInAlphaA', '')
Set $TOMLString$ = ModifyTOML($TOMLString$, 'DEL', 'DELTable.DELtableKey', '')

Set $TOMLString$ = DeleteTableFromTOML($TOMLString$, "newTable")

Set $newTOMLFile$ = $HomeTestFiles$ + "TOMLempty.toml"
Set $TestString$ = booltostring(SaveToTOMLFile($TOMLString$,$newTOMLFile$))
Set $newJSONFile$ = $HomeTestFiles$ + "myJSONfromTOMLdata.json"
set $TestString$ = booltostring(ConvertTOMLfileToJSONfile($newTOMLFile$,$newJSONFile$))

Nach ausführen des Skriptes sieht die TOML-Datei folgendermaßen aus:

# This is a TOML document.
title = "TOML Example"
newADDkeyInRootTable = "newSETValueInRootTable"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00Z-07:32

[database]
server = "192.168.1.1"
ports = [ 8000, 8001, 8002 ]
connection_max = 5000
enabled = true

[servers]
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"
  [servers.alpha.a]

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [  [ "gamma", "delta" ], [ 1, 2 ]  ]
hosts = [  "alpha",  "omega" ]

Regular expression related functions [W/L/M]

Das Arbeiten mit 'regular expressions' hat einige Nachteile:
Das herausfinden der richtigen 'regular expression' kann eine schwierige Aufgabe sein. Also verwenden Sie Werkzeuge zum Testen Ihrer 'regular expressions'.
Die Verwendung von 'regular expressions' führt schnell zu unverständlichen Code, da einer 'regular expression' nicht auf dem aller ersten Blick anzusehen ist was sie macht. Also erläutern Sie in Kommentaren in Ihrem Code was die 'regular expressions' tun sollen.

Es gibt unterschiedliche Varianten von 'regular expressions': Perl, Javascript, Java, …​
Die hier implementierte Variante ist eine Variante von perl style or PCRE.
Eine Dokumentation der hier implementierten Variante finden Sie hier:
https://regex.sorokin.engineer/de/latest/regular_expressions.html

Verwenden Sie ein Werkzeug zum Testen Ihrer 'regular expressions'.
Wir empfehlen Ihnen die 'opsi-regexpr-tester.exe' Anwendung, welche Sie hier herunterladen können:
https://download.uib.de/opsi4.2/misc/helper/opsiRegExprTest.exe

  • opsi-regexpr-tester.exe

Diese Anwendung (opsi-regexpr-tester.exe) hilft Ihnen Ihre Regular Expression zu testen.

opsi-regexpr-tester-start

Das Anwendungsfenster von 'opsi-regexpr-tester' bietet Ihnen zwei Felder:
Im ersten Feld ('Regular Expression :') tragen Sie Ihre Regular Expression ein.
Im zweiten Feld ('Text :') Tragen Sie den Text ein, gegen den die Regular Expression getestet werden soll.
Darüberhinaus können Sie noch 'Pattern Modifiers Flags' angeben, welche die Auswertung der Regular Expression beeinflussen. Details dazu finden Sie in der erwähnten Dokumentation:
https://regex.sorokin.engineer/en/latest/regular_expressions.html
Angeboten werden 6 Flags :

  • i, case-insensitive (Groß- / Kleinschreibung ignorieren)

  • m, multi-line strings

  • s, single line strings

  • g, greediness (Gierigkeit)

  • x, eXtended syntax

  • r, Russian ranges

Sie können durch anklicken der entsprechenden Checkboxen diese Flags aktivieren. Die Flags werden dann am Anfang der Regular Expression hinzugefügt.
Die Flags müssen vor dem Abschnitt stehen für den sie gelten sollen.

Durch drücken des Buttons 'Examine' können Sie nun Ihre Regular Expression testen.

opsi-regexpr-tester-input

Wenn die Regular Expression zu dem Text (oder teilen davon) passt, so werden die passenden Teile grün markiert und 'successful' angezeigt.

opsi-regexpr-tester-success

Wenn die Regular Expression zu keinem Textteil passt, so wird ein Fehler angezeigt.

opsi-regexpr-tester-failure

Über den Button 'clear' können die Eingabefelder gelöscht werden.

  • isRegexMatch(<string>, <pattern>`) : boolean`
    Hierbei ist <pattern> eine 'regular expression' und <string> der zu prüfende String. Die Funktion liefert 'true' zurück wenn <pattern> zu dem <string> passt ('matched') und 'false' wenn es kein 'match' gibt.

Beispiel:

comment "Testing with matching string"

set $ConstTest$ = "true"
set $CompValue$ = booltostring(isRegexMatch('abc efg', '.*abc.*'))
if ($ConstTest$ = $CompValue$)
	comment "isRegexMatch passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isRegexMatch failed"
endif

comment "Testing with non matching string"

set $ConstTest$ = "false"
set $CompValue$ = booltostring(isRegexMatch('abc efg', '.*xyz.*'))
if ($ConstTest$ = $CompValue$)
	comment "isRegexMatch passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isRegexMatch failed"
endif

  • getSubListByContainingRegex(<pattern>, <target list>`) : stringlist`
    Liefert eine Stringliste zurück welche die Strings aus <target list> enthalten bei denen zumindest ein Teil mit <pattern> matched.

  • getSubListByContainingRegex('<pattern list>, <target list>') : stringlist
    Liefert eine Stringliste zurück welche die Strings aus <target list> enthalten bei denen zumindest ein Teil mit einem pattern aus <pattern list> matched.

Beispiel:

comment "Testing with a single pattern"

set $string1$ = "\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}"
set $list1$ = createStringList('uib gmbh','example@xyz.com and example2@xyz.com', 'client')
set $ConstTest$ = "example@xyz.com and example2@xyz.com"

set $list2$ = getSubListByContainingRegex($string1$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "getSubListByContainingRegex passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing getSubListByContainingRegex failed"
endif


comment "Testing with a list of patterns"

set $list3$ = createStringList('\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}','.*uib')
set $ConstTest$ = "uib gmbh | example@xyz.com and example2@xyz.com"

set $list2$ = getSubListByContainingRegex($list3$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "getSubListByContainingRegex passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing getSubListByContainingRegex failed"
endif

  • getRegexMatchList(<pattern>, <target list>`) : stringlist`
    Liefert eine Stringliste zurück welche die Strings aus <target list> enthalten welche vollständig mit <pattern> matchen.

  • getRegexMatchList(<pattern list>, <target list>) : stringlist
    Liefert eine Stringliste zurück welche die Strings aus <target list> enthalten welche vollständig mit einem pattern aus <pattern list> matchen.

Beispiel:

comment "Testing with a single pattern"

set $string1$ = "\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}"
set $list1$ = createStringList('uib gmbh','client','example@xyz.com and example2@xyz.com')
set $ConstTest$ = "example@xyz.com | example2@xyz.com"

set $list2$ = getRegexMatchList($string1$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "getRegexMatchList passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing getRegexMatchList failed"
endif


comment "Testing with a list of patterns"

set $list3$ = createStringList('\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}','.*uib')
set $ConstTest$ = "uib | example@xyz.com | example2@xyz.com"

set $list2$ = getRegexMatchList($list3$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "getRegexMatchList passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing getRegexMatchList failed"
endif

  • removeFromListByContainingRegex(<pattern>, <target list>`) : stringlist`
    Liefert eine Stringliste bei der die Strings aus <target list> entfernt worden sind, welche ganz oder zum Teil mit <pattern> matchen.

  • removeFromListByContainingRegex(<pattern list>, <target list>`) : stringlist`
    Liefert eine Stringliste bei der die Strings aus <target list> entfernt worden sind, welche ganz oder zum Teil mit pattern aus <pattern list> matchen.

Beispiel:

comment "Searching with a single expression"

set $string1$ = "\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}"
set $list1$ = createStringList('uib gmbh','client','example@xyz.com and example2@xyz.com')
set $ConstTest$ = "uib gmbh | client"

set $list2$ = removeFromListByContainingRegex($string1$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "removeFromListByContainingRegex passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing removeFromListByContainingRegex failed"
endif

comment "Searching with a list of expressions"

set $list3$ = createStringList('\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}','.*uib')
set $ConstTest$ = "client"

set $list2$ = removeFromListByContainingRegex($list3$, $list1$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "removeFromListByContainingRegex passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing removeFromListByContainingRegex failed"
endif

  • stringReplaceRegex(<string>, <pattern>, <replacement string>`) : string`
    Liefert einen String bei dem die matches von <pattern> in <string> durch <replacement string> ersetzt worden sind.

Example:

set $ConstTest$ = "xyz abc gmbh"
set $CompValue$ = stringReplaceRegex('uib gmbh','.*uib', 'xyz abc')
if ($ConstTest$ = $CompValue$)
		comment "stringReplaceRegex passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing stringReplaceRegex failed"
endif

  • stringReplaceRegexInList<target list>, <pattern>, <replacement string>`) : stringlist`
    Liefert eine Stringliste bei dem die matches von <pattern> in einem String von <target list> durch <replacement string> ersetzt worden sind.

Example:

set $string1$ = "\w+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,6}"
set $string2$ = "MATCH REMOVED"
set $list1$ = createStringList('uib gmbh','client','example@xyz.com and example2@xyz.com')
set $ConstTest$ = 'uib gmbh | client | MATCH REMOVED and MATCH REMOVED'

set $list2$ = stringReplaceRegexInList($list1$, $string1$, $string2$)

set $CompValue$ = composeString ($list2$, " | ")
if ($ConstTest$ = $CompValue$)
		comment "stringReplaceRegexInList passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing stringReplaceRegexInList failed"
endif

Für weiter Beispiele schauen Sie im Produkt 'opsi-script-test' und dort speziell in der Datei sub-scripts/regex.opsiscript.

URL Functionen [W/L/M]

Diese Funktionen dienen zur analyse und zur Erzeugung von URL’s.
Sie zerlegen eine Url in eine Stringliste mit den URL Komponeten:

Beispiel:

'Protocol=proto'
'Username=usr'
'Password=pwd'
'Host=host'
'Port=8080'
'Path=/path/'
'Document=doc'
'Params=param'
'Bookmark=bookmark'

  • parseUrl(<url string>`) : stringlist`
    Liefert die aus der Zerlegung der URL <url string> entstandene Stringliste.

Beispiel:

comment "Testing parseUrl with all fields"

set $string1$ = "proto://usr:pwd@host:8080/path/doc?param#bookmark"

set $list1$ = createStringList('Protocol=proto','Username=usr','Password=pwd', 'Host=host', 'Port=8080', 'Path=/path/', 'Document=doc', 'Params=param', 'Bookmark=bookmark')
set $ConstTest$ = composeString ($list1$, " | ")

set $list2$ = parseUrl($string1$)
set $CompValue$ = composeString ($list2$, " | ")

if ($ConstTest$ = $CompValue$)
		comment "parseUrl passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing parseUrl failed"
endif

comment "Testing parseUrl with some fields"

set $string1$ = "ftp://example.abc.edu/"

set $list1$ = createStringList('Protocol=ftp','Username=','Password=', 'Host=example.abc.edu', 'Port=0', 'Path=/', 'Document=', 'Params=', 'Bookmark=')
set $ConstTest$ = composeString ($list1$, " | ")

set $list2$ = parseUrl($string1$)
set $CompValue$ = composeString ($list2$, " | ")

if ($ConstTest$ = $CompValue$)
		comment "parseUrl passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing parseUrl failed"
endif

  • createUrl(<urlcomponents list>`) : string`
    Liefert eine URL aus den Komponenten der übergebenen <urlcomponents list>. Dabei muss <urlcomponents list> nicht vollständig sein: leere Teile können weggelassen werden.

Beispiel:

comment "Testing createUrl with all fields"

set $list1$ = createStringList('Protocol=proto','Username=usr','Password=pwd', 'Host=host', 'Port=8080', 'Path=/path/', 'Document=doc', 'Params=param', 'Bookmark=bookmark')

set $ConstTest$ = "proto://usr:pwd@host:8080/path/doc?param#bookmark"
set $CompValue$ = createUrl($list1$)

if ($ConstTest$ = $CompValue$)
		comment "createUrl passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing createUrl failed"
endif

comment "Testing createUrl with some fields"

set $list1$ = createStringList('Protocol=https','Host=www.example.com', 'Path=/b-c-d-330002341216/')

set $ConstTest$ = "https://www.example.com/b-c-d-330002341216/"
set $CompValue$ = createUrl($list1$)

if ($ConstTest$ = $CompValue$)
		comment "createUrl passed"
else
		set $TestResult$ = "not o.k."
		LogWarning "testing createUrl failed"
endif

Für weiter Beispiele schauen Sie im Produkt 'opsi-script-test' und dort speziell in der Datei sub-scripts/urlparser.opsiscript.

Netzwerknummern Funktionen [W/L/M]

  • isValidIP4 (<ip4adr>`) : boolean`
    Liefert 'true' wenn <ip4adr> eine gültige IPv4 Adresse ist (Host,Netz, Maske).

Beispiel:

comment "Testing with valid IPv4 address"

set $ConstTest$ = "true"
set $CompValue$ = booltostring(isValidIP4("255.255.0.0"))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4 passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4 failed"
endif

comment "Testing with invalid IPv4 address"

set $ConstTest$ = "false"
set $CompValue$ = booltostring(isValidIP4("255.256.0.0"))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4 passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4 failed"
endif

  • isValidIP4Network (<ip4adr>, <netmask>`) : boolean`
    Liefert 'true' wenn <ip4adr> zusammen mit <netmask> eine gültige IPv4 Netzwerkadresse ist.
    Dabei kann <netmask> in der CIDR oder der punktseparierten Dezimal Notation angegeben werden.

Beispiel:

comment "Testing with valid network address, where netmask is in cidr notation"
set $ConstTest$ = "true"
set $CompValue$ = booltostring(isValidIP4Network('192.168.0.0','24'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Network passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Network failed"
endif

comment "Testing with valid network address, where netmask is in dotted-decimal notation"
set $ConstTest$ = "true"
set $CompValue$ = booltostring(isValidIP4Network('192.168.0.0','255.255.255.0'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Network passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Network failed"
endif

comment "Testing with invalid network address"
set $ConstTest$ = "false"
set $CompValue$ = booltostring(isValidIP4Network('198.51.100.223','21'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Network passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Network failed"
endif

  • isValidIP4Host (<ip4adr>, <netmask>`) : boolean`
    Liefert 'true' wenn <ip4adr> eine gültige Hostadresse ist, welche in dem per <netmask> angegebenen Subnetz liegt. Dabei kann <netmask> in der CIDR oder der punktseparierten Dezimal Notation angegeben werden.

Beispiel:

comment "Testing with valid host address, where netmask is in dotted-decimal notation"

set $ConstTest$ = "true"
set $CompValue$ = booltostring(isValidIP4Host('198.51.104.254', '255.255.248.0'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Host passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Host failed"
endif

comment "Testing with valid host address, where netmask is in cidr notation"

set $ConstTest$ = "true"
set $CompValue$ = booltostring(isValidIP4Host('198.51.104.254', '21'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Host passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Host failed"
endif

comment "Testing with invalid host address"

set $ConstTest$ = "false"
set $CompValue$ = booltostring(isValidIP4Host('198.51.104.0', '21'))
if ($ConstTest$ = $CompValue$)
	comment "isValidIP4Host passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing isValidIP4Host failed"
endif

  • getIP4NetworkByAdrAndMask (<ip4adr>, <netmask>) : string
    Liefert einen String mit der Netzwerkadresse basierend auf der Hostadresse <ip4adr> und der Netzmaske <netmask>. Dabei kann <netmask> in der CIDR oder der punktseparierten Dezimal Notation angegeben werden.

Beispiel:

comment "Testing with netmask in cidr notation "

set $ConstTest$ = "198.48.0.0"
set $CompValue$ = getIP4NetworkByAdrAndMask('198.51.100.223', '12')
if ($ConstTest$ = $CompValue$)
	comment "getIP4NetworkByAdrAndMask passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing getIP4NetworkByAdrAndMask failed"
endif

comment "Testing with netmask in dotted decimal notation "

set $ConstTest$ = "198.48.0.0"
set $CompValue$ = getIP4NetworkByAdrAndMask('198.51.100.223', '255.240.0.0')
if ($ConstTest$ = $CompValue$)
	comment "getIP4NetworkByAdrAndMask passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing getIP4NetworkByAdrAndMask failed"
endif

  • getDefaultNetmaskByIP4adr (<ip4adr>) : string
    Liefert die Defaultnetzmaske zu IP-Adresse <ip4adr>. Die Defaultnetzmaske steht für ein Netz der Klassen A,B,C.

Beispiel:

set $ConstTest$ = "255.255.0.0"
set $CompValue$ = getDefaultNetmaskByIP4adr("128.42.5.4")
if ($ConstTest$ = $CompValue$)
	comment "getDefaultNetmaskByIP4adr passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "testing getDefaultNetmaskByIP4adr failed"
endif
  • cidrToNetmask (<string>) : string //since 4.12.4.37
    Liefert die Netzmaske (dotted decimal notation) zum gegebene IPv4 CIDR-Suffix.
    cidr ⇐ 0 ergibt "0.0.0.0"
    cidr >= 32 ergibt "255.255.255.255"
    Leere oder üngültige Eingabe ergibt Leerstring
    siehe auch : [netmaskToCidr]
    siehe auch : [getDefaultNetmaskByIP4adr]
    siehe auch : [getIP4NetworkByAdrAndMask]

Beispiel:

set $netmask$ = cidrToNetmask("24")
comment "expected: 255.255.255.0"
set $netmask$ = cidrToNetmask("16")
comment "expected: 255.255.0.0"
set $netmask$ = cidrToNetmask("-1")
comment "expected: 0.0.0.0"
set $netmask$ = cidrToNetmask("55")
comment "expected: 255.255.255.255"
set $netmask$ = cidrToNetmask("")
comment "expected: "

Beispiel:

set $cidr$ = netmaskToCidr("255.255.255.0")
comment "expected: 24"
set $cidr$ = netmaskToCidr("255.255.0.0")
comment "expected: 16"
set $cidr$ = netmaskToCidr("255.255.10.0")
comment "(invalid input) expected: "
set $cidr$ = netmaskToCidr("")
comment "(empty input) expected: "

  • isValidFQDN (<domainName>) : boolean
    Gibt true (wahr) zurück wenn die Zeichenkette einem Fully Qualified Domain Name (FQDN, deutsch etwa "vollständig qualifizierter Domainname") entspricht und false (falsch) wenn nicht. Ein Fully Qualified Domain Name (FQDN) hat die folgenden Eigenschaften:

    • Die komplette Zeichenkette besteht insgesamt aus nicht mehr als 254 Zeichen

    • Sie muss aus mindestens drei, durch Punkte getrennte, Zeichenketten bestehen

    • Jede dieser Zeichenketten darf 63 Zeichen nicht überschreiten

    • Die Zeichenketten, bis auf die Letzte, dürfen Buchstaben, ganze Zahlen und Minuszeichen enthalten. Das Minuszeichen darf nicht am Anfang stehen

    • Die letzte Zeichenkette (TLD, Top-Level-Domain) darf nur Buchstaben enthalten und muss mindestens 2 Zeichen lang sein

Beispiel:

Message "Testing of isValidFQDN"
SetLogLevel=7

DefVar $TestResult$
DefVar $CompValue$

DefStringList $CorrectFQDNs$
DefStringList $IncorrectFQDNs$

Set $CorrectFQDNs$ = CreateStringList("www.uib.de", "opsi-script.uib.de", "m.opsi.org", "a-a.b-b.cc", "a1b2.c3d4.e5f6.g7h8.i9j0.zz", "1a-2b.3c_4d.5e-6f.zzz","123.123.com")
Set $IncorrectFQDNs$ = CreateStringList("abcde", "uib.de", "www.uib", "www.uib.d", "-script.uib.de", "_script.uib.de", "www.uib.00", "a1b2.c3d4.e5f6", "aaa.-bbb.zz", "#aaa.bbb.zz", "a+a.bbb.zz", "a?a.bbb.zz")

DefFunc myFQDNTester($expected$ : string, $fqdn$ : string, ref $TestResult$ : string) : void
    DefVar $CompValue$
    set $CompValue$ = booltostring(isValidFQDN($fqdn$))
    if $CompValue$ = $expected$
            comment "Testing isValidFQDN succeeded"
    else
            set $TestResult$ = "not o.k."
            LogWarning "Testing isValidFQDN failed"
    endif
endfunc

for %s% in $CorrectFQDNs$ do  myFQDNTester("true","%s%",$TestResult$)
for %s% in $IncorrectFQDNs$ do  myFQDNTester("false","%s%",$TestResult$)

Für weiter Beispiele schauen Sie im Produkt 'opsi-script-test' und dort speziell in der Datei sub-scripts/networkcalc.opsiscript

Prozess- und Skript-Funktionen [W/L/M]

  • waitForPackageLock(<seconds timeout string>,<bool should we kill>`) : bool` //since 4.11.6.1 [L]
    Liefert 'true' zurück, wenn das Linux-Packagesystem nicht gesperrt ist. Ist es gesperrt, so wird <seconds timeout string> Sekunden auf die Freigabe gewartet. Ist der Timeout erreicht, so wird der Prozess, welcher den Lock erzeugt hat, abgeschossen, wenn <bool should we kill> gleich 'true' ist. Dieses Vorgehen ist aber nicht empfohlen.

  • processIsRunning(<process name>`) : boolean` //since 4.11.6.1 [W/L/M]
    Liefert 'true', wenn der Prozess <process name> in der aktuellen Prozessliste ist.

  • isProcessChildOf(<searchprocstr>, <parentprocstr>): bool //since 4.12.4.35 [W/L/M]
    Liefert 'true', wenn der Prozess <searchprocstr> ein Kindprozess von <parentprocstr> ist.
    Beispiel:

    if isProcessChildOf('%opsiscriptprocname%', 'opsiclientd.exe')
      comment "running in opsi service context"
    endif

  • shellCall (<command string>`) : stringlist (output)` //since 4.11.4.2 [W/L/M]
    Führt <command string> mit der Standard-Shell (cmd.exe / bash) aus.

    set $list$ = shellCall('net start')

    ist eine Abkürzung für den Ausdruck:

    set $list$ = getOutStreamFromSection ('ShellScript_netstart winst /sysnative')
    
    [ShellScript_netstart]
    net start

  • shellCall (<command string>`) : noresult` //since 4.11.6.1 [W/L/M]

    shellCall('net start')

    ist eine Abkürzung für den Ausdruck:

    ShellScript_netstart winst /sysnative
    
    [ShellScript_netstart]
    net start

  • shellCall (<command string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M]

    set $exitcode$ = shellCall('net start')

    ist eine Abkürzung für den Ausdruck:

    ShellScript_netstart winst /sysnative
    set $exitcode$ = getLastExitcode
    
    [ShellScript_netstart]
    net start

  • powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true']]) : stringlist (output) //since 4.12.0.16 [W]
    powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true'][, <optionstr> = '']]) : stringlist (output) //since 4.12.4.28 [W]
    Führt <command string> mit der PowerShell aus.
    Genauer gesagt wird ein Skript ausgeführt, das wie folgt aussieht:

    trap { write-output $_ ; exit 1 }
    <commandstr>
    exit $LASTEXITCODE

    Die erste Zeile dient dazu, dass bei Exceptions kein exitcode=0 zurückgeliefert wird, und die letzte Zeile dient dazu, den letzten produzierten Exitcode zurückzuliefern.
    Die Architektur der powershell.exe ist per default sysnative. Die Architektur kann aber auch über den optionalen zweiten Parameter <access str> angegeben werden. Dabei muss der übergebene <access str> einer der folgenden Werte sein: 32bit, sysnative, 64bit.
    (siehe auch: Kapitel 64 Bit-Unterstützung)
    Da per Windows-Default die ExecutionPolicy der PowerShell auf Restricted steht, können Skripte nicht ohne weiteres ausgeführt werden. Daher hat der Befehl powershellCall per default folgendes Verhalten: Die aktuelle ExecutionPolicy wird gesichert und die ExecutionPolicy auf RemoteSigned gesetzt. Dann wird das Skript ausgeführt und abschließend die ExecutionPolicy wieder zurück gesetzt. Dieses Default-Verhalten kann über den optionalen dritten Parameter <policy bool str> geändert werden: Hat <policy bool str> den Wert "false", so wird die ExecutionPolicy nicht modifiziert.
    Wird die Funktion powershellCall dort aufgerufen, wo eine Stringliste erwartet wird, so enthält die Stringliste die Ausgabe von <commandstr>.
    Seit 4.12.4.35:
    Wird als aktuelle ExecutionPolicy AllSigned detektiert, so wird der PowerShell-Aufruf automatisch so umgebaut, dass das temporäre PowerShell-Skript nicht per -File aufgerufen wird, sondern per -Command Get-Content -Path <tempfilename> | Out-String | Invoke-Expression. Dadurch wird das Skript ohne Berücksichtigung der ExecutionPolicy ausgeführt. In einem solchen Fall werden aber evtl. angegebene PASSPARAS nicht mehr berücksichtigt.
    Seit 4.12.4.28:
    Der optionale <optionstr> kann genutzt werden, um dem Befehl zusätzliche Optionen mitzugeben. Da der powershellcall intern letztendlich ein ExceWith Aufruf ist, können die dort dokumentierten Optionen auch hier angegeben werden, siehe sec-section.adoc#opsi-script-execwith-params
    Beispiel:

    set $list$= powershellCall('Get-Process -ProcessName "opsi*"')

    ist eine Abkürzung für den Ausdruck:

    set $policy$ = takeString(0,shellCall('powershell.exe get-executionpolicy'))
    shellCall('powershell.exe set-executionpolicy RemoteSigned')
    set $list$ = getOutStreamFromSection ('Execwith_ps powershell.exe winst /sysnative')
    shellCall('powershell.exe set-executionpolicy '+$policy$)
    
    [Execwith_ps]
    trap { write-output $_ ; exit 1 }
    Get-Process -ProcessName "opsi*"
    exit $LASTEXITCODE

    Hinweis zum PowerShell-Befehl 'Get-Partition'
    Die Ausgabe des PowerShell-Befehls Get-Partition enthält NULL-Characters \u0000 in der Spalte DriveLetter überall dort, wo kein Laufwerksbuchstabe steht. Das führt in opsi-script zu Problemen beim direkten Einlesen der Ausgabe von Get-Partition. Möchte man die Ausgabe von Get-Partition in einem Skript weiterverarbeiten, dann empfehlen wir als Lösung:

    DefStringlist $ResultList$
    PowershellCall('Get-Partition > "%opsiUserTmpDir%\Get-Partition.txt"')
    Set $ResultList$ = LoadTextFile("%opsiUserTmpDir%\Get-Partition.txt")

    Dabei wird die Ausgabe von Get-Partition zuerst in eine Datei gespeichert und dadurch wird das Problem mit den NULL-Characters umgangen.

  • powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true']]) : noresult //since 4.12.0.16 [W]
    powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true'][, <optionstr> = '']]) : noresult //since 4.12.4.28 [W]
    siehe [powershellCall_list]
    Die Funktion powershellCall kann auch dort aufgerufen werden, wo kein Rückgabe-Wert erwartet wird.
    Beispiel:

    powershellCall('Get-Process -ProcessName "opsi*"')

  • powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true']]) : string (exitcode) //since 4.12.0.16 [W]
    powershellCall(<commandstr> [,<access str>='sysnative' [,<policy bool str>='true'][, <optionstr> = '']]) : string (exitcode) //since 4.12.4.28 [W]
    siehe [powershellCall_list]
    Wird die Funktion powershellCall dort aufgerufen wo, ein String erwartet wird, so enthält der String den Exitcode des ausgeführten Skriptes.
    Beispiel:

    set $exitcode$ = powershellCall('Get-Process -ProcessName "opsi*"')

  • processCall(<string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M]
    Startet das Programm <string> als Prozess und liefert den Exitcode zurück.

    set $exitcode$ = processCall('setup.exe /S')

    ist eine Abkürzung für den Ausdruck:

    Winbatch_setup
    set $exitcode$ = getLastExitcode
    
    [Winbatch_setup]
    setup.exe /S

    Tatsächlich basiert processCall intern auf den selben Routinen wie winbatch und verarbeitet daher auch die selben Modifier:

    • /LetThemGo
      Verschiebt den aufgerufenen Prozess in den Hintergrund und wartet nicht auf dessen Beendigung; d.h. dass sofort die nächsten Zeilen der WinBatch-Sektion bzw. die nächsten Zeilen des übergeordneten Programms abgearbeitet werden.

    • /TimeOutSeconds <seconds>
      Bricht das Warten auf das Prozessende oder eine Wartebedingung (/WaitForProcessEnding) nach Ablauf von <seconds> ab, auch wenn das Prozessende oder die Wartebedingung noch nicht erfüllt ist.
      Der Prozess, auf dessen Ende gewartet werden sollte, wird nicht gestoppt.
      Kann seit Version 4.11.3 auch alleine (z.B. ohne /WaitForProcessEnding) verwendet werden, aber nicht zusammen mit /WaitSeconds.
      Seit 4.11.4.6 wird der Zeitablauf bis zum Timeout über den Fortschrittsbalken angegeben.

    • /WaitSeconds [number of seconds]
      Die Parametrisierung /WaitSeconds [AnzahlSekunden] modifiziert das Verhalten dahingehend, dass opsi-script jeweils erst nach [AnzahlSekunden] die Skriptbearbeitung fortsetzt. Die angegebene Zeit stoppt opsi-script auf jeden Fall. In der Default-Einstellung wird zusätzlich auf das Ende der angestoßenen Prozesse gewartet. Ist letzteres nicht gewünscht, so kann der Parameter mit dem Parameter /LetThemGo kombiniert werden.

    • /WaitForProcessEnding <program name>
      Wartet darauf, dass sich der Prozess mit dem Namen <program name> beendet.
      Kann und sollte mit /TimeOutSeconds kombiniert werden.

    • /32Bit //seit 4.11.3.5 [W]
      Das ist der Default. Die in der Sektion angegebenen Pfade werden als 32 Bit Pfade interpretiert.
      Beispiel: c:\windows\system32\regedit.exe ruft (auch auf einem 64bit System) die 32 Bit 'regedit.exe' auf.

    • /64Bit //seit 4.11.3.5 [W]
      Die in der Sektion angegebenen Pfade werden als 64 Bit Pfade interpretiert.
      Beispiel: c:\windows\system32\regedit.exe ruft (auf einem 64bit System) die 64 Bit 'regedit.exe' auf.

    • /SysNative //seit 4.11.3.5 [W]
      Die in der Sektion angegebenen Pfade werden gemäß der OS-Architektur interpretiert.
      Beispiel: c:\windows\system32\regedit.exe ruft auf einem 64bit System die 64 Bit 'regedit.exe' und auf einem 32bit System die 32 Bit 'regedit.exe’auf.

Spezielle Kommandos [W/L/M]

  • Killtask <process> [W/L/M]
    stoppt alle Prozesse, in denen das durch <process> bezeichnete Programm ausgeführt wird. Beispiel :

killtask "winword.exe"

  • ChangeDirectory <directory> //since 4.11.2.6 [W/L/M]
    Setzt das angegebene Directory als Arbeitsverzeichnis des opsi-script. Wirkt auf alle nachfolgenden Aktionen (z.B. winbatch Sektionen) und wird am Ende einese Scriptes automatisch zurückgesetzt. Beispiel :

ChangeDirectory "%SCRIPTPATH%\programm"

  • UpdateEnvironment //since 4.11.5.1 [W]
    Sendet Windows das Signal das Environment aus der Registry neu einzulesen. Anzuwenden nachdem Umgebungsvariablen wie z.B. PATH verändert, gesetzt oder gelöscht wurden. ABER: Normale ShellScript oder Winbatch Aufrufe erben trotzdem das 'alte' Environment. Daher danach winbatch mit dem Parameter /RunElevated verwenden.

Example:

comment "Set Environment Variables and check for it ...."
Registry_add_environment /sysnative
UpdateEnvironment

comment "This will not work because the environment is inherited from the running process"
set $list$ = shellCall('set opsi-script-test')

comment "This will work because this new started process will get a new environment"
winbatch_check_environment /RunElevated
if ("42" = getlastExitCode)
	comment "passed"
else
	comment "failed"
endif

[Registry_add_environment]
openkey [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment]
set "opsi-script-test"="deleteme"

[winbatch_check_environment]
"%system%\cmd.exe" /c "if %opsi-script-test%==deleteme exit 42"

  • sleepSeconds <string> [W/L/M]
    unterbricht die Programmausführung für <string> Sekunden. Dabei muß <string> ein Stringausdruck sein welcher eine Integerzahl repräsentiert.

  • markTime [W/L/M]
    Setzt einen Zeitstempel für die Systemlaufzeit und zeichnet diese auf.

  • diffTime [W/L/M]
    Zeichnet die vergangene Zeit seit der letzten aufgezeichneten Zeit (marktime) auf.

Beispiel:

set $list$ = listCertificatesFromSystem
if "" = takeFirstStringContaining($list$,"opsi-script-test test CA")
	comment "not found"
endif
ImportCertToSystem('opsi-script-test-CA.pem')
if isCertInstalledInSystem("opsi-script-test test CA")
	comment "found"
	removeCertFromSystem("opsi-script-test test CA")
	if not(isCertInstalledInSystem("opsi-script-test test CA"))
		comment "CA succesful removed"
	endif
endif
  • reloadProductList [W/L/M] //since 4.12.6.1
    Lädt die Produktliste vom opsi-server nach Durchführung des Skriptes in opsi-script neu ein. Ist die Produktliste nicht leer, wird sie erneut von opsi-script abgearbeitet. loadProductList kann überall in der Actions-Sektion des Skriptes stehen. Die Empfehlung ist aber ,der Logik entsprechend, den Befehl ans Ende der Sektion zu setzen.

Steuerung des Logging [W/L/M]

  • comment <STRINGAUSDRUCK> [W/L/M]
    bzw.
    comment = <Zeichensequenz>
    wird einfach der Wert des String-Ausdrucks (bzw. Zeichensequenz) als Kommentar in die Protokolldatei eingefügt.

  • LogError <STRINGAUSDRUCK> [W/L/M]
    oder
    LogError = <Zeichensequenz>
    Fügt eine zusätzlich Fehlermeldungen in der Protokolldatei ein und erhöht den Fehlerzähler um eins.

  • LogWarning <STRINGAUSDRUCK> [W/L/M]
    oder
    LogWarning = <Zeichensequenz>
    Fügt eine zusätzlich Warnmeldungen in der Protokolldatei ein und erhöht den Warnungszähler um eins.

  • includelog <file name> <tail size> //since 4.11.2.1 [W/L/M]

  • includelog <file name> <tail size> [<encoding>] //since 4.11.4.1 [W/L/M]
    Fügt die Datei <file name> in den aktuellen ein. Dabei werden nur die letzten <tail size> Zeilen und nicht die komplette Logdatei eingfügt. Wenn Sie ein anderes Programm (z.B. ein setup programm) starten das eine Logdatei produziert, können Sie mit diesem Begfehl die Informationen aus dieser Logdatei in den Log des opsi-script übernehmen.
    Seit Version 4.11.3.2 kann auch eine negative <tail size> angegeben werden. Dann arbeitet includelog im 'Head' Modus, d.h. ist <tail size> = -5, so werden die ersten 5 Zeilen von <file name> in den Log übernommen. Seit Version 4.11.4.1 kann als dritter Parameter ein encoding angegeben werden. Bekannte encodings sind beim Befehl encoding angegeben. Wird als encoding auto angegeben, so wird versucht das passende Encoding zu eraten. Beispiel:

includelog "%Scriptpath%\test-files\10lines.txt" "5"
includelog "%Scriptpath%\test-files\10lines_utf16.txt" "5" "ucs2be"

  • SetConfidential <secret string> [W/L/M]
    Dient dazu vertrauliche Informationen (z.B. Passwörter) aus den Logdateien fernzuhalten. Diese werden dort durch '(confidential)' ersetzt.
    Wird der Loglevel auf '9' gesetzt, so werden die 'confidential’s im Klartext gelogt.
    Seit Version 4.11.3.5

Beispiel:

message "SetConfidential"
SetConfidential "forbidden"
comment "This is a forbidden string"
comment "should be in the log file: This is a ***(confidential)*** string"

Log:

message SetConfidential
comment: This is a ***(secret)*** string
comment: should be in the log file: This is a ***(confidential)*** string

  • asConfidential( <secret string expression> ) : string //since 4.12.0.16 [W/L/M]
    Diese Funktion dient dazu vertrauliche Informationen von einer Funktion zu erlangen, ohne das die Werte in der Logdatei landen. Dabei kommt es zu folgenden Ablauf:

    1. Aktuellen Loglevel sichern

    2. Loglevel auf Warning (4) setzen+

    3. Auswerten der übergeben Stringexpression (z.B. einer Funktion welche einen String liefert)

    4. Setzen dieses ermittelten Strings als Confidential d.h. dieser String wird ab jetzt nicht mehr geloggt.

    5. Ursprünglichen Loglevel wiederherstellen

    6. Rückgabe des ermittelten Stringwertes.

Beispiel:

set $ConstTest$ = asConfidential(stringReplace("this is my old secret", "old", "new"))
comment "this is my new secret"
comment "should be in the log file:  ***(confidential)*** "

Log:

Set  $ConstTest$ = asConfidential(stringReplace("this is my old secret", "old", "new"))
  The value of the variable "$ConstTest$" is now: "***(confidential)***"
comment: This is a ***(confidential)*** string
comment: should be in the log file: This is a ***(confidential)*** string----

  • asConfidential( <secret stringlist expression> ) : stringlist //since 4.12.4.15 [W/L/M]
    This function should be used to get confidential stringlist from an other stringlist function without without logging the secret strings. The Function work like the string function asconfidential, but for stringlists.

Information und Interaktion [W/L/M]

  • Message <STRINGAUSDRUCK> [W/L/M]
    bzw.
    Message = <Buchstabenfolge>
    bewirkt, dass in der Batch-Oberfläche des opsi-script der Wert von STRINGAUSDRUCK bzw. dass die Buchstabenfolge als Hinweis-Zeile zum gerade laufenden Installationsvorgang angezeigt wird (solange bis die Installation beendet ist oder eine andere message angefordert wird).
    Empfohlen ist die erste Variante, da nur hier auch Variablen für den Messagetext verwendet werden können. Beispiel:

Message "Installation von "+$productid$

  • ShowMessageFile <file name> [W/L/M]
    zeigt den Inhalt der Datei <file name> in einem gesonderten Fenster an und wartet auf Bestätigung durch den Anwender. Z.B. könnte so eine "Nachricht des Tages" angezeigt werden:

ShowMessageFile "p:\login\day.msg"

  • ShowBitMap [<DATEINAME>] [<Beschriftung>] [W/L/M]
    wird die Bilddatei <DATEINAME> (BMP-, JPEG- oder PNG-Format, 160x160 Pixel) in der Batch-Oberfläche angezeigt. Eine Beschriftung kann ebenfalls hinzugefügt werden. <DATEINAME> und <Beschriftung> sind String-Ausdrücke. Wenn der Namensparameter fehlt, wird das Bild gelöscht. Beispiel:

ShowBitmap "%scriptpath%\" + $ProduktName$ + ".bmp"  "$ProduktName$"

  • Pause <STRINGAUSDRUCK> [W/L/M]
    bzw.
    Pause = <Zeichensequenz>
    Die beiden Anweisungen zeigen in einem Textfenster den in STRINGAUSDRUCK gegebenen Text (bzw. Zeichensequenz) an. Auf Anklicken eines Knopfes setzt sich der Programmlauf fort.

  • Stop <STRINGAUSDRUCK> [W/L/M]
    bzw.
    stop = <Zeichensequenz> [W/L/M]
    der STRINGAUSDRUCK (bzw. Zeichensequenz, die möglicherweise auch leer ist) wird angezeigt und um Bestätigung gebeten, dass der Programmablauf abgebrochen werden soll.

  • setActionProgress <string> : noresult //since 4.11.3 [W/L/M]
    Übermittelt <string> als ActionProgress für das laufende Produkt an den Server. Der Default von ActionProgress ist 'installing' während ein Script ausgeführt wird. Der ActionProgress wird im configed angezeigt.

Kommandos für userLoginScripts / User Profile Management [W]

  • GetScriptMode //since 4.11.2.1
    liefert eines der beiden Werte 'Machine','Login':

    • 'Machine' - das Script läuft nicht als 'userLoginScript'

    • 'Login' - das Script läuft als 'userLoginScript'

  • GetLoggedInUser //since 4.11.1.2

  • GetUsercontext //since 4.11.1.2
    liefert den Namen des Users in dessen Kontext der opsi-script gerade läuft.
    siehe auch: [GetUsercontext]

  • saveVersionToProfile //since 4.11.2.1
    speichert productversion-packageversion die im lokalen Profil
    Diese Funktion ist gedacht für userLoginScripts.
    Diese Funktion kann in Kombination mit readVersionFromProfile verwendet werden um festzustellen ob ein Script schonmal gelaufen ist. Es speichert im Lokalen Profil (in der Datei "%CurrentAppdataDir%\.opsi.org\userLoginScripts.ini"), dass das 'userLoginScript' für dieses opsi product in dieser product version und package version für den aktuellen user ausgefürt wurde. Sieh auch scriptWasExecutedBefore

  • readVersionFromProfile //since 4.11.2.1
    liefert einen string mit productversion-packageversion für das aktuelle opsi produkt der aus dem lokalen Profil ausgelesen wird. Siehe auch: saveVersionToProfile
    Diese Funktion ist gedacht für userLoginScripts.

  • scriptWasExecutedBefore //since 4.11.2.1
    Mit dieser boolschen Funktion kann überprüft werden, ob das 'userLoginScript' zu diesem Produkt in dieser Version schon mal zuvor gelaufen ist und eine erneute Ausführung unnötig ist. Dazu liest diese Funktion zunächst einen evtl. vorhandenen Versionsstempel vom Profil ein (wie das mit readVersionFromProfile möglich ist) und vergleicht diesen mit der aktuell laufenden Version. Aus dem Vergleich ergibt sich der Rückgabewert (wahr/falsch). Danach werden noch die aktuellen Werte in das Profil zurückgeschrieben (wie das mit saveVersionToProfile möglich ist). Somit benötigen Sie nur diese eine Funktion in einer if Anweisung, um zu prüfen ob das Script schon mal gelaufen ist.

  • isLoginScript //since 4.11.2.1
    Diese boolsche Funktion liefert 'true' wenn das aktuelle Script als 'userLoginScript' läuft. Siehe auch: GetScriptMode

For-To Schleife [W/L/M]

Zum mehrfachen Ausführen eines Befehls oder einer Subsektion.

Syntax:

for %<temporary string variable>% = <start string> to <end string> do <one statement> //since 4.11.5 [W/L/M]

Die temporäre Variable %<temporary string variable>% muss nicht und darf nicht deklariert werden und ist in der aufgerufenen Subsektion als Konstante verfügbar.

Example:

Code from opsi-script-test:

message "for to loop"
set $ConstTest$ = "12345"
set $CompValue$ = ""
for %s% = "1" to "5" do sub_iteration_test
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

[sub_iteration_test]
set $CompValue$ = $CompValue$ + '%s%'

ergibt den Log:

message for to loop
Set  $ConstTest$ = "12345"
  The value of the variable "$ConstTest$" is now: "12345"
Set  $CompValue$ = ""
  The value of the variable "$CompValue$" is now: ""

~~~~~~ Looping through:  '1', '2', '3', '4', '5'

  ~~~~~~~ Start Sub ~~~~~~~  sub_iteration_test
  Set  $CompValue$ = $CompValue$ + '1'
    The value of the variable "$CompValue$" is now: "1"

  ~~~~~~~ End Sub   ~~~~~~~  sub_iteration_test


  ~~~~~~~ Start Sub ~~~~~~~  sub_iteration_test
  Set  $CompValue$ = $CompValue$ + '2'
    The value of the variable "$CompValue$" is now: "12"

  ~~~~~~~ End Sub   ~~~~~~~  sub_iteration_test


  ~~~~~~~ Start Sub ~~~~~~~  sub_iteration_test
  Set  $CompValue$ = $CompValue$ + '3'
    The value of the variable "$CompValue$" is now: "123"

  ~~~~~~~ End Sub   ~~~~~~~  sub_iteration_test


  ~~~~~~~ Start Sub ~~~~~~~  sub_iteration_test
  Set  $CompValue$ = $CompValue$ + '4'
    The value of the variable "$CompValue$" is now: "1234"

  ~~~~~~~ End Sub   ~~~~~~~  sub_iteration_test


  ~~~~~~~ Start Sub ~~~~~~~  sub_iteration_test
  Set  $CompValue$ = $CompValue$ + '5'
    The value of the variable "$CompValue$" is now: "12345"

  ~~~~~~~ End Sub   ~~~~~~~  sub_iteration_test


~~~~~~ End Loop
If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: passed
Else
EndIf

Switch / Case Statement [W/L/M]

Syntax:

Switch <string expression>
  Case <string const>
    <statement(s)>
  EndCase
  [DefaultCase
    <statement(s)>
   EndCase]
EndSwitch

Switch / Case Ausdrücke können nicht geschachtelt werden (innerhalb eines Case darf es kein weiteres Switch geben).
Eine Möglichkeit etwa das selbe wie Switch / Case zu erreichen, sind die seit 4.12.4.37 verfügbaren if-elseif-else Ausdrücke, welche auch schachtelbar sind.
siehe: IfElseEndif

Examples:

Code from opsi-script-test:

set $ConstTest$ = "5"
Switch $ConstTest$
	Case "1"
		set $CompValue$ = "1"
	EndCase
	Case "2"
		set $CompValue$ = "2"
	EndCase
	Case "3"
		set $CompValue$ = "3"
	EndCase
	Case "4"
		set $CompValue$ = "4"
	EndCase
	Case "5"
		set $CompValue$ = "5"
	EndCase
	Case "6"
		set $CompValue$ = "6"
	EndCase
	Case "7"
		set $CompValue$ = "7"
	EndCase
	DefaultCase
		set $CompValue$ = "notexisting"
	EndCase
EndSwitch
if ($ConstTest$ = $CompValue$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

.

[Sub_check_exitcode]
comment "Test for installation success via exit code"
set $ExitCode$ = getLastExitCode
; informations to exit codes see
; http://msdn.microsoft.com/en-us/library/aa372835(VS.85).aspx
; http://msdn.microsoft.com/en-us/library/aa368542.aspx
Switch $ExitCode$
	Case "0"
		comment "Looks good: setup program gives exitcode zero"
	EndCase
	Case "1605"
		comment "ERROR_UNKNOWN_PRODUCT	1605"
		comment "This action is only valid for products that are currently installed."
		comment "Uninstall of a not installed product failed - no problem"
	EndCase
	Case "1641"
		comment "looks good: setup program gives exitcode 1641"
		comment "ERROR_SUCCESS_REBOOT_INITIATED	164"
		comment "The installer has initiated a restart."
		comment "This message is indicative of a success."
		ExitWindows /Reboot
	EndCase
	Case "3010"
		comment "looks good: setup program gives exitcode 3010"
		comment "ERROR_SUCCESS_REBOOT_REQUIRED	3010"
		comment "A restart is required to complete the install."
		comment "This message is indicative of a success."
		ExitWindows /Reboot
	EndCase
	DefaultCase
		logError "Fatal: Setup program gives an unknown exitcode unequal zero: " + $ExitCode$
		isFatalError "Exit Code: "+ $ExitCode$
	EndCase
EndSwitch

Bedingungsanweisungen (if-Anweisungen) [W/L/M]

Die Ausführung einer oder mehrere Anweisungen kann in den primären Sektionen von der Erfüllung bzw. Nichterfüllung einer Bedingung abhängig gemacht werden.

Beispiel:

;Welche Windows-Version?
DefVar $MSVersion$

Set $MSVersion$ = GetMsVersionInfo
if CompareDotSeparatedNumbers($MSVersion$,">=","6")
     sub_install_win7
else
  if ( $MSVersion$ = "5.1" )
    sub_install_winXP
  else
    stop "not a supported OS-Version"
  endif
endif

Ab Version 4.12.4.37 kennt opsi-script auch eine elseif Anweisung.

Beispiel:

Defvar $OS$
set $OS$ = GetOS

if $OS$ = "Windows_NT"
	comment "We are on Windows"
elseif $OS$ = "Linux"
	comment "We are on Linux"
elseif $OS$ = "macos"
	comment "We are on macOS"
else
	LogWarning "Unsupported OS"
endif

Allgemeine Syntaxregeln [W/L/M]

Folgendes Schema der if-Anweisung ist ersichtlich:
if <Bedingung>
;eine oder mehrere Anweisungszeilen
elseif <Bedingung>
;eine oder mehrere Anweisungszeilen
else
;eine oder mehrere Anweisungszeilen
endif

Der else-Teil der Anweisung darf fehlen.
Der elseif-Teil der Anweisung darf fehlen.
if-Anweisungen können geschachtelt werden. Das bedeutet, dass in der Anweisung nach einem if Satz (sowohl in dem if als auch im else oder elseif Teil) eine weitere if-Anweisung folgen darf.

<Bedingungen> sind boolesche Ausdrücke, das heißt logische Ausdrücke, die entweder den Wert 'wahr' oder den Wert 'falsch' tragen können.

Boolesche Ausdrücke [W/L/M]

Ein Vergleichsausdruck, welcher ein boolscher Ausdruck ist, sieht folgendermaßen aus:
<STRINGAUSDRUCK> <Vergleichszeichen> <STRINGAUSDRUCK>
An der Stelle <Vergleichszeichen> kann eins der folgenden Zeichen stehen:
< = >= >

Bei String-Vergleichen im opsi-script wird Groß-/Kleinschreibung nicht unterschieden.

Ungleich muss mit einem NOT() Ausdruck umgesetzt werden, was weiter unten gezeigt wird.

Es gibt einen Vergleichsausdruck um zwei Strings wie (integer) Zahlen zu vergleichen. Wenn einer der Werte nicht in eine Zahl übertragen werden kann, wird ein Fehler ausgegeben.
Diese Zahlenvergleichsausdrücke haben die gleich Form wie die String-Vergleichsausdrücke, allerdings wird dem dem Vergleichszeichen ein INT vorangestellt:
<STRINGAUSDRUCK> INT<Vergleichszeichen> <STRINGAUSDRUCK>
So können Ausdrücke wie

if $Name1$ INT<= $Name2$

oder

if $Number1$ INT>= $Number2$

gebildet werden.

Boolesche Operator sind AND, OR und NOT() (Groß-/Kleinschreibung nicht unterschieden).
b1, b2 und b3 sind boolesche Ausdrücke, die sich zu kombinierten Ausdrücken verbinden lassen.
b1 AND b2
b1 OR b2
NOT( b3 )
Diese booleschen Ausdrücke zeigen dabei eine Konjunktion (AND), ein Disjunktion (OR) und eine Negation (NOT).

Ein boolescher Ausdruck kann in runden Klammer eingeschlossen werden (diese produziert dann einen neuen booleschen Ausdruck mit dem selben Wert).

Die allgemeinen Regel für boolesche Operatorenprioritäten ("and" vor "or") sind im Moment nicht implementiert. Ein Ausdruck mit mehr als einem Operator wird von links nach rechts interpretiert. Wenn also eine boolescher Ausdruck einen AND und OR Operator enthalten soll, müssen runde Klammern eingesetzt werden. So muss zum Beispiel explizit geschrieben werden
b1 OR (b2 AND b3)
oder
(b1 OR b2) AND b3
Das zweite Beispiel beschreibt, was ausgeführt werden würde, wenn keine runden Klammern gesetzt wäre – wohingegen die übliche Operatorenprioritäten so laufen würde wie in der ersten Zeile angezeigt.

Boolesche Operatoren können als spezielle boolesche Wertefunktionen eingesetzt werden (die Negation-Operatoren demonstrieren das sehr deutlich).

Es sind noch weitere boolesche Funktionen implementiert. Jeder Aufruf einer solchen Funktion begründet sich in einen booleschen Ausdruck:

  • FileOrFolderExists (<Dateiname oder Verzeichnispfad> [,<access str>]) : boolean [W/L/M] (ab Version 4.12.4.14)
    Die Funktion gibt wahr (true) zurück wenn der angegebene Dateiname oder das Verzeichnis existiert, andererseits falsch (false).
    Der optionale Parameter <access str> ist nur unter Windows gültig. Gültige Werte sind 32bit, 64bit oder sysnative; sysnative ist der default Wert. Siehe hierzu Kapitel 64 Bit-Unterstützung
    see also: [DirectoryExists]
    see also: [FileExists]

  • DirectoryExists (<path> ) : bool //since 4.12.1 [W/L/M]
    Tests if <path> points to a directory.
    <access str> = one of 32bit, 64bit, sysnative ; default sysnative ; ignored at non windows
    see also: [FileOrFolderExists]
    see also: [FileExists]

Examples:

if ($INST_SystemType$ = "64 Bit System")
	set $ConstTest$ = "true"
	Set $tmp$ = "C:\Windows\system32\Boot"
	set $tmp1$ = "64bit"
	set $CompValue$ = boolToString(DirectoryExists($tmp$,$tmp1$))
	if ($ConstTest$ = $CompValue$)
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $ConstTest$ = "true"
	Set $tmp$ = "C:\Windows\system32\Boot"
	set $tmp1$ = "sysnative"
	set $CompValue$ = boolToString(DirectoryExists($tmp$,$tmp1$))
	if ($ConstTest$ = $CompValue$)
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $ConstTest$ = "true"
	Set $tmp$ = "C:\Windows\system32\Boot"
	; fall back to sysnative
	set $CompValue$ = boolToString(DirectoryExists($tmp$))
	if ($ConstTest$ = $CompValue$)
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif

	set $ConstTest$ = "false"
	Set $tmp$ = "C:\Windows\system32\Boot"
	set $tmp1$ = "32bit"
	set $CompValue$ = boolToString(DirectoryExists($tmp$,$tmp1$))
	if ($ConstTest$ = $CompValue$)
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif
endif

  • fileIsSymlink(<file name>) // seit 4.12.4.21 [W/L/M]
    Die Funktion gibt wahr zurück, wenn die genannte Datei oder das Verzeichnis existiert und ein symbolischer Link ist, ansonsten kommt die Antwort falsch.

  • LineExistsIn(<Zeile>, <Dateiname>) [W/L/M]
    Die Funktion gibt wahr zurück, wenn die Textdatei <Dateiname> eine Zeile beinhaltet, die im ersten Parameter beschrieben ist. Anderenfalls (oder falls die Datei garnicht existiert) wird falsch zurückgegeben.
    Jeder Parameter ist ein String-Ausdruck.

  • LineBeginning_ExistsIn(<string>, <Dateiname>) [W/L/M]
    Die Funktion gibt wahr zurück, wenn in der Textdatei <Dateiname> eine Zeile vorhanden ist, welche mit dem Parameter <string> beginnt. Anderenfalls (oder falls die Datei garnicht existiert) wird falsch zurückgegeben.
    Jeder Parameter ist ein String-Ausdruck.

  • LineContaining_ExistsIn( <string>, <Dateiname> ) //since 4.11.4.10 [W/L/M]
    Die Funktion gibt wahr zurück, wenn in der Textdatei <Dateiname> eine Zeile vorhanden ist, welche den Parameter <string> enthält. Anderenfalls (oder falls die Datei garnicht existiert) wird falsch zurückgegeben.
    Jeder Parameter ist ein String-Ausdruck.

  • XMLAddNamespace(<XMLfilename>, <XMLelementname>, <XMLnamespace>) [W]
    Mit dieser Funktion wird eine XML Namensraum im ersten XML-Element-Tag mit dem vergebenen Namen definiert (falls noch nicht vorhanden). Er wird ausgegeben, wenn ein Name eingefügt wurde. Die opsi-script XML-Patch-Sektion benötigt diese Namensraumdefinition. Der File muss so formatiert werden, dass das Element-Tag keine Zeilenumbrüche beinhaltet. Für ein Anwendungsbeispiel siehe im Kochbuch Kapitel "Einfügen einer Namensraumdefinition in eine XML-Datei".

  • HasMinimumSpace(<Laufwerksname>, <Kapazität>) [W]
    gibt true zurück, wenn mehr Platz als die geforderte <Kapazität> auf dem Laufwerk <Laufwerksname> vorhanden ist. <Kapazität> ist syntaktisch ebenso wie <Laufwerksname> ein String-Ausdruck. Die <Kapazität> kann als Nummer ohne genauere Bezeichnung (dann interpretiert als Bytes) oder mit einer näheren Bezeichnung wie "kB", "MB" oder "GB" ausgegeben werden (case sensitive).
    Anwendungsbeispiel:

if not (HasMinimumSpace ("%SYSTEMDRIVE%", "500 MB"))
  LogError "Es ist nicht genug Platz auf dem Laufwerk %SYSTEMDRIVE%, erforderlich sind 500 MB"
  isFatalError
endif

  • opsiLicenseManagementEnabled [W/L/M]
    gibt true zurück wenn das opsi System über ein anwendbares (freigeschaltetes) Lizenzmanagement verfügt.

if opsiLicenseManagementEnabled
   set $mykey$ = DemandLicenseKey ("pool_office2007")
else
   set $mykey$ = GetProductProperty("productkey","")
endif

  • runningAsAdmin [W]
    Boolsche Funktion welche 'true' liefert wenn das laufende Script mit Administrativen Rechten ausgeführt wird.
    Seit 4.11.1.1

  • isLoginScript [W]
    Boolsche Funktion welche 'true' liefert wenn das laufende Script über die opsi Erweiterung User Profile Management als userLoginScript läuft.
    Seit 4.11.2.1
    siehe auch : [isLoginScript]

  • contains(<str>, <substr>`)` [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn <substr> in <str> enthalten ist. Die Funktion arbeitet case sensitive.
    Seit 4.11.3
    siehe auch : [contains]

  • isNumber(<str>`)` [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn <str> einen ganzahligen Wert (integer) representiert.
    Seit 4.11.3
    siehe auch : [isNumber]

  • runningOnUefi [W]+ Boolsche Funktion welche 'true' liefert wenn das laufende Betriebssystem im UEFI mode gebootet wurde.
    Seit 4.11.4.3

  • runningInPE //since 4.12.0.13: [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn das laufende Betriebssystem ein Windows PE ist.

  • runningInWAnMode //since 4.12.4.16: [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn beim laufenden opsi-service Kontext der opsiserver = localhost ist.

  • isDriveReady(<drive letter>`)` //since 4.11.4.4: [W]
    Boolsche Funktion welche 'true' liefert auf das angebene Laufwerk zugegriffen werden kann (z.B. In Wechsellaufwerk ist ein Medium ist eingelegt)

  • saveTextFile(<list>, < filename>`)` //since 4.11.4.4: [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn die Liste <list> erfolgreich in < filename> gespeichert wurde.

  • saveTextFileWithEncoding(<list>, < filename>, <encoding>`) : bool` //since 4.11.6.4 [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn die Liste <list> erfolgreich in dem dem Zeichensatz <encoding> nach <filename> gespeichert wurde.

  • saveUnicodeTextFile(<list>, < filename>, <encoding>`) : bool` //since 4.12.4.14 [W/L/M]
    Boolsche Funktion welche 'true' liefert wenn die Liste <list> erfolgreich in dem dem Unicode Zeichensatz <encoding> nach <filename> gespeichert wurde.

  • CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>`)` //since 4.11.5.2: [W/L/M]
    vergleicht zwei Strings vom Typ <zahl>[.<zahl>[.<zahl>[.<zahl>]]] unter Verwendung des <relation str>, welcher einen der folgenden Werte haben darf: [<,⇐,=,>=,>].
    Seit Version 4.12.4.28:

  • Wenn in einem Vergleichspaar mindestens eine <zahl> führende Nullen hat, dann werden beide Zahlwerte als Nachkommastellen verglichen, d.h. 17 > 018 denn 0.17 > 0.018.

  • Wenn in einem Vergleichspaar mindestens eine <zahl> als letztes Zeichen keine Ziffer hat, dann wird zunächst nur der Zahlteil zum Vergleich herangezogen und bei Gleichheit auch der anhängende Buchstabe, d.h. 1.23a < 1.23b und 1.24a > 1.23b.

siehe auch: Stringfunktion`CompareDotSeparatedNumbers(<string1>, <string2>)>> : [CompareDotSeparatedNumbers_str]
siehe auch: Stringfunktion `CompareDotSeparatedStrings(
<string1>, <string2>`)` : [CompareDotSeparatedStrings_str]
siehe auch : [CompareDotSeparatedStrings_bool]

Example:
The code:

set $string1$ = "1.2.30.4.5"
set $string2$ = "1.20.30.4.5"
if CompareDotSeparatedNumbers($string1$, "<", $string2$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
if CompareDotSeparatedNumbers($string1$, "<=", $string2$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
if CompareDotSeparatedNumbers($string1$, "=<", $string2$)
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif
if CompareDotSeparatedNumbers($string1$, "=", $string2$)
	set $TestResult$ = "not o.k."
	LogWarning "failed"
else
	comment "passed"
endif
if CompareDotSeparatedNumbers($string1$, ">=", $string2$)
	set $TestResult$ = "not o.k."
	LogWarning "failed"
else
	comment "passed"
endif
if CompareDotSeparatedNumbers($string1$, "=>", $string2$)
	set $TestResult$ = "not o.k."
	LogWarning "failed"
else
	comment "passed"
endif
if CompareDotSeparatedNumbers($string1$, ">", $string2$)
	set $TestResult$ = "not o.k."
	LogWarning "failed"
else
	comment "passed"
endif

produce the log:

Set  $string1$ = "1.2.30.4.5"
  The value of the variable "$string1$" is now: "1.2.30.4.5"
Set  $string2$ = "1.20.30.4.5"
  The value of the variable "$string2$" is now: "1.20.30.4.5"
If
    Checking if "1.2.30.4.5" is "<" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, "<", $string2$)   <<< result true
Then
  comment: passed
Else
EndIf
If
    Checking if "1.2.30.4.5" is "<=" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, "<=", $string2$)   <<< result true
Then
  comment: passed
Else
EndIf
If
    Checking if "1.2.30.4.5" is "=<" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, "=<", $string2$)   <<< result true
Then
  comment: passed
Else
EndIf
If
    Checking if "1.2.30.4.5" is "=" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, "=", $string2$)   <<< result false
Then
Else
  comment: passed
EndIf
If
    Checking if "1.2.30.4.5" is ">=" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, ">=", $string2$)   <<< result false
Then
Else
  comment: passed
EndIf
If
    Checking if "1.2.30.4.5" is "=>" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, "=>", $string2$)   <<< result false
Then
Else
  comment: passed
EndIf
If
    Checking if "1.2.30.4.5" is ">" than / as "1.20.30.4.5"
  CompareDotSeparatedNumbers($string1$, ">", $string2$)   <<< result false
Then
Else
  comment: passed
EndIf

Und seit 4.12.4.28:

if CompareDotSeparatedNumbers("4.2.2", ">", "4.2.00079")
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

if CompareDotSeparatedNumbers("0.9.8h", ">", "0.9.8e")
	comment "passed"
else
	set $TestResult$ = "not o.k."
	LogWarning "failed"
endif

  • boolToString(<boolean expression>`)` : bool string (true/false) // since 4.12.0.0 [W/L/M]

  • stringToBool(<string expression: true/false>`)` : boolean // since 4.12.0.0 [W/L/M]

  • RegKeyExists(<regkey>[,<access str>]) : bool //since 4.12.0.16 [W]
    Prüft ob der als <regkey> übergeben String als Rgistrykey existiert. Wird der Registrykey gefunden so wird true zurückgegeben, ansonsten false.
    Die Zugriffsart ist per Default sysnative. Über den optionalen zweiten Parameter kann die Zugriffsart auch explizit angegeben werden. Dabei muss der übergebene <access str> einer der folgenden Werte sein: 32bit, sysnative, 64bit.
    (siehe auch: Kapitel 64 Bit-Unterstützung)

Beispiele:

RegKeyExists("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")

RegKeyExists("HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\general","32bit")

  • RegVarExists(<regkey>, <var str>[,<access str>]) : bool //since 4.12.0.16 [W]
    Prüft ob der als <regkey> übergeben String als Registrykey existiert und ob dort eine Variable mit dem Namen <var str> existiert. Wird beides gefunden so wird true zurückgegeben, ansonsten false.
    Die Zugriffsart ist per Default sysnative. Über den optionalen dritten Parameter kann die Zugriffsart auch explizit angegeben werden. Dabei muss der übergebene <access str> einer der folgenden Werte sein: 32bit, sysnative, 64bit.
    (siehe auch: Kapitel 64 Bit-Unterstützung)

Beispiele:

RegVarExists("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon","Shell")

RegVarExists("HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\general","bootmode","32bit")

  • runningWithGui : bool` //since 4.12.3.6 [W/L/M] Liefert true wenn das ausgeführte Betriebsystem eine GUI hat (bei Win+Mac immer true)

isPingReachable(<host>) : boolean //since 4.12.3.6 [W/L/M]
Liefert true wenn wenn die mit <host> angegebene Adresse per Ping erreichbar ist. Dabei kann <host> sowohl ein IP-Name als auch eine IP-Nummer sein.

Include Kommandos [W/L/M]

Die Verwendung von Include Kommandos führt schnell zu unübersichtlichen Code.
Lassen Sie die Finger davon wenn Sie Anfänger sind.

Include Kommandos: Syntax

Mit Include Kommandos kann der Inhalt einer externen Datei dem laufende Script hinzugefügt werden. Dies kann entweder einfügend oder anhängend erfolgen. Die Include Kommandos sind normale Kommandos der primären Sektionen. Die eingefügten Dateien können weitere Include Kommandos enthalten.
Diese Kommandos gibt es seit Version 4.11.3

  • include_insert <file name> [W/L/M]
    Fügt den Inhalt von <file name> nach der aktuellen Zeile im laufenden Script ein. Somit ist die erste Zeile der eingefügten Datei die nächste Zeile welche der opsi-script interpretiert.

  • include_append <file name> [W/L/M]
    Fügt den Inhalt von <file name> am Ende des laufenden Scriptes ein. Diese Anweisung dient vor allem dazu Sektionen aus z.B. einer Bibliothek hinzu zufügen.

Für beide Funktionen gilt:
<file name> ist:

  • Ein kompletter Pfad zu einer Datei. [W/L/M]

  • Eine Datei in %ScriptPath% [W/L/M]

  • Eine Datei in %opsiScriptHelperPath%\lib [W]
    Entspricht: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • Eine Datei in %ScriptPath%/../lib //since 4.11.5.2 [W/L/M]

  • Eine Datei in %OpsiScriptDir%\lib [W]

Die Prüfung erfolgt in dieser Reihenfolge. Die erste Datei die gefunden wird, wird genommen.

Beispiel:
Wir haben folgendes Script:

[Actions]
include_append "section_Files_del_tmp_dummy.opsiinc"
include_insert "include-test1.opsiinc"

Dabei hat die Datei include-test1.opsiinc folgenden Inhalt:

DefVar $inctestvar$
set $inctestvar$ = "inctest"
Files_del_tmp_dummy
include_append "section_Files_copy_inctest.opsiinc"
Files_copy_inctest

if fileExists("c:\opsi.org\tmp\dummy.txt")
	comment "passed"
else
	comment "failed"
	set $TestResult$ = "not o.k."
	LogWarning "include test failed"
endif

if fileExists("%scriptpath%\test-files\dummy.txt")
	comment "passed"
else
	comment "failed"
	set $TestResult$ = "not o.k."
	LogWarning "include test failed"
endif
Files_del_tmp_dummy

Dabei hat die Datei section_Files_copy_inctest.opsiinc folgenden Inhalt:

[Files_copy_inctest]
copy "%scriptpath%\test-files\dummy.txt" "c:\opsi.org\tmp"

Dabei hat die Datei section_Files_del_tmp_dummy.opsiinc folgenden Inhalt:

[Files_del_tmp_dummy]
del -f "c:\opsi.org\tmp\dummyt.txt"

Include Kommandos: Library

Mit der Version 4.11.3 werden folgende Includefiles in %OpsiScriptDir%\lib ausgeliefert:

insert_check_exit_code.opsiinc:

; opsi include file

DefVar $ExitCode$

include_append "section_sub_check_exitcode.opsiinc"

insert_get_licensekey.opsiinc:

; opsi include file

DefVar $LicenseRequired$
DefVar $LicenseKey$
DefVar $LicensePool$

include_append "section_sub_get_licensekey.opsiinc"

section_sub_check_exit_code.opsiinc:

;opsi include file

[Sub_check_exitcode]
comment "Test for installation success via exit code"
set $ExitCode$ = getLastExitCode
; informations to exit codes see
; http://msdn.microsoft.com/en-us/library/aa372835(VS.85).aspx
; http://msdn.microsoft.com/en-us/library/aa368542.aspx
if ($ExitCode$ = "0")
	comment "Looks good: setup program gives exitcode zero"
else
	comment "Setup program gives a exitcode unequal zero: " + $ExitCode$
	if ($ExitCode$ = "1605")
		comment "ERROR_UNKNOWN_PRODUCT	1605	This action is only valid for products that are currently installed."
		comment "Uninstall of a not installed product failed - no problem"
	else
		if ($ExitCode$ = "1641")
			comment "looks good: setup program gives exitcode 1641"
			comment "ERROR_SUCCESS_REBOOT_INITIATED	1641	The installer has initiated a restart. This message is indicative of a success."
			ExitWindows /Reboot
		else
			if ($ExitCode$ = "3010")
				comment "looks good: setup program gives exitcode 3010"
				comment "ERROR_SUCCESS_REBOOT_REQUIRED	3010	A restart is required to complete the install. This message is indicative of a success."
				ExitWindows /Reboot
			else
				logError "Fatal: Setup program gives an unknown exitcode unequal zero: " + $ExitCode$
				isFatalError "Exit Code: "+ $ExitCode$
			endif
		endif
	endif
endif

section_sub_get_licensekey.opsiinc:

; opsi include file

[Sub_get_licensekey]
if opsiLicenseManagementEnabled
	comment "License management is enabled and will be used"

	comment "Trying to get a license key"
	Set $LicenseKey$ = demandLicenseKey ($LicensePool$)
	; If there is an assignment of exactly one licensepool to the product the following call is possible:
	; Set $LicenseKey$ = demandLicenseKey ("", $ProductId$)
	;
	; If there is an assignment of a license pool to a windows software id, it is possible to use:
	; DefVar $WindowsSoftwareId$
	; $WindowsSoftwareId$ = "..."
	; Set $LicenseKey$ = demandLicenseKey ("", "", $WindowsSoftwareId$)

	DefVar $ServiceErrorClass$
	set $ServiceErrorClass$ = getLastServiceErrorClass
	comment "Error class: " + $ServiceErrorClass$

	if $ServiceErrorClass$ = "None"
		comment "Everything fine, we got the license key '" + $LicenseKey$ + "'"
	else
		if $ServiceErrorClass$ = "LicenseConfigurationError"
			LogError "Fatal: license configuration must be corrected"
			LogError getLastServiceErrorMessage
			isFatalError $ServiceErrorClass$
		else
			if $ServiceErrorClass$ = "LicenseMissingError"
				LogError "Fatal: required license is not supplied"
				isFatalError $ServiceErrorClass$
			endif
		endif
	endif
else
	LogError "Fatal: license required, but license management not enabled"
	isFatalError "No Licensemanagement"
endif

Aufrufe von Unterprogrammen [W/L/M]

Anweisungen in primären Sektionen, die auf einen Programmtext an anderer Stelle verweisen, sollen hier Unterprogramm- oder Prozeduraufrufe heißen.

if ($MSVersion$>="6")
     sub_install_win7
else
  if ( $MSVersion$ = "5.1" )
    sub_install_winXP
  else
    stop "not a supported OS-Version"
  endif
endif

So "ruft" in obigem Beispiel die Anweisung in der Actions-Sektion

sub_install_winXP

die Sektion '[sub_install_winXP]', welche dann im Skript an anderer Stelle nachzulesen ist als

[sub_install_winXP]
Files_Kopieren_XP
WinBatch_SetupXP

Weil es sich in diesem Beispiel um eine Sub-Sektion handelt, also immer noch um eine primäre Sektion, kann in ihr wiederum auf weitere Sektionen verwiesen werden, in diesem Fall auf die Sektionen '[Files_Kopieren_XP]' und '[WinBatch_Setup_XP]'.

Generell gibt es drei Wege um die genannten Anweisungen zu platzieren:

  1. Der gebräuchlichste Ort für den Aufruf eines Sub-Sektion ist eine weitere interne Sektion im Skript, wo die aufgerufene Befehle platziert werden (wie in dem Beispiel).

  2. Die bezeichneten Befehle können auch in einer andere Datei untergebracht werden, welche als externe Sektion läuft.

  3. Jede String-Liste kann als eine Befehlsliste für einen Sub-Programm Aufruf benutzt werden.

Zur Syntax der Sub-Programm Aufrufe im einzelnen:

Komponenten eines Unterprogrammaufrufs

Formal kann die Syntax wie folgt aufgerufen werden
'<proc. type>(<proc. name> | <External proc. file> | <Stringlisten Funktion> )'

Diese Ausdrücke können durch einen oder mehrere Parameter ergänzt werden (ist vom Ablauftyp abhängig).

Das bedeutet: Ein Ablauf besteht aus drei Hauptbereichen.

Der erste Teil ist der Unterprogramm Typnamen.
Beispiele für Typennamen sind Sub (Aufruf einer primären Sektion bzw. eines Unterprogramms des primären Typs) sowie Files und WinBatch (diese Aufrufe sind speziell für die zweite Sektion).
Den kompletten Überblick über die existierenden Sub-Programmtypen sind am Anfang von Kapitel "Aufrufe von Unterprogrammen" genauer beschrieben.

Der zweite Teil bestimmt, wo und wie die Zeilen des Subprogramms gefunden werden. Dazu gibt es zwei Möglichkeiten:

  1. Das Sub-Programm ist eine Zeilenabfolge, die im sich ausführbaren Bereich des opsi-script Skriptes als interne Sektion befindet. Es wird ein eindeutiger Sektionsname (bestehend aus Buchstaben, Zahlen und einigen Sonderzeichen) hinzugefügt, um den Programmtyp näher zu beschreiben (ohne Leerzeichen).
    z.B.
    'sub_install_winXP'
    oder
    'files_copy_winXP'
    Sektionsnamen sind case insensitive wie jeder andere String.

  2. Wenn der Programmtyp alleine steht, wird eine String-Liste oder ein String-Ausdruck erwartet. Wenn der folgende Ausdruck nicht als String-Listenausdruck aufgelöst werden kann (vgl. 3.) wird ein String-Ausdruck erwartet. Der String wird dann als Dateiname interpretiert. Der opsi-script versucht die Datei als Textdatei zu öffnen und interpretiert die Zeilen als eine externe Sektion des beschriebenen Typs.
    Bsp.:
    sub '"p:\install\opsiutils\mainroutine.opsiscript"'
    Es wird versucht die Zeile mainroutine.opsiscript als Anweisung der Subsektion auszulesen.
    Der String wird als Dateiname interpretiert und kann dabei folgendes sein:

    • Ein kompletter Pfad zu einer Datei. [W/L/M]

    • Eine Datei in %ScriptPath% [W/L/M]

    • Eine Datei in %opsiScriptHelperPath%\lib [W]
      Entspricht: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

    • Eine Datei in %ScriptPath%/../lib [W/L/M]

    • Eine Datei in %OpsiScriptDir%\lib [W]

Die Prüfung erfolgt in dieser Reihenfolge. Die erste Datei die gefunden wird, wird genommen.

  1. Wenn der Ausdruck auf eine alleinstehenden spezifizierten Sektionstyp folgt, kann dieser als ein String-Listenausdruck aufgelöst werden. Die String-Listenkomponenten werden dann als ein Sektionsausdruck interpretiert.
    Dieser Mechanismus kann bspw. dazu verwendet werden, um eine Datei mit Unicode-Format zu laden und dann mit den üblichen Mechanismen zu bearbeiten:

registry loadUnicodeTextFile("%scriptpath%/opsiorgkey.reg") /regedit

Syntaktisch hat diese Zeile die drei Bestandteile:
* registry, die eigentliche Anweisung, die den Sektionstyp spezifiziert.
* loadUnicodeTextFile (..), ein String-Listenausdruck, in dem näher beschrieben ist, wie man eine Zeile der registry Sektion bekommt.
* /regedit, Option als 2. Parameter (typspezifisch, s. das Folgende).

In diesem Beispiel gibt der Aufrufparameter ein Beispiel an für den dritten Teil eines Subsektionsaufrufs:

Der dritte Part eine Aufrufs umfasst spezielle Aufrufsoptionen. Referenzen für die Aufrufsoptionen beziehungsweise für eine genauere Beschreibung der Sektionsaufrufe finden sich in siehe Kapitel "Sekundäre Sektionen".

Reboot-Steueranweisungen

Die Anweisung ExitWindows dient zur Steuerung von Reboot, Shutdowns, u.ä. Vorgängen welche erst nach Beendigung des opsi-script selbst durchgeführt werden. Die Benennung des Befehls und die Tatsache, das es ExitWindows nicht ohne Modifier gibt, ist historisch bedingt: Unter Windows 3.1 konnte man Windows beenden und zur DOS-Ebene zurück wechseln.

  • ExitWindows /RebootWanted
    Abgekündigt: vermerkt eine Rebootanfrage eines Skriptes in der Registry, lässt aber das opsi-script Skript weiterlaufen und weitere Skripte abarbeiten und rebootet erst, wenn alle Skripte durchgelaufen sind. Eigentlich wird dieses Kommando jetzt als ExitWindows /Reboot behandelt (da ansonsten eine Installation fehlschlagen könnte, weil ein benötigtes Produkt nicht komplett installiert wurde).

  • ExitWindows /Reboot [W/L/M]
    unterbricht eine Skriptfolge durch die Auslösung des Reboots nachdem der opsi-script die Bearbeitung des laufenden Skriptes beendet hat.

  • ExitWindows /ImmediateReboot [W/L/M]
    unterbricht die normale Ausführung eines Skriptes, an der Stelle, an der er aufgerufen wird. Nach dem der Befehl aufgerufen wurde, werden (außer if-Anweisungen) keine Anweisungen mehr ausgeführt und der Rechner rebootet. Dabei bleibt in der opsi-Umgebung der Actionrequest der das Skript aufgerufen hat bestehen.Dadurch wird gewährleistet, dass nach dem Neustart der opsi-script wieder das Skript, dass abgebrochen wurde, startet. Das Skript sollte daher so konzipiert sein, dass die Ausführung nach dem Punkt der Unterbrechung fortgesetzt wird (andernfalls erhalten wir möglicherweise eine Endlosschleife…​) vgl. das Beispiel in diesem Abschnitt.

  • ExitWindows /ShutdownWanted [W]
    sorgt dafür, dass der PC nach Abschluss der Installation aller angefragten Produkte heruntergefahren wird.

Wie man eine Markierung setzt, um sicherzustellen, dass das Skript nicht in eine Endlosschleife läuft, wenn ExitWindows /ImmediateReboot aufgerufen wird, demonstriert folgendes Codebeispiel:

DefVar $Flag$
DefVar $WinstRegKey$

Set $WinstRegKey$ = "HKLM\SOFTWARE\opsi.org\winst"
Set $Flag$ = GetRegistryStringValue32("["+$WinstRegKey$+"] "+"RebootFlag")

if not ($Flag$ = "1")
  ;=========================
  ; Anweisungen vor Reboot

  Files_doSomething

  ; Reboot initialisieren ...
  Set $Flag$ = "1"
  Registry_SaveRebootFlag
  ExitWindows /ImmediateReboot

else
  ;=========================
  ; Anweisungen nach Reboot

  ; Rebootflag zurücksetzen
  Set $Flag$ = "0"
  Registry_SaveRebootFlag

  ; die eigentlichen Anweisungen

  Files_doMore

endif


[Registry_SaveRebootFlag]
openKey [$WinstRegKey$]
set "RebootFlag" = "$Flag$"

[Files_doSomething]
; eine Sektion, die vor dem Reboot ausgeführt wird

[Files_doMore]
; eine Sektion, die nach dem Reboot ausgeführt wird

Scriptabbruch und fehlgeschlagene Installation anzeigen [W/L/M]

Passieren bei einer Installation Fehler, die zum Fehlschlagen der Installation führen, so sollte dies an den Server zurückgemeldet werden.

Um in einem opsi-script Skript, eine Installation als gescheitert zu erklären, gibt es eine Ausdruck namens
isFatalError [W/L/M]
unterbricht die normale Ausführung eines Skriptes, an der Stelle, an der er aufgerufen wird. Nach dem der Befehl aufgerufen wurde, werden keine Anweisungen mehr ausgeführt und als Skriptergebnis wird 'failed' zurückgeliefert. Wird dieser Befehl nicht aufgerufen, so ist das Skriptergebnis 'success'.

Seit 4.11.3.2 ist auch die folgende Variante erlaubt:

  • isFatalError <string> [W/L/M]
    wobei <string> als kurze Fehlerbeschreibung an den opsi-server als 'actionProgress' weitergegeben wird und im opsi-configed angezeigt wird.

Es gibt keinen Automatismus innerhalb eines Winst-Skriptes, um zu einen 'failed' Ergebnis zu kommen. Sie müssen skriptgesteuert den Fehler selbst feststellen. Hierzu gibt Ihnen der opsi-script einige Hilfsmittel.

Ein „fataler Fehler“ sollte zum Beispiel ausgelöst werden, wenn der Plattenplatz für die Installation nicht ausreicht:

DefVar $SpaceNeeded$"
Set $SpaceNeeded$" = "200 MB"

if not(HasMinimumSpace ("%SYSTEMDRIVE%", $SpaceNeeded$"))
  LogError "Nicht genügend Platz. Erforderlich sind "+$SpaceNeeded$
  isFatalError
  ; beendet die Skriptausführung und setzt den Produktstatus auf failed
else
  ; die Installation wird gestartet
  ; ...
endif

Fehler die von Funktionen des opsi-script zurückgeliefert werden, werden in die Logdatei geschrieben und erhöhen den Fehlerzähler des opsi-script. Dieser Fehlerzähler kann ausgewertet werden. So besteht auch die Möglichkeit, in einem kritischen Abschnitt eines Skriptes festzustellen, ob Fehler bzw. wie viele Fehler aufgetreten sind (und abhängig hiervon ggf. isFatalError aufzurufen).

  • markErrorNumber [W/L/M]
    startet die Fehlerzählung für einen Abschnitt.
    Die Zahl der Fehler, die ab dieser Stelle aufgetreten sind, kann dann abgerufen werden mit dem Ausdruck: errorsOccurredSinceMark

  • errorsOccurredSinceMark [W/L/M]
    wird verwendet um das Auftreten von Fehlern seit dem Aufruf von markErrorNumber zu ermitteln. Dieser Ausdruck dient dann zum Vergleich mit einer Zahl.
    Z.B. kann man die Bedingung „es kam in diesem Abschnitt mindestens ein Fehler vor“ so formulieren:
    if errorsOccurredSinceMark > 0

Sofern die Skriptanweisungen nicht direkt einen Fehler produzieren, jedoch aufgrund bestimmter Umstände eine Situation trotzdem als Fehlersituation gewertet werden soll, kann auch mittels der Anweisung logError eine Fehlermeldung generiert werden.

markErrorNumber
; Fehler, die nach dieser Marke auftreten werden gezählt
; und werden als fatale Fehler gewertet

logError "test error"
; wir schreiben einen Kommentar "test error" in die Logdatei
; und die Fehleranzahl wird um eins erhöht
; für Testzwecke kann man diese Zeile auskommentieren

if errorsOccurredSinceMark > 0
    ; die Skriptausführung wird so bald wie möglich beendet
    ; und setzt den Produktstatus auf "failed"

    isFatalError
    ; Kommentare können  noch geschrieben werden

    comment "error occured"

else
    ; kein Fehler aufgetreten, gibt folgendes aus:

    comment "no error occured"
endif

  • isSuccess //since 4.11.3.7 [W/L/M]
    Bricht das Script ab ohne einen Fehler zu melden.

  • noUpdateScript //since 4.11.3.7 [W/L/M]
    Führt nach einem Setup kein Updatescript aus auch wenn eines vorhanden ist.

  • isSuspended //since 4.11.4.1 [W/L/M] Bricht die Scriptabarbeitung ab ohne das ein Erfolg oder Fehler gemeldet werden. Der ActionRequest (z.B. 'setup') bleibt unverändert.

Lokale Funktionen [W/L/M]

Seit Version 4.12 kennt opsi-script auch lokale Funktionen.

Ein Beispiel:

DefFunc myFunc(val $str1$ : string, $str2$ : string) : string
	set $result$ = $str1$ + $str2$
endfunc

Konzept

Ziel dieser Erweiterung ist die Umsetzung folgender Konzepte:

  • Funktionen mit Rückgabewert:
    Die Funktionen haben einen Rückgabewert, welcher vom Typ string oder stringlist ist. Der Aufruf einer solchen Funktion kann überall da erfolgen, wo ein Stringausdruck bzw. eine Stringliste erwartet wird.
    Funktionen ohne Rückgabewert sind ab 4.12.0.16 auch erlaubt und müssen als void deklariert werden.

  • Frei definierbare Aufrufparameter: Einer Funktion können Parameter übergeben werden. Diese Parameter werden bei der Deklaration der Funktion definiert. Die Aufrufparameter können vom Typ string oder stringlist sein.
    Die Aufrufparameter können als 'CallByValue' oder per 'CallByReference' übergeben werden. 'CallByValue' ist der Default, das bedeutet: Wird keine Aufrufmethode explizit angegeben, so wird 'CallByValue' verwendet. Soll 'CallByValue' explizit angegeben werden, so erfolgt dies über das Schlüsselwort val. 'CallByValue' bedeutet, dass beim Aufruf der Funktion der Inhalt des Ausdrucks für einen Aufrufparameters auf die lokale Variable des Aufrufparameters kopiert wird.
    'CallByReference' muss über das Schlüsselwort ref explizit angegeben werden. 'CallByReference' bedeutet, dass beim Aufruf eine Verbindung zwischen der aufrufenden Variable und dem lokalen Aufrufparameter erstellt wird. Eine Änderung der lokalen Variable des Aufrufparameters wirkt sich direkt auf die beim Aufruf verwendete Variable aus.
    Die Übergabeparameter stehen innerhalb der Funktion als lokale Variablen zur Verfügung.

  • Lokale Variablen:
    Eine Funktion enthält lokale Variablen. Implizit gibt es die Aufrufparameter als lokale Variablen und die Variable $result$, welche vom Typ des Rückgabewertes ist. Darüberhinaus können weitere Variablen innerhalb der Funktion definiert werden.
    All dies Variablen sind lokal, d.h. sie sind nur innerhalb dieser Funktion sichtbar. Eine lokale Variable mit dem selben Namen einer globalen Variable verdeckt innerhalb der Funktion die entsprechende globale Variable.

  • Geschachtelte Funktionen:
    Eine lokale Funktion kann wiederum eine oder mehrere Definitionen von lokalen Funktionen enthalten. Diese Funktionen sind nur innerhalb der Funktion sichtbar, in der sie definiert sind.

  • Rekursive Aufrufe:
    Eine Funktion kann sich selbst rekursiv aufrufen.

  • Primäre und sekundäre Sektionen innerhalb von Funktionen:
    Der Funktionskörper kann eigene Sektionen enthalten. Diese sind lokal zu dieser Funktion, also nur innerhalb der Funktion sichtbar.

Syntax

Definition

DefFunc <func name>([calltype parameter ptype][,[calltype parameter ptype]]) : ftype
<function body>
endfunc

Dabei ist:

  • DefFunc das Schlüsselwort zur Beginn der Definition einer lokalen Funktion.

  • '<func name>' der frei gewählte Name der Funktion.

  • 'calltype' der Aufruftyp [val | ref]. Wird kein Aufruftyp angegeben, so gilt val als gesetzt.

  • 'parameter' der freigewählte Name des Aufrufparameters, welcher unter diesem Namen innerhalb der Funktion als lokale Variable zur Verfügung steht.

  • 'ptype' der Datentyp des Parameters und entweder string oder stringlist.

  • 'ftype' der Datentyp der Funktion und entweder string, stringlist oder void. Die void-Deklaration bedeutet, dass es keine Rückabe gibt.

  • '<function body>' der Körper der Funktion, welcher dem opsi-script Syntax genügen muss.
    In diesem Teil gibt es die automatisch erzeugte lokale Variable $result$, welche den Datentyp der Funktion hat (String/Stringliste) und dazu dient, den Rückgabewert aufzunehmen.

  • endfunc das Schlüsselwort am Ende einer Funktionsdefinition.

Eine Funktion muss definiert werden bevor sie aufgerufen werden kann.

Beispiele

Einfache Funktion welche zwei Strings miteinander verbindet:

[actions]
DefVar $mystr$
DefVar $str1$
set $str1$ = 'ha'

DefFunc myFunc(val $str1$ : string, $str2$ : string) : string
	set $result$ = $str1$ + $str2$
endfunc

set $mystr$ = myFunc("he","ho")
set $mystr$ = myFunc("he",timeStampAsFloatStr)
set $mystr$ = myFunc("he",$str1$)

Erwartete Ergebnisse:

  • 'heho'

  • 'he42921.809'

  • 'heha'

Funktion vom Type stringlist welcher ein string und eine stringlist übergeben werden:

[actions]
DefVar $mystr$
DefVar $str1$
DefStringlist $list1$
DefStringlist $list2$

set $str1$ = 'ha'

DefFunc myFunc1(val $str1$ : string, $list1$ : stringlist) : stringlist
	set $result$ = createStringlist($str1$ , takeString(2,$list1$))
endfunc

set $list2$ = splitstring("/etc/opsi/huhu","/")
set $list1$ = myFunc1("hi",$list2$)

Erwartete Ergebnisse:

  • $list1$ = [hi,opsi]

Funktion vom Type string welcher ein boolscher string übergeben wird:

[actions]

DefFunc myFunc2($str1$ : string) : string
	set $result$ = booltostring($str1$)
endfunc

if stringtobool(myfunc2('1 > 0'))
	comment "true"
else
 	comment "false"
endif

Erwartete Ergebnisse:

  • 'true'

Funktion vom Type string welcher ein string übergeben wird mit lokaler Variable:

[actions]
DefVar $mystr$

DefFunc myFunc3($str1$ : string) : string
	DefVar $locstr1$
	set $locstr1$ = '123'
	set $result$ = $locstr1$ + $str1$
endfunc

set $mystr$ = myFunc3("he")

Erwartete Ergenisse:

  • '123he'

Funktion vom Type string welcher ein string übergeben wird mit lokaler Variable und geschachtelter Funktion:

[actions]
DefVar $mystr$

DefFunc myFunc4($str1$ : string) : string
	DefVar $locstr1$

	DefFunc myFunc5($str1$ : string) : string
		set $result$ = 'inner' + $str1$
	endfunc

	set $locstr1$ = '123'
	set $result$ = $str1$ + myFunc5($locstr1$)
endfunc

set $mystr$ = myFunc4("outer")

Erwartete Ergebnisse:

  • 'outerinner123'

Einfache Funktion vom Type string welcher ein string by reference übergeben wird mit lokaler Variable:

[actions]
DefVar $mystr$
DefVar $str1$
DefVar $str2$

set $str1$ = 'ha'
set $str2$ = 'hi'

DefFunc myFunc6(ref $str1$ : string) : string
	DefVar $locstr1$
	set $locstr1$ = '123'
	set $str1$ = 'setinlocal'
	set $result$ = $locstr1$ + $str1$
endfunc

set $mystr$ = myFunc6($str2$)
set $mystr$ = $str1$ + $str2$

Erwartete Ergebnisse:

  • '123setinlocal'

  • 'hasetinlocal'

Funktion vom Type stringlist welcher eine Variable vom Type stringlist mit 'call by reference' übergeben wird mit lokalen stringlist Variable:

[actions]
DefVar $mystr$
DefStringlist $list1$
DefStringlist $list2$

et $list2$ = splitstring("/etc/opsi/huhu","/")

DefFunc myFunc7(ref $list1$ : stringlist) : stringlist
	DefStringlist $loclist1$
	set $loclist1$ = splitstring("/a/b/c","/")
	set $list1$ = createStringList('setinlocal')
	set $loclist1$ = addListToList($loclist1$,$list1$)
	set $result$ = $loclist1$
endfunc

set $list1$ = myFunc7($list2$)
comment "$list2$ index 0: " + takestring(0,$list2$)

Erwartete Ergenisse:

  • $list1$ = [,a,b,c,setinlocal]

  • 'setinlocal'

Funktion vom Type stringlist welcher ein string übergeben wird mit lokaler Variable und lokaler sekundärer Sektion:

[actions]
DefStringlist $list1$

DefFunc myFunc8($str1$ : string) : stringlist
	DefStringlist $loclist1$
	set $loclist1$ = getoutstreamfromsection("shellInAnIcon_test")
	set $result$ = $loclist1$

	[shellinanicon_test]
	set -x
	$str1$
endfunc

set $list1$ = myFunc8('pwd')

Erwartete Ergebnisse:

  • $list1$ = [+ pwd, /home/uib/gitwork/lazarus/opsi-script]

Funktion vom Type void (also ohne Rückgabe) welcher ein string übergeben wird:

[actions]
ScriptErrorMessages = false
DefVar $str1$

set $str1$ = 'haha'

DefFunc myNoResultFunc(ref $str1$ : string) : void
	set $str1$ = "huhu"
endfunc

myNoResultFunc($str1$)
comment "$str1$ is: "+$str1$

Erwartete Ergebnisse:

  • $str1$ is: huhu

Funktion vom Type string welcher kein Parameter übergeben wird:

[actions]
ScriptErrorMessages = false
DefVar $str1$

DefFunc myNoParamFunc() : string
	set $result$ = "huhu"
endfunc

set $str1$ = myNoParamFunc()

Erwartete Ergebnisse:

  • $str1$ is: huhu

Import von Library Funktionen [W/L/M]

importLib <string expr> ; import library // since 4.12.0.0
<string expr> : <file name>[.<file extension>][::<function name>]
Wenn keine '.<file extension>' (Dateierweiterung übergeben wird, so wird .opsiscript als Default verwendet.
Wenn kein '::<function name>' über geben wird, so werden alle Funktionen der angegebenen Datei importiert.

<file name> ist:

  • Ein kompletter Pfad zu einer Datei. [W/L/M]

  • Eine Datei in %ScriptPath% [W/L/M]

  • Eine Datei in %opsiScriptHelperPath%\lib [W]
    Entspricht: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • Eine Datei in %ScriptPath%/../lib //since 4.11.5.2 [W/L/M]

  • Eine Datei in %OpsiScriptDir%\lib [W] oder /usr/share/opsi-script/lib [L]

Die Prüfung erfolgt in dieser Reihenfolge. Die erste Datei die gefunden wird, wird genommen.

User Profile Management [W/L/M]

Diese Erweiterung funktioniert nicht zusammen mit der WAN-Erweiterung! Schalten Sie auf WAN-Clients bitte das Login-Event nicht an.

Einführung

Der opsi-script verfügt über eine Reihe von speziellen Befehlen um Modifikationen in Profilen vorzunehmen. Diese Arbeiten aber auf den lokalen Profilen und sind beim Einsatz von Roaming Profiles (Servergespeicherte Profile) weitgehend nutzlos. Mit der opsi Erweiterung User Profile Management wird eine Möglichkeit geschaffen auch hier Veränderungen an den Profilen vorzunehmen. Dies geschieht in dem beim User Login der opsi-script gestartet wird um spezielle userLoginScripte auszuführen.

Konzept

Wenn die Profile nicht bei der Installation der Software gleich mit gepatcht werden können, muss zwischen dem Maschinen Teil und dem Profil Teil der Installation deutlicher unterschieden werden. Die kann sowohl innerhalb eines Scriptes geschehen, als auch durch die Auslagerung des Profil Teils in ein eigenes Script.

Die Kernkonzepte dieser opsi Erweiterung sind:

  • Ausführen spezieller userLoginScripte beim Login des users
    Im Rahmen des User Logins wird der opsi-script gestartet aber in einem speziellem Modus ausgeführt in dem nur bei den Produkten hinterlegte 'userLoginScripte' ausgeführt werden.

  • Ausführen der Scripte mit administrativen Rechten aber im Userkontext
    Domain Login Scripte werden vom User mit user Rechten ausgeführt. Die opsi 'userLoginScripte' werden vom opsi-script ausgeführt, welcher mit administrativen Rechten läuft. Gleichzeitig begibt sich der opsi-script aber in den Kontext des Users der sich eingelogged hat, so dass die Manipulation der Profile mit den selben Befehlen durchgeführt werden kann, wie in einem Domain Loginscript.

  • Ausführen der Scripte innerhalb des opsi-service Kontext
    Die opsi userLoginScripts laufen innerhalb des opsi-service Kontextes und haben so über Scriptkonstanten die Informationen zu Produktnamen, Version und Packageversion die gerade bearbeitet wird. Weiterhin sind die Werte der Produktproperties im Zugriff sowie alle sonstigen Informationen welche eventuell über opsiservicalls abgerufen werden sollen.

Spezielle opsi-script Funktionen

  • Aufrufparameter /allloginscripts oder /loginscripts
    Wird der opsi-script im opsi-service Kontext mit dem zusätzlichen Parameter /allloginscripts oder /loginscripts aufgerufen, so hat das im wesentlichen folgende Auswirkungen:

    • Es werden die Produkte ermittelt, welche ein 'userLoginScript' haben.
      Bei /allloginscripts werden für alle diese Produkte die 'userLoginScripte' ausgeführt.
      Bei /loginscripts werden nur die Loginscripts auf einem Client ausgeführt, bei denen das entsprechende Produkt dem Client bekannt ist, also installiert ist oder war.
      Siehe auch: Konfiguration

    • Es wird der user der sich eingelogt hat ermittelt und dafür gesorgt, dass die Konstanten zum aktuellen User wie z.B. %CurrentAppdataDir% auf die entsprechenden Verzeichnisse des eingelogten users zeigen. Ebenso werden Registry Operationen (Registry Sektionen und GetRegistryString) welche sich auf HKCU beziehen, so ausgeführt, dass die Daten aus dem Registryzweig des Users kommen.

  • Aufrufparameter /silent
    Der Aufrufparameter /silent sorgt dafür, dass während der Scriptabarbeitung das Fenster des opsi-script nicht angezeigt wird.

  • Funktion GetScriptMode
    Um innerhalb eines Scriptes zu unterscheiden in welchem Modus das Script gerade ausgeführt wird, liefert die Funktion GetScriptMode zwei mögliche Werte zurück:

    • 'Machine'
      Das Script wird nicht als 'userLoginScript' ausgeführt (sondern z.B. als setup oder uninstall Script).

    • 'Login'
      Das Script wird als 'userLoginScript' ausgeführt.

  • Primäre Sektion ProfileActions
    diese Sektion kann dazu dienen, Aktionen auf Userprofilen zusammenzufassen. Dabei kann eine Syntax verwendet werden, die es ermöglicht, diese Sektion sowohl als Bestandteil eines normalen Loginscripts, als auch als 'userLoginScript' zu nutzen. Dazu wird diese primäre Sektion auf unterschiedliche Art ausgewertet, je nachdem ob das script im Machine mode oder Login mode (also als userLoginScript) läuft.

    • 'Login'
      Läuft ein Script als 'userLoginScript' und enthält eine Sektion ProfileActions, so wird die Scriptabarbeitung bei dieser Sektion gestartet (und nicht bei Actions).

    • 'Machine'
      Läuft ein Script als normales Installationsscript, so kann die Sektion ProfileActions ähnlich einer 'Sub'-Sektion als Untersektion aufgerufen werden. Für die Abarbeitung dieser Sektion gilt: Für alle 'Registry'-Sektions Aufrufe ist implizit '/AllNtUserDats' gesetzt. Für alle 'Files'-Sektions Aufrufe ist implizit '/AllNtUserProfiles' gesetzt.
      Seit Version 4.11.3.2 gilt auch: Für alle 'Patches'-Sektions Aufrufe ist implizit '/AllNtUserProfiles' gesetzt.

  • Registry Sektionen

    • Registry Sektionen welche auf 'HKCU' bzw. 'HKEY_CURRENT_USER' arbeiten, werden im Loginscript Mode so ausgeführt, dass die Änderungen im Zweig des eingeloggten users landen. Entsprechendes gilt für die Funktionen GetRegistryStringValue*.

    • Registry Sektionen welche im Normalen Modus ('Machine') mit dem Modifier '/AllNtUserDats' aufgerufen werden, dürfen jetzt in der openkey Anweisung den Root 'HKCU' bzw. 'HKEY_CURRENT_USER' enthalten. Dies ermöglicht es, dieselbe Registry Sektion in den unterschiedlichen Modi auszuführen.

  • Winbatch Sektionen mit /RunAsLoggedOnUser
    der opsi-script läuft auch wenn er über das Loginevent gestartet wird im SYSTEM Kontext und nicht im Kontext des users, der sich gerade eingeloggt hat. Um einen Prozess im Kontext dieses users zu starten, kann eine winbatch Sektion mit der Option /RunAsLoggedOnUser verwendet werden.

  • Vermeidung unnötiger Läufe:
    Mit den Befehl saveVersionToProfile kann im aktuelle Profil hinterlegt werden, dass das userLoginscript zu diesem Produkt in dieser Version gelaufen ist. Mit der Stringfunktion readVersionFromProfile bzw. der boolschen Funktion scriptWasExecutedBefore kann überprüft werden, ob das userLoginScript zu diesem Produkt in dieser Version zuvor schon einmal gelaufen ist und eine erneute Ausführung unnötig ist. Dazu liest diese Funktion zunächst einen evtl. vorhandenen Versionsstempel vom Profil ein (wie das mit readVersionFromProfile möglich ist) und vergleicht diesen mit der aktuell laufenden Version. Aus dem Vergleich ergibt sich der Rückgabewert (wahr/falsch). Danach werden noch die aktuellen Werte in das Profil zurückgeschrieben (wie das mit saveVersionToProfile möglich ist). Somit benötigen Sie nur diese scriptWasExecutedBefore Funktion in einer if Anweisung, um zu prüfen ob das Script schon mal gelaufen ist.
    Weiterhin liefert die Stringlistenfunktion getProductMap eine Infomap, aus der entnommen werden kann, ob das aktuelle Produkt installiert oder deinstalliert usw. ist.

  • Jede Art von ExitWindows Kommando wird ignoriert.

  • Logging
    Die Logs von userLoginScripten werden geschrieben nach:
    c:\opsi.org\log\<login user name>_login.log
    Diese Logdateien werden auch an den opsi-server übertragen. Dabei wird eine neue Logdatei an eine existierende angehängt. Der opsi-server sorgt dafür, dass diese Dateien in der Größe beschränkt bleiben (max. 5 MB). Auf dem opsi server liegen diese logs unter /var/log/opsi/userlogin/<clientid>.log
    Im opsi Managementinterface (opsi-configed) werden diese Logs in einem zusätzliche Untertab 'userlogin' in dem Tab 'Logdateien' angezeigt.

Beispiele von userLoginScripten

Zunächst zwei Beispiele die so aufgebaut sind, wie sie auch in Domain Loginscripten eingesetzt werden könnten.

Ein sehr einfaches allgemeines Beispiel:

[Actions]
requiredWinstVersion >= "4.11.3.2"
Message "Example Profile Patch ...."

Files_profile_copy
Registry_currentuser_set
Patches_profile_ini "%userprofiledir%\opsi-script-test.ini"

[Files_profile_copy]
copy "%Scriptpath%\profiles\*.*" "%CurrentAppdataDir%\ACME"

[Registry_currentuser_set]
openkey [HKCU\Software\ACME]
set "show_greeting_window" = "no"

[Patches_profile_ini]
add [secdummy] dummy1=add1

Ein Beispiel zur Firefoxkonfiguration:

[Actions]
requiredWinstVersion >= "4.11.3.2"
Message "Firefox Profile Patch ...."

DefVar $akt_profile_ini$
DefVar $rel_prefs_path$

comment "check for existing profile ..."
Set $akt_profile_ini$ = "%CurrentAppdataDir%\Mozilla\Firefox\profiles.ini"
if FileExists($akt_profile_ini$)
	Set $rel_prefs_path$ = GetValueFromInifile($akt_profile_ini$,"Profile0","Path","")
	if FileExists("%CurrentAppdataDir%\Mozilla\Firefox\\"+$rel_prefs_path$)
		comment "We found the profile and will now patch it ....."
	endif
else
	comment "no firefox profile found for user"
endif

Als nächstes zeigen wir ein Beispiel welches das erste erweitert um die Möglichkeit Dinge aus dem Profil auch wieder zu entfernen. Je nachdem ob das Produkt auf dem Rechner installiert oder deinstalliert wird, wird ein anderer Scriptteil ausgeführt:

[Actions]
requiredWinstVersion >= "4.11.3.2"
Message "Example Profile Patch ...."

if getValue("installationstate", getProductMap) = "installed"
	comment "Product is installed"
	Files_profile_copy
	Registry_currentuser_set
	Patches_profile_ini "%userprofiledir%\opsi-script-test.ini"
endif

if getValue("lastactionrequest", getProductMap) = "uninstall"
	comment "Product was uninstalled"
	Files_profile_del
	Registry_currentuser_del
endif

[Files_profile_copy]
copy "%Scriptpath%\profiles\*.*" "%CurrentAppdataDir%\ACME"

[Registry_currentuser_set]
openkey [HKCU\Software\ACME]
set "show_greeting_window" = "no"

[Files_profile_del]
del -s -f "%CurrentAppdataDir%\ACME"
del "%userprofiledir%\opsi-script-test.ini"

[Patches_profile_ini]
add [secdummy] dummy1=add1

[Registry_currentuser_del]
deletekey [HKCU\Software\ACME]

Nun ein Beispiel, welches das Setup Skript (setup32.opsiscript und delsub32.opsiscript) nutzt, um unnötige Verdopplung des Codes zu vermeiden:

setup32.opsiscript:

[Actions]
requiredWinstVersion >= "4.11.3.2"

DefVar $MsiId$
DefVar $UninstallProgram$
DefVar $ProductId$
DefVar $InstallDir$

; ----------------------------------------------------------------
; - Please edit the following values                             -
; ----------------------------------------------------------------
Set $ProductId$       = "ACME"
Set $InstallDir$      = "%ProgramFiles32Dir%\ACME"
; ----------------------------------------------------------------
if GetScriptMode = "Machine"
	comment "Show product picture"
	ShowBitmap "%ScriptPath%\\" + $ProductId$ + ".png" $ProductId$

	if FileExists("%ScriptPath%\delsub32.opsiscript")
		comment "Start uninstall sub section"
		Sub "%ScriptPath%\delsub32.opsiscript"
	endif

	Message "Installing " + $ProductId$ + " ..."

	comment "Start setup program"
	Winbatch_install

	comment "Patch the local Profiles ..."
	Registry_currentuser_set /AllNtUserDats
	Files_profile_copy /AllNtUserProfiles
	Patches_profile_ini "%userprofiledir%\opsi-script-test.ini" /AllNtUserProfiles
endif

if GetScriptMode = "Login"
	comment "login part"
	Files_profile_copy
	Registry_currentuser_set
	Patches_profile_ini "%userprofiledir%\opsi-script-test.ini"
endif


[Winbatch_install]
"%ScriptPath%\setup.exe" /sp- /silent /norestart

[Files_profile_copy]
copy "%Scriptpath%\profiles\*.*" "%CurrentProfileDir%\Appdata\ACME"

[Registry_currentuser_set]
openkey [HKCU\Software\ACME]
set "show_greeting_window" = "no"

[Patches_profile_ini]
add [secdummy] dummy1=add1

delsub32.opsiscript:

Message "Uninstalling " + $ProductId$ + " ..."

if GetScriptMode = "Machine"
	comment "The machine part ..."
	Set $UninstallProgram$ = $InstallDir$ + "\uninstall.exe"
	if FileExists($UninstallProgram$)
		comment "Uninstall program found, starting uninstall"
		Winbatch_uninstall
	endif
	; does also work since 4.11.2.1
	Registry_currentuser_del /AllNtUserDats
	Files_profile_del /AllNtUserProfiles
endif

if GetScriptMode = "Login"
	comment "The profile part ..."
	Files_profile_del
	Registry_currentuser_del
endif

[Winbatch_uninstall]
"$UninstallProgram$" /silent /norestart

[Files_profile_del]
del -s -f "%CurrentAppdataDir%\ACME"
del "%userprofiledir%\opsi-script-test.ini"

[Registry_currentuser_del]
deletekey [HKCU\Software\ACME]

Nun ein Beispiel, welches eine Variante des vorherigen Beispiels ist. Dabei wird der code durch die Verwendung der neuen primären Sektion ProfileActions vereinfacht und das Script ist sowohl als Installationsscript als auch als 'userLoginScript' verwendbar.

[Actions]
requiredWinstVersion >= "4.11.3.2"

DefVar $ProductId$
DefVar $InstallDir$

Set $ProductId$       = "ACME"
Set $InstallDir$      = "%ProgramFiles32Dir%\ACME"

comment "Show product picture"
ShowBitmap "%ScriptPath%\\" + $ProductId$ + ".png" $ProductId$

Message "Installing " + $ProductId$ + " ..."

comment "Start setup program"
Winbatch_install

comment "Patch the local Profiles ..."
ProfileActions

[ProfileActions]
comment "login part"
Files_profile_copy
Registry_currentuser_set
Patches_profile_ini "%userprofiledir%\opsi-script-test.ini"

[Winbatch_install]
"%ScriptPath%\setup.exe" /sp- /silent /norestart

[Files_profile_copy]
copy "%Scriptpath%\profiles\*.*" "%CurrentProfileDir%\Appdata\ACME"

[Registry_currentuser_set]
openkey [HKCU\Software\ACME]
set "show_greeting_window" = "no"

[Patches_profile_ini]
add [secdummy] dummy1=add1

Nun eine Variante, welche sich im Profil merkt, ob das Skript für dieses Produkt in dieser Version und diesen User schon mal ausgeführt wurde. Eine Zeile mit den Produkt-Informationen wird in die Datei %AppData%\.opsi.org\userLoginScripts.ini geschrieben.

[Actions]
requiredWinstVersion >= "4.11.3.2"
Message "Example Profile Patch ...."

comment "Did we run this script before ? - and set version stamp in profile"
if not (scriptWasExecutedBefore)
	comment "loginscript was not run yet "
	Files_profile_copy
	Registry_currentuser_set
	Patches_profile_ini "%userprofiledir%\opsi-script-test.ini"
endif

[Files_profile_copy]
copy "%Scriptpath%\profiles\*.*" "%CurrentAppdataDir%\ACME"

[Registry_currentuser_set]
openkey [HKCU\Software\ACME]
set "show_greeting_window" = "no"

[Patches_profile_ini]
add [secdummy] dummy1=add1

Konfiguration

Um die 'User Profile Management' Erweiterung zu nutzen, muss in der Konfiguration des opsiclientd das Loginevent aktiviert werden. Für dieses Event wird (wenn der entsprechend aktuelle opsi-client-agent auf dem Client installiert ist) der opsi-script mit dem ergänzenden Parameter '/allloginscripts' oder '/loginscripts' gestartet.

  • /allloginscripts bedeutet, dass bei einem Login alle Loginscripts die dem Server bekannt sind ausgeführt werden, unabhängig ob das entsprechende Produkt dem Client bekannt ist (also installiert ist oder war) oder nicht.

  • /loginscripts bedeutet, das bei einem Login nur die Loginscripts auf einem Client ausgeführt werden, bei denen das entsprechende Produkt dem Client bekannt ist, also installiert ist oder war. (Technisch: bei denen es für diesen Client ein productOnClient Objekt gibt mit:
    (installationStatus= installed)
    or actionResult = successful) and (lastAction = uninstall).
    Loginscripts von Produkten, die der Client noch nie gesehen hat, werden nicht ausgeführt.
    Dies ist der Default.

Einen Schalter zur Aktivierung des Loginevents können Sie auf der Kommandozeile wie folgt einrichten: (meist will man zum Test nur einzelne Clients aktivieren, daher serverseitig hier der Wert 'false')

opsi-admin -d method config_createBool opsiclientd.event_user_login.active "user_login active" false

Als weiterer opsi-script Parameter kann zusätzlich auch noch der Parameter '/silent' verwendet werden, welcher die Anzeige des opsi-script Fensters unterbindet.
Dies ist der Default.

opsi-admin -d method config_createUnicode opsiclientd.event_user_login.action_processor_command "user_login action_processor" "%action_processor.command% /sessionid %service_session% /loginscripts /silent" "%action_processor.command% /sessionid %service_session% /loginscripts /silent"

Die so eingerichteten Einstellungen können Sie im opsi Managementinterface im Tab 'Hostparameter' Server- oder Client-spezifisch modifizieren.

Notification

Wenn Sie (wie oben beschrieben) das Loginevent aktiviert haben, so sehen Sie nach jedem Login den user_login_notifier:

User Login Notifier
Abbildung 5. User Login Notifier