The Copyright of this manual is held by uib gmbh in Mainz, Germany.

This manual is published under the creative commons license
'Attribution - ShareAlike' (by-sa).

CC by sa

A description of the license can be found here:
https://creativecommons.org/licenses/by-sa/3.0/

The legally binding text of the license can be found here:
https://creativecommons.org/licenses/by-sa/3.0/legalcode

Most parts of the opsi software is open source.
Not open source are the parts of the source code which contain new extensions, that are still under cofunding, which have not been paid off yet. See also: opsi cofunding projects

All of the open source code is published under the AGPLv3.

agplv3

The legally binding text of the AGPLv3 license can be found here: http://www.gnu.org/licenses/agpl-3.0-standalone.html

Information about the AGPL: http://www.gnu.org/licenses/agpl-3.0.en.html

For licenses to use opsi in the context of closed source software, please contact uib gmbh.

The names 'opsi', 'opsi.org', 'open pc server integration' and the opsi logo are registered trademarks of uib gmbh.

2. Introduction

The open source program opsi-script (former at windows 'opsi-winst') serves in the context of opsi – open pc server integration (cf. www.opsi.org) – as the central function for initiating and performing the automatic software installation. It may also be used stand alone as a tool for setup programs for any piece of software.

opsi-script is basically an interpreter for a specific, rather simple script language which can be used to express all relevant elements of a software installation.

A software installation that is described by a opsi-script script and performed by executing the script has several advantages compared with installations that are managed by a group of shell commands (e. g. copy etc.):

  • opsi-script can log very thoroughly all operations of the installation process. The support team can check the log files, and then easily detect when errors occurred or other problematic circumstances unfold.

  • Copy actions can be configured with a great variety of options if existing files should be overwritten

  • Especially, it may be configured to copy files depending on their internal version.

  • There are different modes to write to the Windows registry:

    • overwrite existing values

    • write only when no value exists

    • append a value to an existing value.

  • The Windows registry can be patched for all users which exist on a work station (including the default user, which is used as prototype for further users).

  • There is a sophisticated syntax for an integrated patching of XML configuration files.

3. opsi-script reference card (4.12.5.3)

For Windows [W], Linux [L] and MacOS [M]

3.1. Global text constants

3.1.1. System directories

System directories [W]:

%ProgramFilesDir%: 'c:\program files'

%ProgramFiles32Dir%: 'c:\Program Files (x86)' //since 4.10.8

%ProgramFiles64Dir%: 'c:\program files' //since 4.10.8

%ProgramFilesSysnativeDir% : 'c:\program files' //since 4.10.8

%Systemroot% : 'c:\windows'

%System% : 'c:\windows\system32'

%Systemdrive% : 'c:'

%ProfileDir% :
NT5: 'c:\Documents and Settings'
NT6: 'C:\users\'

3.1.2. Common (AllUsers) directories [W]:

%AllUsersProfileDir% or %CommonProfileDir% :
NT5: 'c:\Documents and Settings\All Users'
NT6: 'C:\Users\Public'

%CommonStartMenuPath% or %CommonStartmenuDir% :
NT5: 'c:\Documents and Settings\All Users\Startmenu'
NT6: 'C:\ProgramData\Microsoft\Windows\Start Menu'

%CommonAppdataDir% :
NT5: 'c:\Documents and Settings\All Users\Application Data'
NT6: 'C:\ProgramData'

%CommonDesktopDir%
NT5: 'c:\Documents and Settings\All Users\Desktop'
NT6: 'C:\Users\Public\Desktop'

%CommonStartupDir%
NT5: 'c:\Documents and Settings\All Users\Autostart'
NT6: 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp'

%CommonProgramsDir%

3.1.3. Default User directories [W]:

%DefaultUserProfileDir% //since 4.11.1.1

3.1.4. Current user directories [W]:

User is the logged in user or given by /usercontext.

%AppdataDir% or %CurrentAppdataDir% : //since 4.10.8.13
NT5: 'c:\Documents and Settings\%USERNAME%\Application Data' NT6: 'c:\users\%USERNAME%\Appdata\Roaming'

%CurrentStartmenuDir% //since 4.10.8.13

%CurrentDesktopDir% //since 4.10.8.13

%CurrentStartupDir% //since 4.10.8.13

%CurrentProgramsDir% //since 4.10.8.13

%CurrentSendToDir% //since 4.10.8.13

%CurrentProfileDir% //since 4.11.2.1

3.1.5. /AllUserProfiles directory constants [W/L/M]:

%UserProfileDir%
or
%CurrentProfileDir% // since 4.11.2.1
NT5: 'c:\Documents and Settings\%USERNAME%'
NT6: 'c:\users\%USERNAME%'

3.1.6. opsi-script Path and Directories [W/L/M]:

%ScriptPath% or %ScriptDir%

%RealScriptPath% (since 4.12.4.21)

%ScriptDrive%

%OpsiscriptDir% (since 4.12.3.6), %WinstDir%

%OpsiscriptVersion% (since 4.12.3.6), %WinstVersion% (since 4.10.8.3)

%opsiscriptProcname% (since 4.12.4.35)

%Logfile%

%opsiScriptHelperPath% %ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib // since 4.11.3.2

%opsiTmpDir% : c:\opsi.org\tmp // since 4.11.4.3

%opsiUserTmpDir% : c:\opsi.org\usertmp // since 4.12.4.37

%opsiLogDir% : c:\opsi.org\log // since 4.11.4.3

%opsidata% : c:\opsi.org\data // since 4.12.0.12

%opsiapplog% : c:\opsi.org\applog // since 4.12.0.12

3.1.7. Network informations [W/L/M]:

%Host% : value of environment variable HOST.

%PCName%: value of environment variable PCNAME, or if absent of COMPUTERNAME.

%Username% : Name of actual user.

%IPName% : The dns name of the pc. Usually identical with the netbios name and therefore with %PCName% besides that the netbios names uses to be uppercase.

%IPAddress% : may be the IP-Address of the machine. Use funktion GetMyIpByTarget() instead.
see also : GetMyIpByTarget

3.1.8. Service Data [W/L/M]

%HostID% : FQDN of the client in opsi service context, otherwise the computer name

%FQDN% : FQDN in network context

%opsiserviceURL%

%opsiServer%

%opsiDepotId% //since 4.11.4

%opsiserviceUser% FQDN used for the connection to the opsi-config-server

%opsiserviceClientId% : command line option /clientid

%opsiservicePassword%

%installingProdName%: productid //since 4.10.8

%installingProdVersion%: product version //since 4.10.8

%installingProduct% : productid (deprecated)

3.1.9. Functions to handle constants [W/L/M]

replaceOpsiConstants(<string list>`) : stringlist` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_list

replaceOpsiConstants(<string>`) : string` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_string

3.2. In Primary Sections

3.2.1. Kinds of Primary Sections [W/L/M]:

[Initial]

[Actions]

[sub<identifier>`]`

sub <file name>

[ProfileActions] [W]

3.2.2. opsi-script control [W/L/M]:

encoding=<encoding> // (default is system encoding) since 4.11.4.2 see also : encoding

LogLevel (deprecated) see also : Specification of Logging Level [W/L/M]

SetLogLevel = <number> or SetLogLevel = <string> // (default=6) see also : SetLogLevel

SetLogLevel = 7
SetLogLevel = "7"

ExitOnError = <boolean value> // (default=false) see also : ExitOnError

ScriptErrorMessages = <boolean value> // (default=true) see also : ScriptErrorMessages

FatalOnSyntaxError = <boolean value> // (default=true) since 4.11.3.2 see also : FatalOnSyntaxError

FatalOnRuntimeError = <boolean value> // (default=false) since 4.11.3.2 see also : FatalOnRuntimeError

AutoActivityDisplay = <boolean value> // (default=false); if true shows a marquee (endless) progressbar while winbatch/dosbatch sections are . //since 4.11.4.7 see also : AutoActivityDisplay see also : Central configuration via opsi Configs

forceLogInAppendMode = <boolean value> // (default=false); if true, log will be send in append mode . //since 4.12.3.6 see also : forceLogInAppendMode

Message <string> or Message = <const string> see also : Message

ShowMessageFile <string> see also : ShowMessageFile

ShowBitMap [<file name>] [<sub title>] see also : ShowBitMap

comment <string> or comment = <const string> see also : comment

LogError <string> or LogError = <const string> see also : LogError

LogWarning <string> or LogWarning = <const string> see also : LogWarning

includelog <file name> <tail size> //since 4.11.2.1 [W/L/M] see also : includelog

includelog <file name> <tail size> [<encoding>] //since 4.11.4.1 [W/L/M] see also : includelog

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

SetConfidential <secret string> //since 4.11.3.5 [W/L/M] see also : SetConfidential

asConfidential( <secret string expression> ) : string //since 4.12.0.16 [W/L/M] see also : asConfidential_str

asConfidential( <secret stringlist expression> ) : stringlist //since 4.12.4.15 [W/L/M] see also : asConfidential_list

Pause <string> or Pause = <const string> see also : Pause

Stop <string> or stop = <const string> see also : Stop

include_insert <file name> // since 4.11.3 see also : include_insert

include_append <file name> // since 4.11.3 see also : include_append

NormalizeWinst // (set normal window state) since 4.11.3 see also : NormalizeWinst

IconizeWinst // (set minimized window state) see also : IconizeWinst

MaximizeWinst // (set maximized window state) // since 4.11.5.1 see also : MaximizeWinst

RestoreWinst // (restore last window state) see also : RestoreWinst

SetSkinDirectory <path to skin.ini> // since 4.11.3.5 see also : SetSkinDirectory

runningInWanMode : boolean //since 4.12.4.17 [W/L/M] see also : runningInWanMode

reloadProductList //since 4.12.6.1 [W/L/M] see also : reloadProductList

3.2.3. Variables [W/L/M]:

Strings

DefVar <variable name>
; since 4.12.4.32 also possible:
DefVar <variable name> [= <inital value>]

Set <variable name> = <value>

Stringlists

DefstringList <variable name> ; since 4.12.4.32 also possible:
DefstringList <variable name> [= <inital value>]

3.2.4. Functions

String functions
Important

GetOS // 'Linux' or 'Windows_NT' [W/L/M] see also : GetOS

getLinuxDistroType // 'debian' or 'redhat' or 'suse' (see getLinuxVersionMap) [L] see also : getLinuxDistroType

GetMsVersionInfo //Windows Version Information [W] see also : GetMsVersionInfo

GetSystemType //OS Architecture ("64 Bit System" or "x86 System") [W/L/M]
see also : GetSystemType

getOSArchitecture // OS Architecture (x86_32 / x86_64/ arm_64) //since 4.12.4.17 [W/L/M]
see also : getOSArchitecture

getRegistryValue(<keystr>, <varstr> ) : string //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : getRegistryValue

GetRegistrystringvalue (`"[key] var")` [W] see also : GetRegistrystringvalue

GetRegistryStringValue32 (`"[key] var")` //since 4.10.8 [W] see also : GetRegistryStringValue32

GetRegistryStringValue64 (`"[key] var")` //since 4.10.8 [W] see also : GetRegistryStringValue64

GetRegistryStringValueSysNative (`"[key] var")` //since 4.10.8 [W] see also : GetRegistryStringValueSysNative

GetValueFromInifile (<file path>, <section>, <key>, <default value>, OPTIONAL <encoding>`) : string` [W/L/M] see also : GetValueFromInifile

GetProductProperty (<PropertyName>, <DefaultValue> ) [W/L/M] see also : GetProductProperty

GetConfidentialProductProperty (<PropertyName>, <DefaultValue>`)` //since 4.11.5.2 [W/L/M] see also : GetConfidentialProductProperty

trim(<string>`)` [W/L/M] see also : trim

lower(<string>`)` [W/L/M] see also : lower

upper(<string>`)` [W/L/M] see also : upper

unquote(<string>,<quote-string>`)` //since 4.11.2.1 [W/L/M] see also : unquote

unquote2(<string>,<quote-string>`)` //since 4.11.5.2 [W/L/M] see also : unquote2

stringReplace(<string>, <oldPattern>, <newPattern>`)` //since 4.11.3 [W/L/M] see also : stringReplace

strLength(<string>`)` //since 4.11.3 [W/L/M] see also : strLength

strPos(<string>, <sub string>`)` //since 4.11.3 [W/L/M] see also : strPos

strPart(<string>, <start pos>, <number of chars>`)` //since 4.11.3 [W/L/M] see also : strPart

getValue(<key string>, <hash string list> ) [W/L/M] see also : getValue

getValueBySeparator(<key string>,<separator string>,<hash string list> ) //since 4.11.2.1 [W/L/M] see also : getValueBySeparator

setValueByKey(<key>, <value>, <targetlist> ) [W/L/M] see also : [setValueByKey]

getValueFromFile(<key string>, <file name>`)` //since 4.11.4.4 [W/L/M] see also : getValueFromFile

getValueFromFileBySeparator(<key string>,<separator string>,<file name>`)` //since 4.11.4.4 [W/L/M] see also : getValueFromFileBySeparator

getLastExitCode : string (exitcode) [W/L/M] see also : getLastExitCode

Special: License Management

DemandLicenseKey( poolId [, productId [,windowsSoftwareId]] )

set $mykey$ = DemandLicenseKey ("", "office2007")

see also : DemandLicenseKey

FreeLicense (`poolId [, productId [,windowsSoftwareId]])`

set $result$ = FreeLicense("", "office2007")

see also : FreeLicense

Special: Usercontext / loginscripts [W]:

GetUserSID(<Windows Username>`)` see also : GetUserSID

GetLoggedInUser //since 4.11.1.2 see also : GetLoggedInUser

GetUsercontext //since 4.11.1.2 see also : getLastExitCode

GetScriptMode possible values 'Machine','Login' //since 4.11.2.1 see also : GetUsercontext

saveVersionToProfile - save productversion-packageversion to local profile //since 4.11.2.1 see also : saveVersionToProfile

readVersionFromProfile : string - read productversion-packageversion from local profile //since 4.11.2.1 see also : readVersionFromProfile

scriptWasExecutedBefore : boolean - is true if saved and running productversion-packageversion are identical //since 4.11.2.1 see also : scriptWasExecutedBefore

Other

GetHostsName (<hostaddress> ) [W/L/M] see also : GetHostsName

GetHostsAddr (<hostname> ) [W/L/M] see also : GetHostsAddr

ExtractFilePath (<path>`)` [W/L/M] see also : ExtractFilePath

calculate(<arithmetic string expression>`)` // since 4.11.3.5 : knows: +-*/() [W/L/M] see also : calculate

DecStrToHexStr ( <decstring>, <hexlength>`)` [W/L/M] see also : DecStrToHexStr

HexStrToDecStr (<hexstring>`)` [W/L/M] see also : HexStrToDecStr

base64EncodeStr(<string>`)` [W/L/M] see also : base64EncodeStr

base64DecodeStr(<string>`)` [W/L/M] see also : base64DecodeStr

convert2Jsonstr(<string>`)` //since 4.10.8.3

RandomStr [W/L/M] see also : RandomStr

RandomStrWithParameters [W/L/M] see also : RandomStrWithParameters

RandomIntStr(<number str>`) : string` [W/L/M] see also : RandomIntStr

CompareDotSeparatedStrings(<string1>, <string2>`) : string` [W/L/M] see also : CompareDotSeparatedStrings_str

CompareDotSeparatedNumbers(<string1>, <string2>`) : string` [W/L/M] see also : CompareDotSeparatedNumbers_str

EnvVar (<environment variable>`)` [W/L/M] see also : EnvVar

ParamStr [W/L/M] see also : ParamStr

getDiffTimeSec (Time in seconds since last marktime) //since 4.11.3 [W/L/M] see also : getDiffTimeSec

SidToName(<well known sid>`)` //since 4.11.3: gives localized name of the sid [W] see also : SidToName

GetMyIpByTarget(<target ip addr>`) : string` //since 4.11.3.2 /4.11.6 [W/L/M] see also : GetMyIpByTarget

GetIpByName(<ip addr / ip name>`)` //since 4.11.3.2 [W/L/M] see also : GetIpByName

reencodestr(<str>, <from>, <to>`)` //since 4.11.4.2 [W/L/M] see also : reencodestr

strLoadTextFile ( <filename> ) //since 4.11.4.6 [W/L/M] see also : strLoadTextFile

strLoadTextFileWithEncoding ( <filename> , <encoding>`)` //since 4.11.4.6 [W/L/M] see also : strLoadTextFileWithEncoding

GetShortWinPathName(<longpath string>) //since 4.11.5.2 [W] see also : GetShortWinPathName

stringinput(< message str>,< boolstr confidential>`) : string` //since 4.12.1.2 [W/L/M] see also : stringinput

which(<command in path>`) : string` (command with path) //since 4.12.3.6 [W/L/M] see also : which

replaceOpsiConstants(<string>`) : string` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_string

ReadTOMLFile(<TOMLfilePath: String>`) : String` //since 4.12.5.0 [W/L/M] see also : ReadTOMLFile

GetTOMLAsString(<TOMLcontents: String>`) : String` //since 4.12.5.0 [W/L/M] see also : GetTOMLAsString

GetTOMLTableAsString(<TOMLcontents: String> , <table name : String>`) : String` //since 4.12.5.0 [W/L/M] see also : GetTOMLTableAsString

GetValueFromTOML(<TOMLcontents: String> , <keyPath: String> , <defaultValue: String>`) : String` //since 4.12.5.0 [W/L/M] see also : GetValueFromTOML

ModifyTOML(<TOMLcontents: String> , <command: String> , <keyPath: String> , <value: String>`) : String` //since 4.12.5.0 [W/L/M] see also : ModifyTOML

DeleteTableFromTOML(<TOMLcontents: String> , <tablePath: String>`) : String` //since 4.12.5 [W/L/M] see also : DeleteTableFromTOML

ConvertTOMLtoJSON(<TOMLcontents: String>`) : String` //since 4.12.5.0 [W/L/M] see also : ConvertTOMLtoJSON

Deprecated

GetNtVersion Deprecated - please use GetMsVersionInfo [W] see also : GetMsVersionInfo

IniVar (<key>`)` : (deprecated; use GetProductProperty) [W] see also : GetProductProperty

SubstringBefore (<string1>, <string2>`)` (deprecated; use splitString / takestring) [W/L/M] see also : splitString

String list functions
Important

splitString (<string1>, <string2>`)` [W/L/M]

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

see also : splitString

splitStringOnWhiteSpace (<string>`)` [W/L/M] see also : splitStringOnWhiteSpace

loadTextFile (<file name>`)` [W/L/M] see also : loadTextFile

loadUnicodeTextFile (<file name>`)` [W] see also : loadUnicodeTextFile

loadTextFileWithEncoding( <file name> , <encoding>`)` //since 4.11.5 [W/L/M] see also : loadTextFileWithEncoding

composeString (<string list>, <Link>`)` [W/L/M] see also : composeString

takeString (<index>, <list>`)` [W/L/M] see also : takeString

setStringInListAtIndex(<newstring>,<list>,<indexstr>`) : stringlist` //since 4.11.6 [W/L/M] see also : setStringInListAtIndex

takeFirstStringContaining(<list>,<search string>`)` [W/L/M] see also : takeFirstStringContaining

getOutStreamFromSection (<dos section name>`)` [W/L/M]

set $list$= getOutStreamFromSection ('DosInAnIcon_try')

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

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

see also : shellCall_list

getReturnListFromSection (<xml section name>`)` [W/L/M] see also : getReturnListFromSection

getListContaining(<list>,<search string>`)` [W/L/M] see also : getListContaining

getListContainingList(<list1>,<list2>`)` //since 4.11.3.7 [W/L/M] see also : getListContainingList

count (<list>`)` [W/L/M] see also : count

emptylist (<list>`)` //since 4.11.3.7 [W/L/M] see also : emptylist

for %<identifier>`% in` <list> do <one statement | sub section> [W/L/M]

for %s% in $list1$ do sub_test_string

see also : forInDo

GetProcessList //since 4.11.1.2; gives list of exename;pid;dom/user [W/L/M] see also : GetProcessList

getProductPropertyList(<propname>,<default value>`)` //since 4.11.3 [W/L/M] see also : getProductPropertyList

getRegistryKeyList32(<regkey>`)` //since 4.11.3 [W] see also : getRegistryKeyList32

getRegistryKeyList64(<regkey>`)` //since 4.11.3 [W] see also : getRegistryKeyList64

getRegistryKeyListSysnative(<regkey>`)` //since 4.11.3 [W] see also : getRegistryKeyListSysnative

getRegistryKeyList(<regkey>, <access str>`)` //since 4.12.5.0 [W] see also : getRegistryKeyList

getRegistryVarList32(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarList32

getRegistryVarList64(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarList64

getRegistryVarListSysnative(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarListSysnative

getRegistryVarList(<regkey>, <access str>`)` //since 4.12.5.0 [W] see also : getRegistryVarList

getProfilesDirList //since 4.11.3.2 [W/L/M] see also : getProfilesDirList

listFiles (<Path>, <Searchmask> , <SearchSubDirectories>, <[Redirection]>`) : stringlist` //since 4.12.3 [W/L/M]

Set $Filelist$ = listFiles("C:\windows\system32","*.ico;*.dll","False","64bit")

see also : listFiles

replaceOpsiConstants(<string list>`) : stringlist` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_list

Infomaps

GetLocaleInfoMap [W] see also : GetLocaleInfoMap

GetMSVersionMap [W] see also : GetMSVersionMap

getLinuxVersionMap //since 4.11.4 [L]
keys are (example):

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

see also : getLinuxVersionMap

getFileInfoMap( <file name> ) [W] see also : getFileInfoMap

getProductMap // since 4.11.2.4 [W/L/M]
keys are: id, name, description, advice, productversion, packageversion, priority, installationstate, lastactionrequest, lastactionresult, installedversion, installedpackage, installedmodificationtime,actionrequest
see also : getProductMap

getRegistryVarMap32(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarMap32

getRegistryVarMap64(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarMap64

getRegistryVarMapSysnative(<regkey>`)` //since 4.11.3 [W] see also : getRegistryVarMapSysnative

getRegistryVarMap(<regkey>, <access str>`)` //since 4.12.5.0 [W] see also : getRegistryVarMap

getHWBiosInfoMap //since 4.11.4 [W/L/M] see also : getHWBiosInfoMap

editmap(< strlist>`) : stringlist` //since 4.12.1.2 [W/L/M] see also : editmap

Other

createStringList (<string0>, <string1> ,…​ ) [W/L/M]

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

see also : createStringList

reverse (<list>`)` [W/L/M] see also : reverse

getSectionNames(<ini-file>`)` [W/L/M] see also : getSectionNames

retrieveSection (<section name>`)` [W/L/M] see also : retrieveSection

getSubList (<start index> : <end index>, <list>`)` [W/L/M] see also : getSubList

getSubListByMatch (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByMatch_sl

getSubListByMatch (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByMatch_ll

getSubListByContaining ( <search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByContaining_sl

getSubListByContaining (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByContaining_ll

getSubListByKey (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByKey_sl

getSubListByKey (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByKey_ll

getKeyList (<list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getKeyList

addtolist(<list>,<string>`)` //since 4.10.8 [W/L/M] see also : addtolist

addListToList(<dest list>,<src list>`)` //since 4.10.8 [W/L/M] see also : addListToList

reencodestrlist(<list>, <from>, <to>`)` //since 4.11.4.2 [W/L/M] see also : reencodestrlist

removeFromListByContaining(<search string>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M] see also : removeFromListByContaining_str

removeFromListByContaining(<search list>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M] see also : removeFromListByContaining_list

removeFromListByMatch(<searchstring>,<target list>`) : stringlist` //since 4.11.6 [W/L/M] see also : removeFromListByMatch

LoadTOMLFile(<TOMLfilePath: String>`) : StringList` //since 4.12.5 [W/L/M] see also : LoadTOMLFile

GetTOMLAsStringList(<TOMLcontents: String>`) : StringList` //since 4.12.5 [W/L/M] see also : GetTOMLAsStringList

GetTOMLKeys(<TOMLcontents: String>`) : StringList` //since 4.12.5 [W/L/M] see also : GetTOMLKeys

GetTOMLTableNames(<TOMLcontents: String>`) : StringList` //since 4.12.5 [W/L/M] see also : GetTOMLTableNames

GetTOMLTable(<TOMLcontents: String> , <table name : String>`) : StringList` //since 4.12.5 [W/L/M] see also : GetTOMLTable

Boolean operators and functions

see also : Boolean Expressions

<string1> = <string2> [W/L/M]

<bool1> AND <bool2> [W/L/M]

<bool1> OR <bool2> [W/L/M]

NOT(<bool3>) [W/L/M]

FileExists (<file name>`)` [W/L/M] see also : FileExists

FileExists32 (<file name>`)` [W] see also : FileExists

FileExists64 (<file name>`)` [W] see also : FileExists

FileExistsSysNative (<file name>`)` [W] see also : FileExists

DirectoryExists (<folder path> [,<access str>]) : boolean //since 4.12.1 [W/L/M]
'sysnative' is the default for <access str>. Otherwise, it can be '32bit', '64bit' or 'sysnative' see also : DirectoryExists

FileOrFolderExists (<file or folder path> [,<access str>]) : boolean [W/L/M] 'sysnative' is the default for <access str>. Otherwise, it can be '32bit', '64bit' or 'sysnative' see also : FileOrFolderExists

fileIsSymlink (<file name>`)` // since 4.12.4.21 [W/L/M]
see also : fileIsSymlink

LineExistsIn (<string>, <file name>`)` [W/L/M] see also : LineExistsIn

LineBeginning_ExistsIn (<string>, <file name>`)` [W/L/M] see also : LineBeginning_ExistsIn

LineContaining_ExistsIn( <string>, <file name> ) //since 4.11.4.10: true: if a in <file name> contains <string> [W/L/M] see also : LineContaining_ExistsIn

XMLAddNamespace(<XMLfilename>, <XMLelementname>, <XMLnamespace>`)` [W] see also : XMLAddNamespace

XMLRemoveNamespace(<XMLfilename>, <XMLelementname>, <XMLnamespace>`)` [W] see also : XMLRemoveNamespace

HasMinimumSpace (<drive letter>, <capacity>`)` [W] see also : HasMinimumSpace

Example:

if not (HasMinimumSpace ("%SYSTEMDRIVE%", "500 MB"))
   LogError "Required free space of 500 MB not available on %SYSTEMDRIVE%"
   isFatalError
endif

opsiLicenseManagementEnabled [W/L/M] see also : opsiLicenseManagementEnabled

runningAsAdmin //since 4.11.1.1 [W/L/M] see also : runningAsAdmin

isLoginScript //since 4.11.2.1 [W] see also : isLoginScript

contains(<str>, <substr>`) : bool` //since 4.11.3: true if <substr> in <str> [W/L/M] see also : contains

isNumber(<str>`)` //since 4.11.3: true if <str> represents an integer [W/L/M] see also : isNumber

runningOnUefi //since 4.11.4.3: true: if the running OS was booted in UEFI mode [W] see also : runningOnUefi

runningInPE //since 4.12.0.13: true: if the running OS is a Windows PE [W/L/M] see also : runningInPE

runningInWAnMode //since 4.12.4.16: true: if opsiserver = localhost [W/L/M] see also : runningInWAnMode

isDriveReady(<drive letter>`)` //since 4.11.4.4: true: if the drive can be accessed [W] see also : isDriveReady

runningWithGui : bool` //since 4.12.3.6: true: if the running OS has a GUI (at Win+Mac always true)[M/L/W] see also : runningWithGui

saveTextFile(<list>, < filename>`)` //since 4.11.4.4: true: if list is succesfully written to file [W/L/M] see also : saveTextFile

saveTextFileWithEncoding(<list>, < filename>, <encoding>`) : bool` //since 4.11.6.4: true: if list is succesfully written to file [W/L/M] see also : saveTextFileWithEncoding

saveUnicodeTextFile(<list>, < filename>, <encoding>`) : bool` //since 4.12.4.13: true: if list is succesfully written to unicode file [W/L/M] see also : saveUnicodeTextFile

CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>`)` //since 4.11.5.2: [W/L/M] see also : CompareDotSeparatedNumbers_bool

CompareDotSeparatedStrings(<str1>,<relation str>,<str2>`)` //since 4.11.5.2: [W/L/M] see also : CompareDotSeparatedStrings_bool

RegKeyExists(<regkey>[,<access str>]) : bool //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : RegKeyExists

RegVarExists(<regkey>, <var str> ) : bool //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : RegVarExists

isPingReachable(<host>) : boolean //since 4.12.3.6 [W/L/M] see also : isPingReachable

isValidFQDN(<domain name>) : boolean //since 4.12.4.4 [W/L/M] see also : isValidFQDN

fileHasBom (<file name>`) : boolean` //since 4.12.4.17 [W/L/M] see also : fileHasBom

SaveToTOMLFile(<TOMLcontents: String> , <TOML file Path: String>`) : boolean` //since 4.12.5 [W/L/M] see also : SaveToTOMLFile

ConvertTOMLfileToJSONfile(<TOMLfilePath: String> , <JSONfilePath: String>`) : boolean` //since 4.12.5 [W/L/M] see also : ConvertTOMLfileToJSONfile

Misc functions

Killtask <process name> [W/L/M] see also : Killtask

requiredOpsiscriptVersion <relation operator> <version> //since 4.12.3.6 [W/L/M]

requiredOpsiscriptVersion >= "4.12.3.6"

requiredWinstVersion <relation operator> <version> [W/L/M]
outdatet - use requiredOpsiscriptVersion see also : requiredOpsiscriptVersion

UpdateEnvironment //since 4.11.5 [W]:
Subsequent calls of winbatch with the parameter /RunElevated will see the changed Environment (NT6 only). see also : UpdateEnvironment

Flow control

'if - elseif - else - endif' [W/L/M] see also : IfElseEndif

Syntax:

if <condition>
;statement(s)
[elseif <condition>
;statement(s)]
[else
;statement(s)]
endif

elseif //since 4.12.4.37

Example:

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

'for - to - do' Statement //since 4.11.5 [W/L/M] see also : ForToDo

for %<temporary string variable>% = <start string> to <end string> do <one statement>

Example:

for %s% = "1" to "5" do sub_iteration_test

'Switch / Case' Statement //since 4.11.5 [W/L/M]
ifdef::manual[see also : SwitchCase]
Can not be nested.
see also : [IfElseEndif]

Syntax:

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

Example:

set $ConstTest$ = "5"
Switch $ConstTest$
	Case "1"
		set $CompValue$ = "1"
	EndCase
	Case "2"
		set $CompValue$ = "2"
	EndCase
	DefaultCase
		set $CompValue$ = "notexisting"
	EndCase
EndSwitch

isFatalError [W/L/M] see also : isFatalError

isFatalError <string> //since 4.11.3.2 [W/L/M] see also : isFatalError

isSuccess //since 4.11.3.7 [W/L/M] see also : isSuccess

isSuspended //since 4.11.4.1 [W/L/M] see also : isSuspended

noUpdateScript //since 4.11.3.7 [W/L/M] see also : noUpdateScript

ExitWindows /Reboot [W/L/M] see also : Reboot

ExitWindows /ImmediateReboot [W/L/M] see also : ImmediateReboot

ExitWindows /ImmediateLogout [W] see also : ImmediateLogout

ExitWindows /ShutdownWanted [W] see also : ShutdownWanted

ExitWindows /RebootWanted (deprecated, acts like /Reboot) [W] see also : Reboot

sleepSeconds <Integer> or <string> : noresult [W/L/M] see also : sleepSeconds

ChangeDirectory <directory> //since 4.11.2.6 [W/L/M] see also : ChangeDirectory

3.3. Secondary Sections

3.3.1. Winbatch [W/L/M]

Function: execute programs via operating system API

[WinBatch<identifier>`]`

Modifier:

/LetThemGo

/WaitForProcessEnding "<program.exe>"

/TimeOutSeconds <seconds>

/WaitForWindowAppearing <window title> ('does not work with 64 Bit programs') [W]

/WaitForWindowVanish <window title> ('does not work with 64 Bit programs') [W]

/RunElevated // since 4.11.3: only at >= NT6 ; no network access [W]

/RunAsLoggedOnUser // since 4.11.3.5 ; works only inside 'userLoginScripts' [W]

/32Bit //since 4.11.3.5 [W]

/64Bit //since 4.11.3.5 [W]

/SysNative //since 4.11.3.5 [W]

3.3.2. DosBatch and DosInAnIcon (ShellBatch and ShellInAnIcon) [W/L/M]

Function: Execute section via cmd.exe [W] or bash [L/M]

[DosBatch<identifier>`]` <optional parameters> <winst <modifier>>

[DosInAnIcon<identifier>`]` <optional parameters> <winst <modifier>>

[ShellBatch<identifier>`]` <optional parameters> <winst <modifier>>

[ShellInAnIcon<identifier>`]` <optional parameters> <winst <modifier>>

Modifier: //since 4.11.1.1

/32Bit [W]

/64Bit [W]

/SysNative [W]

/showoutput [W/L/M] // since 4.11.4.7

/WaitForProcessEnding "<program.exe>" // since 4.12.4 [W/L/M]

/TimeOutSeconds <seconds> // since 4.12.4 [W/L/M]

/RunElevated // since 4.12.4: only at >= NT6 ; no network access [W]

The modifiers has to be seperated by 'winst' from the parameters.

DosInAnIcon_do_64bit_stuff winst /64Bit

Commands: see manual

3.3.3. ExecWith [W/L/M]

see also : ExecWith Sections

Function: Execute section via any interpreter

[ExecWith<identifier>`]` <path to interpreter>

Modifier:

/LetThemGo

/EscapeStrings

/32Bit //since 4.11.3.5 [W]

/64Bit //since 4.11.3.5 [W]

/SysNative //since 4.11.3.5 [W]

The modifiers has to be seperated by 'winst' from the parameters. The following example call the 64Bit version of the powershell.exe.

ExecWith_do_64bit_stuff "%System%\WindowsPowerShell\v1.0\powershell.exe" winst /64Bit

Commands: see manual

3.3.4. Files [W/L/M]

see also : Files

Function: File Operations

[Files<identifier>`]`

Modifier [W]:

/AllNTUserProfiles

/AllNTUserSendTo [W]

/32Bit //since 4.10.8 [W]

/64Bit //since 4.10.8 [W]

/SysNative //since 4.10.8 [W]

Commands:

checkTargetPath = <destination directory> [W/L/M]

copy [Options] <source file(s)> <destination directory> [W/L/M]

some options:

-s recursive [W/L/M]

-e empty Subdirectories

-V version control against targetdir [W]

-v version control against targetdir, %systemroot% and %system% (do not use it) [W]

-c continue without reboot even if it is needed [W]

-d date check [W]

-u update [W]

-x extract [W]

-w weak (do not overwrite protected files) [W]

-n no overwrite [W]

-r copy read only attribute [W]

-h follow symlinks [L] //since 4.11.6.14

delete [Options] <path[/mask]] // [W/L/M]

options:

-s recursive

-f force

r -del on reboot

c continue with out reboot

d [n] date

Example (do not forget the trailing Backslash):
delete -sf c:\delete_this_dir\

del [Options] <path[/mask]] //since 4.11.2.1 [W/L/M]

Works like delete but on
del -s -f c:\not-exists
if c:\not-exists not exists it do not search complete c:\ for not-exits

Example (you may forget the trailing Backslash):
del -sf c:\delete_this_dir

chmod <mode> <path> //since 4.11.4.1 [L]

hardlink <existing file> <new file> // since 4.11.5 [W/L/M]

symlink <existing file> <new file> // since 4.11.5 [W/L/M]
At Windows symlink is only available at NT6 and up.

rename <old filename> <new filename> // since 4.11.5 [W/L/M]

move <old filename> <new filename> // since 4.11.5 [W/L/M]

zipfile <source dir> <zip file> // since 4.12.1 [W/L/M]

unzipfile <zip file> <target dir> // since 4.12.1 [W/L/M]

3.3.5. Registry [W]

see also : Registry

Function: edit Registry

Standard method call:
[Registry<identifier>`]`
works with the specified section.

Alternative method call:
Registry loadUnicodeTextFile(<.reg file>`) /regedit`
import the specified <.reg file>.

Alternative method call (deprecated):
Registry loadUnicodeTextFile(<.addreg file>`) /addreg`
import the specified <.addreg file>.

Modifier:

/AllNTUserDats

/32Bit //since 4.10.8

/64Bit //since 4.10.8

/SysNative //since 4.10.8

Commands:

OpenKey <Key>

openkey [HKLM\Software\opsi.org]

Set <varname> = <registry type>:<value>

Add <varname> = <registry type>:<value>

Examples for registry types:

set "var1" = "my string"
set "var2" = REG_SZ:"my string"
set "var3" = REG_EXPAND_SZ:"%ProgramFiles%"
set "var4" = REG_DWORD:123	; Decimal
set "var5" = REG_DWORD:0x7b	; Hexadecimal
; REG_QWORD is supported since 4.12.6
set "var6" = REG_QWORD:59049772908	; Decimal
set "var7" = REG_QWORD:0xDBFA4076C	; Hexadecimal
set "var8" = REG_BINARY:00 01 02 0F 10
set "var9" = REG_MULTI_SZ:"A|BC|de"

Supp <varname> <list char> <supplement>

supp "Path" ; "C:\utils; %JAVABIN%"

GetMultiSZFromFile <varname> <file name>

SaveValueToFile <varname> <file name>

DeleteVar <varname>

DeleteKey <registry key> (does since 4.11.2.1 also work with /AllNTUserDats)

3.3.6. Patches [W/L/M]

see also : Patches

Function: edit Ini-files

[Patches<identifier>`]` <file name>

Modifier:

/AllNTUserProfiles //since 4.11.3 [W]

Commands:

add [<section name>`]` <variable1> = <value1>

set [<section name>`]<variable1> `= <value1>

addnew [<section name>`]<variable1> `= <value1>

change [<section name>`]<variable1> `= <value1>

del [<section name>`]` <variable1> = <value1>

del [<section name>`]` <variable1>

delsec [<section name>`]`

replace <variable1>`=<value1> <variable2>=`<value2>

3.3.7. PatchTextFile [W/L/M]

see also : PatchTextFile

Function: edit text files

[PatchTextFile<identifier>`]` <file name>

Modifier:

/AllNTUserProfiles //since 4.11.3.4 [W]

/encoding <encoding> //since 4.12.4.17 [W/L/M]

Commands:

Set_Mozilla_Pref (`"<preference type>", "<preference key>", "<preference value>")`
'preference type' takes any value.
Some examples for preference types: pref, user_pref, lock_pref or lockPref.

AddStringListElement_To_Mozilla_Pref (`"<preference type>", "<preference key>", "<add value>")`

Set_Netscape_User_Pref (`"<key>", "<value>")` ('deprecated')

AddstringListElement_To_Netscape_User_Pref ('deprecated')

FindLine <search string>

FindLine_StartingWith <search string>

FindLine_Containing <search string>

GoToTop

AdvanceLine [<number of lines>]

GoToBottom

DeleteTheLine

AddLine_ <line> or Add_Line_ <line>

InsertLine <line> or Insert_Line_ <line>

AppendLine <line> or Append_Line <line>

Append_File <file name>

Subtract_File <file name>

SaveToFile <file name>

Sorted

setKeyValueSeparator <separator char> //since 4.11.4.4 [W/L/M]

setValueByKey <keystr> <valuestr> //since 4.11.4.4 [W/L/M]

3.3.8. LinkFolder [W/L/M]

see also : LinkFolder

Function: Startmenue + Desktop Icons

[LinkFolder<identifier>`]`

Commands:

set_basefolder <system folder>

set_subfolder <folder path> (at Linux set always "")

set_link
  name:            <link name>
  target:          <path and name of the program>
  parameters:      [command line arguments]
  working_dir:     [working directory]
  icon_file:       [path and name of icon file, default=target]
  icon_index:      [number of icon in icon file, default=0] [W]
  shortcut:        [keyboard shortcut for calling the target] [W]
  link_categories: [list of categories] [L]
end_link

delete_element <link name>

delete_subfolder <folder path> [W]

The predefined virtual system folders which can be used are at Windows:
desktop, sendto, startmenu, startup, programs, desktopdirectory,
common_startmenu, common_programs, common_startup, common_desktopdirectory
and at Linux:
common_programs,common_startup,desktop, startup

Predefined link_categories for Linux:
AudioVideo, Audio, Video, Development, Education, Game, Graphics, Network, Office, Settings, System, Utility

Examples

set_basefolder common_desktopdirectory
set_subfolder ""
set_link
  name: opsi-winst
  target: "%ProgramFiles32Dir%\opsi.org\opsi-client-agent\opsi-winst\winst32.exe"
end_link
[LinkFolder_configed_lin]
set_basefolder common_programs
set_subfolder ""

set_link
  name: opsi-configed-Local
  target: java
  parameters: $parameter$
  icon_file: "$InstallDir$/opsi.png"
  link_categories: System;Utility;
end_link

The predefined virtual system folders:
desktop, sendto, startmenu, startup, programs, desktopdirectory
are pointing to the folders of the user that the script is running. If you use it in a userLoginScript with the opsi 'User Profile Management' extension these virtual folders point to the folder of the user that just had logged in.

'shortcut' defaults to empty. // since 4.11.6.7
shortcut may be a combination of ['shift','alt','ctrl'] (not case sensitiv) divided by ' ', '-','+' an a 'Key' or a 'Virtual Key Code'.
The 'Key' is a letter ('A' - 'Z') or a numeral ('0' - '9'). All other Keys must be given by there 'Virtual Key Code' identifier. To get these identifier (as well as the allowed combinations) just use the following helper program:
http://download.uib.de/opsi4.0/helper/showkeys.exe

3.3.9. OpsiServiceCall [W/L/M]

see also : OpsiServiceCall

Function: opsi-Service access

[OpsiServiceCall<identifier>`]`

Commands: see manual

3.3.10. PatchHosts [W/L/M]

see also : PatchHosts

Function: hosts-files bearbeiten

[PatchHosts<identifier>`]`

Commands:

setaddr <hostname> <IPaddress>

setname <IPaddress> <hostname>

setalias <hostname> <alias>

setalias <IPadresse> <alias>

delalias <hostname> <alias>

delalias <IPaddress> <alias>

delhost <hostname>

delhost <ipadresse>

setComment <ident> <comment>

3.3.11. XML2 Sections [W/L/M]

see also : XML2 Sections

Function: edit XML files
since 4.12.1.0

[XML2<identifier>`]`

Commands:

  • strictMode = (true/false) ; Default: false

  • openNode <xml2 path>
    Open the given path as actual node. If the path does not exist, it will be created.

  • SetAttribute <attr name> <attr value>
    At the actual node set <attr value> as value of <attr name>. If <attr name> does not exist, it will be created.

  • AddAttribute <attr name> <attr value>
    If the attribute <attr name> does not exist at the actual node, it will be created with <attr value> as value. If <attr name> already exists, nothing will be changed.

  • DeleteAttribute <attr name>
    If the attribute <attr name> exists at the actual node, it will be deleted.

  • addNewNode <node name>
    Create at the actual node a new sub node <node name> and make this new node to the actual node.

  • setNodeText <string>

  • DeleteNode <xml2 path>

  • gotoParentNode
    Make the parent node to the actual node.

  • rootNodeOnCreate = <node name> // since 4.12.4.27
    If the file does not exist, it will be created with <node name> as root node name.

  • setNodePair <keyNodeName> <keyNodeTextContent> <valueNodeName> <valueNodeTextContent> // since 4.12.4.28
    Creates a <dict> entry like it is used in the Apple info.plist files.

Some notes on the command parameters:

  • <xml2 path> strictMode =false:
    A line of xml node names without any attributes seprated by '` // '.
    Example: `node_level-1_number-1 // node_level-2_B color="green"

  • <xml2 path> strictMode =true:
    A line of xml node names with all existing attributes seprated by '` // '.
    Example: `node_level-1_number-1 // node_level-2_B color="green" count="65"

see also : Section 3.4.25

see also : XML2 Functions

3.3.12. XMLPatch [W]

see also : XMLPatch

Function: edit XML files
Deprecated: please use xml2 sections: Section 3.3.11
and xml2 functions: Section 3.4.25

[XMLPatch<identifier>`]`

Commands: see manual

3.3.13. ExecPython [W/L/M]

see also : ExecPython

Function: Execute section via python interpreter

[ExecPython<identifier>`]`

Commands: see manual

3.3.14. LdapSearch [WLM]

see also : LdapSearch

Function: read from LDAP

[LdapSearch<identifier>`]`

Commands: see manual

3.4. By Topic

3.4.1. Compare related functions [W/L/M]

CompareDotSeparatedStrings(<string1>, <string2>`) : string` [W/L/M] see also : CompareDotSeparatedStrings_str

CompareDotSeparatedStrings(<str1>,<relation str>,<str2>`) : bool` //since 4.11.5.2: [W/L/M] see also : CompareDotSeparatedStrings_bool

CompareDotSeparatedNumbers(<string1>, <string2>`) : string` [W/L/M] see also : CompareDotSeparatedNumbers_str

CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>`) : bool` //since 4.11.5.2: [W/L/M] see also : CompareDotSeparatedNumbers_bool

boolToString(<boolean expression>`)` : bool string (true/false) // since 4.12.0.0 [W/L/M] see also : boolToString

stringToBool(<string expression: true/false>`)` : boolean // since 4.12.0.0 [W/L/M] see also : stringToBool

3.4.2. Crypt / Hash related functions [W/L/M]

DecStrToHexStr ( <decstring>, <hexlength>`) : string` [W/L/M] see also : DecStrToHexStr

HexStrToDecStr (<hexstring>`) : string` [W/L/M] see also : HexStrToDecStr

base64EncodeStr(<string>`) : string` [W/L/M] see also : base64EncodeStr

base64DecodeStr(<string>`) : string` [W/L/M] see also : base64DecodeStr

RandomStr : string [W/L/M] see also : RandomStr

RandomIntStr(<number str>`) : string` [W/L/M] see also : RandomIntStr

encryptStringBlow(<keystring>,<datastring>`) : string` [W/L/M] see also : encryptStringBlow

decryptStringBlow(<keystring>,<datastring>`) : string` [W/L/M] see also : decryptStringBlow

md5sumFromFile(<path to file>`) : string` [W/L/M] see also : md5sumFromFile

hashFromFile(<FileName>, <Hashing Algorithm>`) : string` [W/L/M] //since 4.12.5 see also : hashFromFile

isCertInstalledInSystem(<label>`) : boolstring` [W/L/M] //since 4.12.4.37 see also : [isCertInstalledInSystem]

importCertToSystem(<filename>`) : noresult` [W/L/M] //since 4.12.4.37 see also : [importCertToSystem]

removeCertFromSystem(<label>`) : noresult` [W/L/M] //since 4.12.4.37 see also : [removeCertFromSystem]

listCertificatesFromSystem : stringlist` [W/L/M] //since 4.12.4.37 see also : [listCertificatesFromSystem]

3.4.3. Defined Functions and Libraries [W/L/M]

since 4.12.0.0

Definition

DefFunc <func name>([calltype parameter ptype][,[calltype parameter ptype]]) : ftype
<function body>
endfunc

Where:

  • DefFunc is the keyword used to start defining a local function.

  • '<func name>' is the freely choosen name of the function.

  • 'calltype' is the call type of the parameter [val | ref]. val='Call by Value', ref='Call by Reference'. Default: val

  • 'parameter' is the freely selected name of the call parameter which is available as a local variable within the function under the aforementioned name.

  • 'ptype' is the type of data of the parameter and either string or stringlist.

  • 'ftype' is the type of data of the function and either string ,stringlist or void. void declares that no result is returned.

  • '<function body>' is the body of the function which must conform to the opsi-script syntax.

  • endfunc is the keyword used to end defining a local function.

see also : localfunctions

importLib <string expr> ; import library // since 4.12.0.0
<string expr> : <file name>[.<file extension>][::<function name>]
If no '.<file extension>' is given .opsiscript is used as default.
If no '::<function name>' is given, all function from the given file will be imported.

<file name> is:

  • A complete path to an existing file. [W/L/M]

  • An existing file in %ScriptPath% [W/L/M]

  • A file in %opsiScriptHelperPath%\lib [W]
    Is equivalent to: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • An existing file in %ScriptPath%/../lib [W/L/M]

  • An existing file in %WinstDir%\lib [W] or /usr/share/opsi-script/lib [L]

The tests for the location of the <file name> are done in the order above. 'opsi-script' uses the first file it finds that has a matching name.

see also : Section 9.24

3.4.4. Encoding related functions [W/L/M]

encoding=<encoding> // (default is system encoding) since 4.11.4.2 see also : encoding

GetLocaleInfoMap : stringlist [W] see also : GetLocaleInfoMap

reencodestr(<str>, <from>, <to>`) : string` //since 4.11.4.2 [W/L/M] see also : reencodestr

reencodestrlist(<list>, <from>, <to>`) : stringlist` //since 4.11.4.2 [W/L/M] see also : reencodestrlist

fileHasBom (<file name>) : boolean` //since 4.12.4.17 [W/L/M] see also : fileHasBom

loadUnicodeTextFile (<file name>`) : stringlist` [W/L/M] see also : loadUnicodeTextFile

loadTextFileWithEncoding( <file name> , <encoding>`) : stringlist` //since 4.11.5 [W/L/M] see also : loadTextFileWithEncoding

strLoadTextFileWithEncoding ( <filename> , <encoding>`) : string` //since 4.11.4.6 [W/L/M] see also : strLoadTextFileWithEncoding

saveTextFileWithEncoding(<list>, < filename>`,` <encoding>`) : bool` //since 4.11.6.4: true: if list is succesfully written to file [W/L/M] see also : saveTextFileWithEncoding

includelog <file name> <tail size> [<encoding>] ` : noresult`//since 4.11.4.1 [W/L/M] see also : includelog

3.4.5. Error / Warning related functions [W/L/M]

ExitOnError = <boolean value> // (default=false) see also : ExitOnError

ScriptErrorMessages = <boolean value> // (default=true)

see also : ScriptErrorMessages

FatalOnSyntaxError = <boolean value> // (default=true) since 4.11.3.2 see also : FatalOnSyntaxError

FatalOnRuntimeError = <boolean value> // (default=false) since 4.11.3.2 see also : FatalOnRuntimeError

LogError <string> or LogError = <const string> see also : LogError

LogWarning <string> or LogWarning = <const string> see also : LogWarning

isFatalError [W/L/M] see also : isFatalError

isFatalError <string> //since 4.11.3.2 [W/L/M] see also : isFatalError

markErrorNumber see also : markErrorNumber

errorsOccurredSinceMark <relation> <integer> : boolean see also : errorsOccurredSinceMark

markErrorNumber
comment "log error and thereby increase the error counter"
if errorsOccurredSinceMark > 0
	comment "There was an error ..."
endif

getLastExitCode : string (exitcode) [W/L/M] see also : getLastExitCode

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

processCall(<string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M] see also : processCall

getLastServiceErrorClass : string see also : getLastServiceErrorClass

getLastServiceErrorMessage : string see also : getLastServiceErrorMessage

3.4.6. File related functions [W/L/M]

strLoadTextFile (<file name>`) : string` [W/L/M] see also : strLoadTextFile

strLoadTextFileWithEncoding ( <filename> , <encoding>`) : string` //since 4.11.4.6 [W/L/M] see also : strLoadTextFileWithEncoding

loadTextFile (<file name>`) : stringlist` [W/L/M] see also : loadTextFile

loadUnicodeTextFile (<file name>`) : stringlist` [W] see also : loadUnicodeTextFile

loadTextFileWithEncoding( <file name> , <encoding>`) : stringlist` //since 4.11.5 [W/L/M] see also : loadTextFileWithEncoding

fileHasBom (<file name>) : boolean` //since 4.12.4.17 [W/L/M] see also : fileHasBom

FileExists (<file name>`) : bool` [W/L/M] see also : FileExists

FileExists32 (<file name>`) : bool` [W] see also : FileExists

FileExists64 (<file name>`) : bool` [W] see also : FileExists

FileExistsSysNative (<file name>`) : bool` [W] see also : FileExists

DirectoryExists (<folder path> [,<access str>]) : boolean //since 4.12.1 [W/L/M]
'sysnative' is the default for <access str>. Otherwise, it can be '32bit', '64bit' or 'sysnative' see also : DirectoryExists

FileOrFolderExists (<file or folder path> [,<access str>]) : boolean [W/L/M] 'sysnative' is the default for <access str>. Otherwise, it can be '32bit', '64bit' or 'sysnative' see also : FileOrFolderExists

fileIsSymlink (<file name>`) : bool` // since 4.12.4.21 [W/L/M]
see also : fileIsSymlink

resolveSymlink (<file name>`) : <file name>` // since 4.12.4.21 [W/L/M]
see also : resolveSymlink

listFiles (<Path>, <Searchmask> , <SearchSubDirectories>, <[Redirection]>`) : stringlist` //since 4.12.3 [W/L/M]

Set $Filelist$ = listFiles("C:\windows\system32","*.ico;*.dll","False","64bit")

see also : listFiles

forcePathDelims (<path string>`) : <path string>` // since 4.12.4.21 [W/L/M]
see also : forcePathDelims

LineExistsIn (<string>, <file name>`) : bool` [W/L/M] see also : LineExistsIn

LineBeginning_ExistsIn (<string>, <file name>`) : bool` [W/L/M] see also : LineBeginning_ExistsIn

LineContaining_ExistsIn( <string>, <file name> ) : bool //since 4.11.4.10 [W/L/M]
true: if a in <file name> contains <string> see also : LineContaining_ExistsIn

saveTextFile(<list>, < filename>`) : bool` //since 4.11.4.4 [W/L/M]
true: if list is succesfully written to file see also : saveTextFile

saveTextFileWithEncoding(<list>, < filename>`,` <encoding>`) : bool` //since 4.11.6.4 [W/L/M]
true: if list is succesfully written to file see also : saveTextFileWithEncoding

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

getFileInfoMap32( <file name> ) : stringlist //since 4.11.6.6 [W] see also : getFileInfoMap

getFileInfoMap64( <file name> ) : stringlist //since 4.11.6.6 [W] see also : getFileInfoMap

getFileInfoMapSysnative( <file name> ) : stringlist //since 4.11.6.6 [W] see also : getFileInfoMap

ExtractFilePath (<path>`) : string` [W/L/M] see also : ExtractFilePath

ExtractFileExtension (<path>`) : string` [W/L/M] //since 4.12.1 see also : ExtractFileExtension

ExtractFileName (<path>`) : string` [W/L/M] //since 4.12.1 see also : ExtractFileName

see also: Section 3.3.4

see also: Section 3.3.7

3.4.7. Ini file related functions [W/L/M]

GetValueFromInifile (<file path>, <section>, <key>, <default value>, OPTIONAL <encoding>`) : string` [W/L/M]
see also : GetValueFromInifile

getSectionNames(<ini-file>`) : stringlist` [W/L/M] see also : getSectionNames

GetSectionFromInifile(<ini-file>`) : stringlist` [W/L/M] see also : GetSectionFromInifile

getValue(<key string>, <hash string list>`) : string` [W/L/M] see also : getValue

getValueBySeparator(<key string>,<separator string>,<hash string list>`) : string` //since 4.11.2.1 [W/L/M] see also : getValueBySeparator

setValueByKey(<key>, <value>, <targetlist> ) : stringlist [W/L/M] see also : [setValueByKey]

getValueFromFile(<key string>, <file name>`) : string` //since 4.11.4.4 [W/L/M] see also : getValueFromFile

getValueFromFileBySeparator(<key string>,<separator string>,<file name>`) : string` //since 4.11.4.4 [W/L/M] see also : getValueFromFileBySeparator

see also: Section 3.3.6

3.4.8. Interaction [W/L/M]

Pause <string> or Pause = <const string> see also : Pause

Stop <string> or stop = <const string> see also : Stop

setActionProgress <string> : noresult //since 4.11.3 [W/L/M] see also : setActionProgress

Message <string> or Message = <const string> see also : Message

ShowMessageFile <string> see also : ShowMessageFile

ShowBitMap [<file name>] [<sub title>] see also : ShowBitMap

stringinput(< message str>,< boolstr confidential>`) : string` //since 4.12.1.2 [W/L/M] see also : stringinput

editmap(< strlist>`) : stringlist` //since 4.12.1.2 [W/L/M] see also : editmap

3.4.9. License Management related functions [W/L/M]

DemandLicenseKey( poolId [, productId [,windowsSoftwareId]] ) : string

set $mykey$ = DemandLicenseKey ("", "office2007")

see also : DemandLicenseKey

FreeLicense (`poolId [, productId [,windowsSoftwareId]]) : string`

set $result$ = FreeLicense("", "office2007")

see also : FreeLicense

getLastServiceErrorClass : string see also : getLastServiceErrorClass

getLastServiceErrorMessage : string see also : getLastServiceErrorMessage

opsiLicenseManagementEnabled : bool see also : opsiLicenseManagementEnabled

3.4.10. Linux specific functions [W/L/M]

GetOS : string // 'Linux' or 'Windows_NT' or 'macos' [W/L/M] see also : GetOS

getLinuxDistroType : string // 'debian' or 'redhat' or 'suse' (see getLinuxVersionMap) [L] see also : getLinuxDistroType

getLinuxVersionMap : stringlist //since 4.11.4 [L] see also : getLinuxVersionMap

chmod in Files sections [L/M] see also : Commands

waitForPackageLock(<wait_seconds>,<abort_on_timeout>`) : bool` // since 4.11.6.1 [L] see also : waitForPackageLock

importlib "uib_lin_install" :

cleanupPackageSystem : void //since 4.13.4 [L] see also : cleanupPackageSystem

installupdates : string //since 4.13.4 [L] see also : installupdates

debinstall($packagelist$ : stringlist) : string //since 4.13.4 [L] see also : debinstall

redinstall($packagelist$ : stringlist) : string //since 4.13.4 [L] see also : redinstall

suseinstall($packagelist$ : stringlist) : string //since 4.13.4 [L] see also : suseinstall

ucsinstall($packagelist$ : stringlist) : string //since 4.13.4 [L] see also : ucsinstall

genericLinInstall($packagelist$ : stringlist) : string
see also : genericLinInstall

linuxInstallOneOf($packagelist$ : stringlist) : string
see also : genericLinInstall

isOneInstalled($packagelist$ : stringlist) : string
see also : linuxInstallOneOf

linuxInstallOneFile($packagefile$ : string) : string
see also : linuxInstallOneFile

linuxRemoveOnePackage($packagename$ : string) : string
see also : linuxRemoveOnePackage

linuxRemoveOneOf($packagelist$ : stringlist) : string
see also : linuxRemoveOneOf

3.4.11. Logging related functions [W/L/M]

SetLogLevel = <number> or SetLogLevel = <string> // (default=6)

SetLogLevel = 7
SetLogLevel = "7"

Message <string> or Message = <const string> see also : Message

comment <string> or comment = <const string> see also : comment

LogError <string> or LogError = <const string> see also : scriptWasExecutedBefore

LogWarning <string> or LogWarning = <const string> see also : LogError

includelog <file name> <tail size> //since 4.11.2.1 [W/L/M] see also : includelog

includelog <file name> <tail size> [<encoding>] //since 4.11.4.1 [W/L/M] see also : includelog

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

SetConfidential <secret string> //since 4.11.3.5 [W/L/M] see also : setConfidential

asConfidential( <secret string expression> ) : string //since 4.12.0.16 [W/L/M] see also : asConfidential_str

asConfidential( <secret stringlist expression> ) : stringlist //since 4.12.4.15 [W/L/M] see also : asConfidential_list

forceLogInAppendMode = <boolean value> // (default=false); if true, log will be send in append mode . //since 4.12.3.6 see also : forceLogInAppendMode

opsi-configs

opsi-script.global.debug_prog : boolean ; if false: only Warnings and Errors from program logging; default: false
see also : Central configuration via opsi Configs

opsi-script.global.debug_lib : boolean ; if false: only Warnings and Errors from library logging; default: false
see also : Central configuration via opsi Configs

opsi-script.global.default_loglevel : intstr ; set the default log level; default: '6'
see also : Central configuration via opsi Configs

opsi-script.global.force_min_loglevel : intstr ; set the minimal loglevel; default: '0'
see also : Central configuration via opsi Configs

opsi-script.global.ScriptErrorMessages : boolean ; overwrites the opsi-script internal default; default: false
see also : ScriptErrorMessages

opsi-script.global.AutoActivityDisplay : boolean ; overwrites the opsi-script internal default; default: true
see also : AutoActivityDisplay

opsi-script.global.SupressSystemEncodingWarning : boolean ; suppress some encoding warnings; default: false
see also : SupressSystemEncodingWarning

opsi-script.global.ReverseProductOrderByUninstall : boolean ; product list is reordered for uninstall; default: false
see also : ReverseProductOrderByUninstall

opsi-script.global.log_rotation_count : boolean ; number of opsi-script.log backups; default: 8
see also : log_rotation_count

opsi-script.global.writeProductLogFile : boolean ; logs for every single opsi product; default: false
see also : writeProductLogFile

3.4.12. macOS specific functions [W/L/M]

GetOS : string // 'Linux' or 'Windows_NT' or 'macos' [W/L/M] see also : GetOS

getMacosVersionInfo : string //macOS Version Information //since 4.12.1.0 [M] see also : getMacosVersionInfo

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

GetSystemType : string //OS Architecture ("64 Bit System" or "x86 System") [W/L/M] see also : GetSystemType

getOSArchitecture // OS Architecture (x86_32 / x86_64/ arm_64) //since 4.12.4.17 [W/L/M]
see also : getOSArchitecture

importlib "uib_macosinstalllib" :

install_macos_app($myapp$ : string) : string [M]
see also : xref:install_macos_app>>

install_macos_pkg($mypkg$ : string) : string [M]
see also : xref:install_macos_pkg>>

install_macos_dmg($mydmg$ : string) : string [M]
see also : xref:install_macos_dmg>>

install_macos_zip($myzip$ : string) : string [M]
see also : xref:install_macos_zip>>

install_macos_generic($myfile$ : string) : string [M] see also : install_macos_generic

3.4.13. Network related functions [W/L/M]

GetHostsName (<hostaddress> ) : string [W/L/M] see also : GetHostsName

GetHostsAddr (<hostname> ) : string [W/L/M] see also : GetHostsAddr

GetMyIpByTarget(<target ip addr>`) : string` //since 4.11.3.2 /4.11.6 [W/L/M] see also : GetMyIpByTarget

GetIpByName(<ip addr / ip name>`) : string` //since 4.11.3.2 [W/L/M] see also : GetIpByName

isValidIP4 (<ip4adr>) : boolean //since 4.12.1 see also : isValidIP4

isValidIP4Network (<ip4adr>, <netmask>) : boolean //since 4.12.1 see also : isValidIP4Network

isValidIP4Host (<ip4adr>, <netmask>) : boolean //since 4.12.1 see also : isValidIP4Host

getIP4NetworkByAdrAndMask (<ip4adr>, <netmask>) : string //since 4.12.1 see also : getIP4NetworkByAdrAndMask

getDefaultNetmaskByIP4adr (<ip4adr>) : string //since 4.12.1 see also : getDefaultNetmaskByIP4adr

parseUrl(<url string>) : stringlist //since 4.12.1 see also : parseUrl

createUrl(<urlcomponents list>) : string //since 4.12.1 see also : createUrl

isPingReachable(<host>) : boolean //since 4.12.3.6 see also : isPingReachable

isValidFQDN(<domain name>) : boolean //since 4.12.4.4 [W/L/M] see also : isValidFQDN

cidrToNetmask (<string>) : string //since 4.12.4.37 see also : [cidrToNetmask]

netmaskToCidr (<string>) : string //since 4.12.4.37 see also : [netmaskToCidr]

isCertInstalledInSystem(<label>`) : boolstring` [W/L/M] //since 4.12.4.37 see also : [isCertInstalledInSystem]

importCertToSystem(<filename>`) : noresult` [W/L/M] //since 4.12.4.37 see also : [importCertToSystem]

removeCertFromSystem(<label>`) : noresult` [W/L/M] //since 4.12.4.37 see also : [removeCertFromSystem]

listCertificatesFromSystem(<label>`) : stringlist` [W/L/M] //since 4.12.4.37 see also : [listCertificatesFromSystem]

3.4.14. Number related functions [W/L/M]

isNumber(<str>`) : bool` //since 4.11.3: true if <str> represents an integer [W/L/M] see also : isNumber

CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>`) : bool` //since 4.11.5.2: [W/L/M] see also : CompareDotSeparatedNumbers_bool

CompareDotSeparatedNumbers(<string1>, <string2>`) : string` [W/L/M] see also : CompareDotSeparatedNumbers_str

calculate(<arithmetic string expression>`) : string (number)` // since 4.11.3.5 [W/L/M]
knows: +-*/() see also : calculate

DecStrToHexStr ( <decstring>, <hexlength>`) : string` [W/L/M] see also : DecStrToHexStr

HexStrToDecStr (<hexstring>`) : string` [W/L/M] see also : HexStrToDecStr

RandomIntStr(<number str>`) : string` [W/L/M] see also : RandomIntStr

3.4.15. Operating System related functions [W/L/M]

GetOS : string // 'Linux' or 'Windows_NT' or 'macos' [W/L/M] see also : GetOS

GetMsVersionInfo : string //Windows Version Information [W] see also : GetMsVersionInfo

GetMSVersionMap : stringlist [W] see also : GetMSVersionMap

getLinuxDistroType : string // 'debian' or 'redhat' or 'suse' (see getLinuxVersionMap) [L] see also : getLinuxDistroType

getLinuxVersionMap : stringlist //since 4.11.4 [L] see also : getLinuxVersionMap

getMacosVersionInfo : string //macOS Version Information //since 4.12.1.0 [M] see also : getMacosVersionInfo

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

GetSystemType : string //OS Architecture ("64 Bit System" or "x86 System") [W/L/M] see also : GetSystemType

getOSArchitecture // OS Architecture (x86_32 / x86_64/ arm_64) //since 4.12.4.17 [W/L/M]
see also : getOSArchitecture

getListFromWMI(<wmi namespace str>,<wmi class str>,<property list>,<condition str>`) : stringlist` //since 4.12.1.0 [W] see also : opsi-wmi-test.exe (small helper application works like getListFromWMI)

EnvVar (<environment variable>`) : string` [W/L/M] see also : EnvVar

getProfilesDirList : stringlist //since 4.11.3.2 [W/L/M] see also : getProfilesDirList

listFiles (<Path>, <Searchmask> , <SearchSubDirectories>, <[Redirection]>`) : stringlist` //since 4.12.3 [W/L/M]

Set $Filelist$ = listFiles("C:\windows\system32","*.ico;*.dll","False","64bit")

see also : listFiles

which(<command in path>`) : string` (command with path) //since 4.12.3.6 [W/L/M] see also : which

runningAsAdmin : bool //since 4.11.1.1 [W/L/M] see also : runningAsAdmin

runningOnUefi : bool` //since 4.11.4.3: true: if the running OS was booted in UEFI mode [W/L/M] see also : runningOnUefi

runningInPE : bool` //since 4.12.0.13: true: if the running OS is a Windows PE [W] see also : runningInPE

runningInWAnMode //since 4.12.4.16: true: if opsiserver = localhost [W/L/M] see also : runningInWAnMode

isDriveReady(<drive letter>`) : bool`` //since 4.11.4.4: true: if the drive can be accessed [W] see also : isDriveReady

runningWithGui : bool` //since 4.12.3.6: true: if the running OS with GUI (at Win+Mac always true)[M/L/W] see also : runningWithGui

3.4.16. opsiservicecall and json Related functions [W/L/M]

jsonIsValid(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M] see also : jsonIsValid

jsonIsArray(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M] see also : jsonIsArray

jsonIsObject(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M] see also : jsonIsObject

jsonAsObjectHasKey(<jsonstr>,<keystr>`) : boolean` //since 4.11.6: [W/L/M] see also : jsonAsObjectHasKey

jsonAsArrayCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M] see also : jsonAsArrayCountElements

jsonAsObjectCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M] see also : jsonAsObjectCountElements

jsonAsArrayGetElementByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6: [W/L/M] see also : jsonAsArrayGetElementByIndex

jsonAsObjectGetValueByKey(<jsonstr>, <keystr>`) : valuestring` //since 4.11.6: [W/L/M] see also : jsonAsObjectGetValueByKey

jsonAsObjectSetValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M] see also : jsonAsObjectSetValueByKey

jsonAsObjectSetStringtypeValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M] see also : jsonAsObjectSetStringtypeValueByKey

jsonAsObjectDeleteByKey(<jsonstr>, <keystr>`) : jsonstring` //since 4.11.6.4: [W/L/M] see also : jsonAsObjectDeleteByKey

jsonAsArrayPutObjectByIndex(<jsonstr>, <indexstr>, <objectstr>`) : jsonstring` //since 4.11.6: [W/L/M] see also : jsonAsArrayPutObjectByIndex

jsonAsArrayDeleteObjectByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6.4: [W/L/M] see also : jsonAsArrayDeleteObjectByIndex

jsonAsArrayToStringList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M] see also : jsonAsArrayToStringList

jsonAsObjectGetKeyList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M] see also : jsonIsArray

jsonStringListToJsonArray(<strlist>`) : jsonstr` //since 4.11.6: [W/L/M] see also : jsonAsObjectGetKeyList

convert2Jsonstr(<string>`)` //since 4.10.8.3

see also: OpsiServiceCall Section 3.3.9

3.4.17. opsi related functions [W/L/M]

getProductMap : stringlist // since 4.11.2.4 [W/L/M]
keys are: id, name, description, advice, productversion, packageversion, priority, installationstate, lastactionrequest, lastactionresult, installedversion, installedpackage, installedmodificationtime,actionrequest see also : getProductMap

getProductPropertyList(<propname>,<default value>`) : stringlist` //since 4.11.3 [W/L/M] see also : getProductPropertyList

GetProductProperty (<PropertyName>, <DefaultValue> ) : string [W/L/M] see also : GetProductProperty

GetConfidentialProductProperty ( <PropertyName>, <DefaultValue>`) : string` //since 4.11.5.2 [W/L/M] see also : GetConfidentialProductProperty

setActionProgress <string> : noresult //since 4.11.3 [W/L/M] see also : setActionProgress

retrieveSection (<section name>`) : stringlist` [W/L/M] see also : retrieveSection

replaceOpsiConstants(<string list>`) : stringlist` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_list

replaceOpsiConstants(<string>`) : string` //since 4.12.3.6 [W/L/M] see also : replaceOpsiConstants_string

runningInWanMode : boolean //since 4.12.4.17 [W/L/M] see also : runningInWanMode

reloadProductList //since 4.12.6.1 [W/L/M] see also : reloadProductList

3.4.18. Process and Script Related functions

Killtask <process name> ` : noresult` [W/L/M] see also : Killtask

ChangeDirectory <directory> ` : noresult` //since 4.11.2.6 [W/L/M] see also : ChangeDirectory

GetProcessList : stringlist //since 4.11.1.2; gives list of exename;pid;dom/user [W/L/M] see also : GetProcessList

processIsRunning(<process name>`) : boolean` //since 4.11.6.1 [W/L/M] see also : processIsRunning

isProcessChildOf(<searchprocstr>, <parentprocstr>): bool //since 4.12.4.35 [W/L/M]
see also : [isProcessChildOf]

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

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

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

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

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]
see also : powershellCall_list

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]
see also : powershellCall

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]
see also : powershellCall_str

getOutStreamFromSection (<dos section name>`) : stringlist (output)` [W/L/M]

set $list$= getOutStreamFromSection ('DosInAnIcon_try')

processCall(<string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M] see also : processCall

getLastExitCode : string (exitcode) [W/L/M] see also : getLastExitCode

includelog <file name> <tail size> : noresult //since 4.11.2.1 [W/L/M] see also : includelog

includelog <file name> <tail size> [<encoding>] : noresult //since 4.11.4.1 [W/L/M] see also : includelog

waitForPackageLock(<seconds timeout string>,<bool should we kill>`) : bool` //since 4.11.6.1 [L] see also : waitForPackageLock

which(<command in path>`) : string` (command with path) //since 4.12.3.6 [W/L/M] see also : which

executeSection(<string expr with section call>`)` //since 4.12.3.9 [W/L/M] see also : executeSection

see also: ExecWith sections Section 3.3.3

see also: ShellBatch sections Section 3.3.2

see also: Winbatch sections Section 3.3.1

3.4.19. Regular expression related functions [W/L/M]:

isRegexMatch(<string>, <pattern>) : boolean //since 4.12.1 see also : isRegexMatch

getSubListByContainingRegex(<pattern>, <target list>) : stringlist //since 4.12.1 see also : getSubListByContainingRegex

getSubListByContainingRegex(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : getSubListByContainingRegex

getRegexMatchList(<pattern>, <target list>) : stringlist //since 4.12.1 see also : getRegexMatchList

getRegexMatchList(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : getRegexMatchList

removeFromListByContainingRegex(<pattern>, <target list>) : stringlist //since 4.12.1 see also : removeFromListByContainingRegex

removeFromListByContainingRegex(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : removeFromListByContainingRegex

stringReplaceRegex(<string>, <pattern>, <replacement string>) : string //since 4.12.1 see also : stringReplaceRegex

stringReplaceRegexInList(<target list>, <pattern>, <replacement string>) : stringlist //since 4.12.1 see also : stringReplaceRegexInList

3.4.20. Registry related functions [W]

getRegistryValue(<keystr>, <varstr> ) : string //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : getRegistryValue

GetRegistrystringvalue(`"[key] var") : string` [W] see also : GetRegistrystringvalue

GetRegistryStringValue32 (`"[key] var") : string` //since 4.10.8 [W] see also : GetRegistryStringValue32

GetRegistryStringValue64 (`"[key] var") : string` //since 4.10.8 [W] see also : GetRegistryStringValue64

GetRegistryStringValueSysNative (`"[key] var") : string` //since 4.10.8 [W] see also : GetRegistryStringValueSysNative

getRegistryKeyList32(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryKeyList32

getRegistryKeyList64(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryKeyList64

getRegistryKeyListSysnative(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryKeyListSysnative

getRegistryKeyList(<regkey>, <access str>`) : stringlist` //since 4.12.5.0 [W] see also : getRegistryKeyList

getRegistryVarList32(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarList32

getRegistryVarList64(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarList64

getRegistryVarListSysnative(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarListSysnative

getRegistryVarList(<regkey>, <access str>`) : stringlist` //since 4.12.5.0 [W] see also : getRegistryVarList

getRegistryVarMap32(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarMap32

getRegistryVarMap64(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarMap64

getRegistryVarMapSysnative(<regkey>`) : stringlist` //since 4.11.3 [W] see also : getRegistryVarMapSysnative

getRegistryVarMap(<regkey>, <access str>`) : stringlist` //since 4.12.5.0 [W] see also : getRegistryVarMap

RegKeyExists(<regkey>[,<access str>]) : bool //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : RegKeyExists

RegVarExists(<regkey>, <var str> ) : bool //since 4.12.0.16 [W]
<access str> = one of 32bit, 64bit, sysnative ; default sysnative see also : RegVarExists

see also: Section 3.3.5

see also : Registry-Sections

see also : 64 bit

3.4.21. String handling functions [W/L/M]

see also : string

splitString (<string1>, <string2>`) : stringlist` [W/L/M] see also : splitString

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

splitStringOnWhiteSpace (<string>`) : stringlist` [W/L/M] see also : splitStringOnWhiteSpace

composeString (<string list>, <Link>`) : string` [W/L/M] see also : composeString

takeString (<index>, <list>`) : string` [W/L/M] see also : takeString

setStringInListAtIndex(<newstring>,<list>,<indexstr>`) : stringlist` //since 4.11.6 [W/L/M] see also : setStringInListAtIndex

takeFirstStringContaining(<list>,<search string>`) : string` [W/L/M] see also : takeFirstStringContaining

getIndexFromListByContaining(<list> : stringlist,<search string> : string`)` : <number> : string //since 4.12.0.13 [W/L/M] see also : getIndexFromListByContaining

contains(<str>, <substr>`) : bool` //since 4.11.3: true if <substr> in <str> [W/L/M] see also : contains

isNumber(<str>`) : bool` //since 4.11.3: true if <str> represents an integer [W/L/M] see also : isNumber

trim(<string>`) : string` [W/L/M] see also : trim

lower(<string>`) : string` [W/L/M] see also : lower

upper(<string>`)` [W/L/M] see also : upper

unquote(<string>,<quote-string>`) : string` //since 4.11.2.1 [W/L/M] see also : unquote

unquote2(<string>,<quote-string>`) : string` //since 4.11.5.2 [W/L/M] see also : unquote2

stringReplace(<string>, <oldPattern>, <newPattern>`) : string` //since 4.11.3 [W/L/M] see also : stringReplace

strLength(<string>`) : string (number)` //since 4.11.3 [W/L/M] see also : strLength

strPos(<string>, <sub string>`) : string (numner)` //since 4.11.3 [W/L/M] see also : strPos

strPart(<string>, <start pos>, <number of chars>`) : string` //since 4.11.3 [W/L/M] see also : strPart

getValue(<key string>, <hash string list> ) : string [W/L/M] see also : getValue

getValueBySeparator(<key string>,<separator string>,<hash string list> ) : string //since 4.11.2.1 [W/L/M] see also : getValueBySeparator

getValueFromFile(<key string>, <file name>`) : string` //since 4.11.4.4 [W/L/M] see also : getValueFromFile

getValueFromFileBySeparator(<key string>,<separator string>,<file name>`) : string` //since 4.11.4.4 [W/L/M] see also : getValueFromFileBySeparator

EscapeString: <sequence of characters> : string// [W/L/M] see also : EscapeString

stringReplaceRegex(<string>, <pattern>, <replacement string>) : string //since 4.12.1 [W/L/M] see also : stringReplaceRegex

stringinput(< message str>,< boolstr confidential>`) : string` //since 4.12.1.2 [W/L/M] see also : stringinput

3.4.22. Stringlist handling functions [W/L/M]

see also : stringlist

getListContaining(<list>,<search string>`) : stringlist` [W/L/M] see also : getListContaining

getListContainingList(<list1>,<list2>`) : stringlist` //since 4.11.3.7 [W/L/M] see also : getListContainingList

getIndexFromListByContaining(<list> : stringlist,<search string> : string`)` : <number> : string //since 4.12.0.13 [W/L/M] see also : getIndexFromListByContaining

count (<list>`) : string (number)` [W/L/M] see also : count

emptylist (<list>`) : stringlist` //since 4.11.3.7 [W/L/M] see also : emptylist

for %<identifier>`% in` <list> do <one statement | sub section> [W/L/M]

for %s% in $list1$ do sub_test_string

createStringList (<string0>, <string1> ,…​ ) : stringlist [W/L/M]

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

see also : createStringList

reverse (<list>`) : stringlist` [W/L/M] see also : reverse

getSubList (<start index> : <end index>, <list>`) : stringlist` [W/L/M] see also : getSubList

getSubListByMatch (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByMatch_sl

getSubListByMatch (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByMatch_ll

getSubListByContaining ( <search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByContaining_sl

getSubListByContaining (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByContaining_ll

getSubListByKey (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByKey_sl

getSubListByKey (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getSubListByKey_ll

getKeyList (<list>`)` :stringlist //since 4.12.0.14 [W/L/M] see also : getKeyList

addtolist(<list>,<string>`) : stringlist` //since 4.10.8 [W/L/M] see also : addtolist

addListToList(<dest list>,<src list>`) : stringlist` //since 4.10.8 [W/L/M] see also : addListToList

reencodestrlist(<list>, <from>, <to>`) : stringlist` //since 4.11.4.2 [W/L/M] see also : reencodestrlist

removeFromListByContaining(<search string>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M] see also : removeFromListByContaining_str

removeFromListByContaining(<search list>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M] see also : removeFromListByContaining_list

removeFromListByMatch(<searchstring>,<target list>`) : stringlist` //since 4.11.6 [W/L/M] see also : removeFromListByMatch

takeString (<index>, <list>`) : string` [W/L/M] see also : takeString

takeFirstStringContaining(<list>,<search string>`) : string` [W/L/M] see also : takeFirstStringContaining

setStringInListAtIndex(<newstring>,<list>,<indexstr>`) : stringlist` //since 4.11.6 [W/L/M] see also : setStringInListAtIndex

jsonAsArrayToStringList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M] see also : jsonAsArrayToStringList

jsonStringListToJsonArray(<strlist>`) : jsonstr` //since 4.11.6: [W/L/M] see also : jsonStringListToJsonArray

jsonAsObjectGetKeyList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M] see also : jsonAsObjectGetKeyList

splitString(<string1>, <string2>`)` : stringlist [W/L/M]

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

see also : splitString

splitStringOnWhiteSpace (<string>`) : stringlist` [W/L/M] see also : splitStringOnWhiteSpace

composeString(<string list>, <Link>`) : string` [W/L/M] see also : composeString

getValue(<key string>, <hash string list> ) : string [W/L/M] see also : getValue

getValueBySeparator(<key string>,<separator string>,<hash string list> ) : string //since 4.11.2.1 [W/L/M] see also : getValueBySeparator

setValueByKey(<key>, <value>, <targetlist> ) : stringlist [W/L/M] see also : [setValueByKey]

getSubListByContainingRegex(<pattern>, <target list>) : stringlist //since 4.12.1 see also : getSubListByContainingRegex

getSubListByContainingRegex(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : getSubListByContainingRegex

getRegexMatchList(<pattern>, <target list>) : stringlist //since 4.12.1 see also : getRegexMatchList

getRegexMatchList(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : getRegexMatchList

removeFromListByContainingRegex(<pattern>, <target list>) : stringlist //since 4.12.1 see also : removeFromListByContainingRegex

removeFromListByContainingRegex(<pattern list>, <target list>) : stringlist //since 4.12.1 see also : removeFromListByContainingRegex

stringReplaceRegexInList(<target list>, <pattern>, <replacement string>) : stringlist //since 4.12.1 see also : stringReplaceRegexInList

editmap(< strlist>`) : stringlist` //since 4.12.1.2 [W/L/M] see also : editmap

areListsEqual(< strlist1>, <strlist2>, <flag>`) : boolean` see also : areListsEqual

GetSectionFromInifile(<ini-file>`) : stringlist` [W/L/M] see also : GetSectionFromInifile

3.4.23. Time / Date related functions [W/L/M]

sleepSeconds <Integer> or <string> : noresult [W/L/M]
breaks the program execution for <string> seconds. <string> has to represent an Integer Value
see also : sleepSeconds

markTime : noresult [W/L/M]
sets a time stamp for the current system time and logs it. see also : markTime

getDiffTimeSec : string (Time in seconds since last marktime) //since 4.11.3 [W/L/M] see also : getDiffTimeSec

timeStampAsFloatStr : string (Floating Number - format: 'days.decimal days') //since 4.11.6 [W/L/M] see also : timeStampAsFloatStr

3.4.24. Usercontext / loginscripts related functions [W]:

GetUserSID(<Windows Username>`) : string` see also : GetUserSID

GetLoggedInUser : string //since 4.11.1.2 see also : GetLoggedInUser

GetUsercontext : string //since 4.11.1.2 see also : GetUsercontext

GetScriptMode : string possible values 'Machine','Login' //since 4.11.2.1 see also : GetScriptMode

saveVersionToProfile : noresult - save productversion-packageversion to local profile //since 4.11.2.1 see also : saveVersionToProfile

readVersionFromProfile : string - read productversion-packageversion from local profile //since 4.11.2.1 see also : readVersionFromProfile

scriptWasExecutedBefore : boolean - is true if saved and running productversion-packageversion are identical //since 4.11.2.1 see also : scriptWasExecutedBefore

3.4.25. XML related functions (XML2) [W/L/M]:

getXml2DocumentFromFile(<path to xml file>`) : xml2stringlist` //since 4.12.1 see also : getXml2DocumentFromFile

getXml2Document(<stringlist wit xml>`) : xml2stringlist` //since 4.12.1 see also : getXml2DocumentFromFile

xml2GetFirstChildNodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1. see also : xml2GetFirstChildNodeByName

getXml2UniqueChildnodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1. see also : getXml2UniqueChildnodeByName

getXml2AttributeValueByKey(<xml2stringlist>, <attr name str>`) : string` //since 4.12.1. see also : getXml2AttributeValueByKey

getXml2Text(<xml2stringlist>`) : string` //since 4.12.1. see also : getXml2Text

see also : Section 3.3.11

see also : XML2 Section

3.4.26. TOML files related functions [W/L/M]:

LoadTOMLFile(<TOMLfilePath: String>`) : StringList` //since 4.12.5 see also : LoadTOMLFile

ReadTOMLFile(<TOMLfilePath: String>`) : String` //since 4.12.5 see also : ReadTOMLFile

GetTOMLAsStringList(<TOMLcontents: String>`) : StringList` //since 4.12.5 see also : GetTOMLAsStringList

GetTOMLAsString(<TOMLcontents: String>`) : String` //since 4.12.5 see also : GetTOMLAsString

GetTOMLKeys(<TOMLcontents: String>`) : StringList` //since 4.12.5 see also : GetTOMLKeys

GetTOMLTableNames(<TOMLcontents: String>`) : StringList` //since 4.12.5 see also : GetTOMLTableNames

GetTOMLTable(<TOMLcontents: String> , <table name : String>`) : StringList` //since 4.12.5 see also : GetTOMLTable

GetTOMLTableAsString(<TOMLcontents: String> , <table name : String>`) : String` //since 4.12.5 see also : GetTOMLTableAsString

GetValueFromTOML(<TOMLcontents: String> , <keyPath: String> , <defaultValue: String>`) : String` //since 4.12.5 see also : GetValueFromTOML

ModifyTOML(<TOMLcontents: String> , <command: String> , <keyPath: String> , <value: String>`) : String` //since 4.12.5 see also : ModifyTOML

DeleteTableFromTOML(<TOMLcontents: String> , <tablePath: String>`) : String` //since 4.12.5 see also : DeleteTableFromTOML

SaveToTOMLFile(<TOMLcontents: String> , <TOML file Path: String>`) : boolean` //since 4.12.5 see also : SaveToTOMLFile

ConvertTOMLtoJSON(<TOMLcontents: String>`) : String` //since 4.12.5 see also : ConvertTOMLtoJSON

ConvertTOMLfileToJSONfile(<TOMLfilePath: String> , <JSONfilePath: String>`) : boolean` //since 4.12.5
see also : ConvertTOMLfileToJSONfile

4. Using opsi-script on Linux or macOS

4.1. Introduction

As of version 4.11.4 there is a Linux port of opsi-script.

As of version 4.12.1 there is a macOS port of opsi-script.

Conditionally to the progress on porting and the differences between Linux, Windows and macOS not all functionalities are available for all operating systems.

In the following section the availability is marked as:

  • [W/L/M] may be used on Windows, Linux and macOS as well

  • [W] Windows only

  • [L] Linux only

  • [M] macOS only

4.2. Important differences and hints

'opsi-script.exe' is at Windows a GUI application which may be started with the parameter /silent also without a GUI.

opsi-script is at Linux and macOS command line version which can be started without any access to a graphical display. Nevertheless this program starts a test if a access to a graphical display is possible and (if it is) starts the GUI version 'opsi-script-gui'. This feature may be suppressed by calling opsi-script with the parameter -silent.

'opsi-script-gui' is a graphical version which can not be started without access to a graphical display.

At Linux and macOS the parameter delimiter is not "/" but "-". So instead of calling opsi-script /help you should call opsi-script -help at Linux and macOS.

4.3. opsi-script path at Linux

Since opsi-client-agent 4.2 you will find all components of the opsi-script program at /opt/opsi-script/.

Before opsi-client-agent 4.2:

  • executable programs:
    /usr/bin/opsi-script
    /usr/bin/opsi-script-nogui

  • log files directories:
    if running with root privileges: /var/log/opsi-script
    if not running with root privileges: /tmp

  • language files:
    /usr/share/locale

  • skin files:
    Default = /usr/share/opsi-script/skin
    Custom = /usr/share/opsi-script/customskin

  • opsi-script library files:
    /usr/share/opsi-script/lib

Independent of the version:

  • log files directories:
    if running with root privileges: /var/log/opsi-script
    if not running with root privileges: /tmp

  • config files:
    /etc/opsi-script

4.4. opsi-script path at macOS

You will find all components of the opsi-script program at /Applications/opsi-script/.

  • log files directories:
    if running with root privileges: /var/log/opsi-script
    if not running with root privileges: /tmp

  • config files:
    /etc/opsi-script

4.5. Path handling in opsi-script

As of version 4.11.4 for all functions that expect a path as argument, the path string is converted to a valid path for the actual operating system. This means that all path delimiters will be set OS specific. For example a path string like /home/opsiproduct\myproduct\CLIENT_DATA will be on Linux converted to /home/opsiproduct/myproduct/CLIENT_DATA. Therefore it is not possible to handle files that have a backslash in their name.

4.6. Linux specific functions

For Linux support there are the following special functions:

In the following chapters are some commands presented, that are useful to install software on Linux. These commands are part of the opsi-script library uib_lin_install.

For an overview we start to explain the different approaches of these commands.

  • distribution independent commands

    • cleanupPackageSystem

    • installupdates

  • Installation of one or more packages from an online repo for one specific distribution. (This is what you wnt to do if you have only one distribution in your organization)
    These command take a stringlist with the name of the packages to install as argument. If you want to install only one package you may use createStringList(<package name>) instead of $packagelist$.
    The given package names must match to your distribution. You have to choose the command that matches your distribution family.

    • debinstall($packagelist$ : stringlist) : string //since 4.12.4 [L]

    • redinstall($packagelist$ : stringlist) : string //since 4.12.4 [L]

    • suseinstall($packagelist$ : stringlist) : string //since 4.12.4 [L]

    • ucsinstall($packagelist$ : stringlist) : string //since 4.12.4 [L]

  • Installation / uninstall of one or more packages from an online repo for one specific distribution. This command is distribution independent.

    • genericLinInstall($packagelist$ : stringlist) : string

    • linuxRemoveOnePackage($packagename$ : string) : string

    • linuxInstallOneFile($packagefile$ : string) : string

  • Installation / check / uninstall of one package from an online repo for different distributions. Therefor this one package may have different names in different distributions. All these different names are part of the $packagelist$ argument. This command is distribution independent.

    • linuxInstallOneOf($packagelist$ : stringlist) : string

    • isOneInstalled($packagelist$ : stringlist) : string

    • linuxRemoveOneOf($packagelist$ : stringlist) : string

The details to these library commands you will find here: Documentation of opsi library: uib_lin_install.opsiscript

References to some mor Linux specific library function you will find at: Linux specific functions

4.7. Example scripts for Linux

4.7.1. Run on Linux only

[Actions]
DefVar $OS$

set $OS$ = GetOS

if not ($OS$ = "Linux")
	logError "Installation aborted: wrong OS version: only Linux allowed"
	isFatalError "wrong OS"
endif

4.7.2. Which Linux Version

[Actions]
DefVar $distCodeName$
DefVar $distroName$
DefVar $distRelease$
DefVar $distrotype$


DefStringList $linuxInfo$

set $distrotype$ = getLinuxDistroType
set $linuxInfo$ = getLinuxVersionMap
set $distCodeName$ = getValue("Codename", $linuxInfo$)
set $distRelease$ = getValue("Release", $linuxInfo$)
set $distroName$  = getValue("Distributor ID", $linuxInfo$)
Table 1. getLinuxVersionMap Result Examples
Distro Distributor ID Release Codename Description

Ubuntu Focal

Ubuntu

20.04

focal

Debian 8

Debian

8.3

jessie

Debian GNU/Linux 8.3 (jessie)

openSUSE Leap 42.1

SUSE LINUX

42.1

n/a

openSUSE Leap 42.1 (x86_64)

SLES12SP1

SUSE LINUX

12.1

n/a

SUSE Linux Enterprise Server 12 SP1

CentOS 7.0

CentOS

7.0.1406

Core

CentOS Linux release 7.0.1406 (Core)

RedHat 7.0

RedHatEnterpriseServer

7.0

Maipo

Red Hat Enterprise Linux Server release 7.0 (Maipo)

UCS 4.1

Univention

4.1-1 errata122

Vahr

Univention Corporate Server 4.1-1 errata122 (Vahr)

4.7.3. ShellInAnIcon call

[Actions]

ShellInAnIcon_ls

[ShellInAnIcon_ls]
set -x
ls
exit $?

It’s always a good idea to start with set -x for more information in the log and to set the PATH. You should end with exit $? so that the exitcode of the last call is the exitcode of the section.

4.7.4. Add a repository

Listing 1. Ubuntu / Debian
[Actions]
DefVar $newrepo$

set $newrepo$ = "deb http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/Debian_7.0/ ./"

comment "Method 1: use add-apt-repository ..."
ShellInAnIcon_add_rep_deb
ShellInAnIcon_add_repokey_deb
comment "Method 2: use add-apt-repository ..."
PatchTextFile_add_repo_deb "/etc/apt/sources.list"
ShellInAnIcon_add_repokey_deb

[ShellInAnIcon_add_rep_deb]
set -x
export DEBIAN_FRONTEND=noninteractive
apt-get --yes --force-yes install software-properties-common
apt-get --yes --force-yes install python-software-properties
add-apt-repository '$newrepo$'
exit $?

[PatchTextFile_add_repo_deb]
FindLine_StartingWith "$newrepo$"
DeleteTheLine
GoToBottom
InsertLine "$newrepo$"

[ShellInAnIcon_add_repokey_deb]
set -x
wget --no-check-certificate -O - $newrepo$/Release.key | apt-key add -
apt-get update
exit $?
Listing 2. SUSE
[Actions]
DefVar $newrepo$

set $newrepo$ = "http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/openSUSE_13.1/home:uibmz:opsi:opsi40.repo"

ShellInAnIcon_add_opsi_repository_suse

[ShellInAnIcon_add_opsi_repository_suse]
set -x
zypper --no-gpg-checks --non-interactive --gpg-auto-import-keys ar --refresh $newrepo$
zypper --no-gpg-checks --non-interactive --gpg-auto-import-keys refresh
exit $?
Listing 3. CentOS / Redhat
[Actions]
DefVar $newrepo$

set $newrepo$ = "http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/CentOS_7/home:uibmz:opsi:opsi40.repo"

comment "Method 1: use wget ..."
ShellInAnIcon_add_repo_redhat
ShellInAnIcon_refresh_repo_redhat
comment "Method 2: use PatchTextFile ..."
PatchTextFile_add_repo_redhat "/etc/yum.repos.d/mynew.repo"
ShellInAnIcon_refresh_repo_redhat

ShellInAnIcon_add_repo_redhat

[ShellInAnIcon_add_repo_redhat]
set -x
yum -y install wget
cd /etc/yum.repos.d
wget --no-check-certificate $newrepo$
exit $?

[PatchTextFile_add_repo_redhat]
AppendLine "[home_uibmz_opsi_opsi40]"
AppendLine "name=opsi 4.0 (CentOS_7)"
AppendLine "type=rpm-md"
AppendLine "baseurl=http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/CentOS_7/"
AppendLine "gpgcheck=1"
AppendLine "gpgkey=http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/CentOS_7/repodata/repomd.xml.key"
AppendLine "enabled=1"

[ShellInAnIcon_refresh_repo_redhat]
set -x
yum makecache
yum -y repolist
exit $?

4.7.5. Delete a repository

Listing 4. Ubuntu / Debian
[Actions]
DefVar $delrepo$
DefStringlist = $resultlist$

set $delrepo$ = "deb http://download.opensuse.org/repositories/home:/uibmz:/opsi:/opsi40/Debian_7.0/ ./"

if LineBeginning_ExistsIn($delrepo$, "/etc/apt/sources.list")
	PatchTextFile_del_repo_deb  "/etc/apt/sources.list"
	set $resultlist$ = shellCall("apt-get update")
endif

[PatchTextFile_del_repo_deb]
FindLine_StartingWith "$delrepo$"
DeleteTheLine
Listing 5. SUSE
[Actions]
DefVar $delrepo$

comment "$delrepo$ is the section name of the repo file in /etc/zypp/repos.d/"
comment "$delrepo$ can be found by zypper lr"
set $delrepo$ = "home_uibmz_opsi_opsi40"
ShellInAnIcon_del_opsi_repository_suse

[ShellInAnIcon_del_opsi_repository_suse]
set -x
zypper --non-interactive rr  $delrepo$
exit $?
Listing 6. CentOS / Redhat
[Actions]
DefVar $delrepo$

comment "$delrepo$ ist the name of the repo file in /etc/yum.repos.d"
set $delrepo$ = "/etc/yum.repos.d/home:uibmz:opsi:opsi40.repo"

[ShellInAnIcon_del_opsi_repository_redhat]
set -x
rm $delrepo$
yum makecache
yum -y repolist
exit $?

4.7.6. Installing a package

Generic for all supported distributions

A simple example:

[Actions]
importlib "uib_lin_install"

DefStringlist $packages$
DefVar $installresult$

comment "install new needed packages"
if waitForPackageLock("300", "false")
	comment "we got the package lock."
else
	LogError "could not get Package Lock"
endif

set $packages$ = CreateStringlist("lsb-release","cifs-utils","xterm")
set $installresult$ = genericLinInstall($packages$)
if not(stringtobool($installresult$))
	LogError "failed install packages"
	Message "failed install packages"
	isFatalError "failed dependent packages"
endif

A more sophisticated example:

[Actions]
importlib "uib_lin_install"

DefStringlist $packages$
DefVar $installresult$
DefStringlist $errorList$
DefVar $fatal_error$
DefVar $result_string$

if waitForPackageLock("300", "false")
	comment "we got the package lock."
else
	LogError "could not get Package Lock"
endif

comment "update and clean package system"
cleanupPackageSystem()

comment "install pending updates"
set $result_string$ = installupdates()

comment "install new needed packages"
set $packages$ = CreateStringlist("lsb-release","cifs-utils","xterm")
set $installresult$ = genericLinInstall($packages$)
if not(stringtobool($installresult$))
	if waitForPackageLock("300", "false")
		comment "we got the package lock."
	else
		LogError "could not get Package Lock"
	endif
	cleanupPackageSystem()
	set $installresult$ = debinstall($packages$)
	if not(stringtobool($installresult$))
		LogError "failed install packages"
		Message "failed install packages"
		;isFatalError "failed install packages"
		set $fatal_error$ = "true"
		set $errorList$ = addtolist($errorList$, " failed install packages")
	endif
endif

4.8. macOS specific functions

For macOS support there are the following special functions:

  • GetOS // 'Linux' or 'Windows_NT' or 'macos' [W/L/M] GetOS

  • getMacosVersionInfo [M] getMacosVersionInfo

  • getMacosVersionMap [M] getMacosVersionMap

  • getOSArchitecture // 'x86_32' or 'x86_64' or 'arm_64' [W/L/M] getOSArchitecture

  • chmod in Files sections [L/M] xref:chmod>>

  • importlib "uib_macosinstalllib" :

  • install_macos_app($myapp$ : string) : string [M]

  • install_macos_pkg($mypkg$ : string) : string [M]

  • install_macos_dmg($mydmg$ : string) : string [M]

  • install_macos_zip($myzip$ : string) : string [M]

  • install_macos_generic($myfile$ : string) : string [M]

The details to these library commands you will find here: Documentation of opsi library: uib_macosinstalllib.opsiscript

References to more macOS specific library functions you will find at: macOS specific functions

4.9. Example scripts for macOS

4.9.1. Run on macOS only

[Actions]
DefVar $OS$

set $OS$ = GetOS

if not ($OS$ = "macos")
	logError "Installation aborted: wrong OS version: only macOS allowed"
	isFatalError "wrong OS"
endif

4.9.2. Which macOS Version

The code:

Set  $macosinfomap$ = getMacosVersionMap

gives (for example) the 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

5. Start and Command Line Options

Since version 4.11.3, the opsi-script program contains at Windows a manifest with the statement:
<requestedExecutionLevel level="highestAvailable" />. This means that if opsi-script is called on an NT6 OS by an Administrator, then it will run as an 'elevated' process. If opsi-script is called with normal user privileges, then it will run with the privileges of this user.

If you start opsi-script without any parameter, it will start in the interactive mode.

opsi-script can be started with different sets of parameters depending on context and purpose of use.

Note

At Linux or macOS the parameter char is not "/" as here decribed for Windows but "-". So instaed of using opsi-script /help as we do on Windows, we use at Linux / macOS opsi-script -help.

Generic Options:

  • /? or /h[elp]
    Show help

  • /silent
    Run opsi-script without GUI

Execute one (or more) scripts:
opsi-script <scriptfile>[;<scriptfile>]* [<logfile>]
where:
<scriptfile> = Name of the script file (incl. path).
<logfile> = Name of the log file (incl. path). Paths to log files see also: Section 5.1

  • /parameter <parameterstring>
    A string that can be passed to the executed script and can be retrevaled by the command Paramstr.
    Hereby is <parameterstring> a string without whitespaces.

  • /logfile <logfile>
    Define the log file:
    Hereby is:
    <logfile> = Name of the log file (incl. path). Paths to log files see also: Section 5.1

  • /lang <lang>
    Define the localization:
    Hereby is:
    <lang> = The two char language abbreviation (de,en,fr,es,…​)

  • /batch
    Execute the given script with the batch GUI. The batch GUI has no possibility for user interaction. In combination with the option /silent there will be no GUI at all. If you call opsi-script without the option /batch the interactive GUI ist started, which is designed for development end testing purposes.

  • /productid <productId>
    For the use together with /servicebatch ; see overthere.

  • /servicebatch
    Execute the given script with the batch GUI and with a connection to the opsi web service. Thereby the given script will be executed as it would be if the opsi product given by the option /productid had the action request 'setup'.
    The script file has to be the first option.
    The option /opsiservice and its sub options has to be given.
    The option /productid has to be given. This one is used for the communication with the opsi web service to run the given script as it would be the 'setup-script' of the opsi product given with this option.

  • /logproductid <productId>
    While creating the log file the given <productId> should be used to note it as source of the log file.

  • /normalwindow
    Switches off the maximize if of the GUI in the not interactive mode.

  • /usercontext < [domain\]username >
    If the given user is loged in then opsi-script will try to resolve the constants like %CurrentAppdataDir%, %CurrentStartmenuDir%, %CurrentDesktopDir%, %CurrentStartupDir%, %CurrentProgramsDir%, %CurrentSendToDir%, %CurrentProfileDir% from the context of the given user.
    Mostly used together with the’User Profile Management' opsi extension.

  • /opsiservice <opsiserviceurl>
    /clientid <clientname>
    /username <username>
    /password <password>
    [/sessionid <sessionid>]
    [/credentialfile <credentialfile>]
    Give the connection data to connect to the opsi web service:
    Hereby you have to give either /clientid and /username and /password and also optional the /sessionid
    or you have to give this data via a /credentialfile.

Declare what should be done in the context of the connected /opsiservice

  • Default (none of the following parameters):
    Process the action requests as they stored for this client on the opsi-server.

  • /allloginscripts or /loginscripts
    Process the login scripts of the opsi products. Using /allloginscripts all login scripts that are known to the opsi-server will be processed, no matter iftheses products are known to the client or not. Using /loginscripts only these login scripts will be precessed that belong to products that are installed or were installed and then removed (technical: there is an existing productOnClient object).

  • /productlist <productid>[,<productid>]*
    Process the given /productlist in a way as it would normally done if there are the action request 'setup' is stored at the opsi-server.
    Usally used by the event_silent_install.

  • /processproducts <productid>[,<productid>]*
    Process the action requests as they stored for this client on the opsi-server but limited to the list of products given by /processproducts.

5.1. Log File and Paths

The default log file name is opsi-script.log. You may find (by default) up to 8 backup copys of old log files: from opsi-script_0.log until opsi-script_8.log.
The default number of backups may be overwritten by using the config: [opsi-script-configs_log_rotation_count]

The log file encoding is UTF-8.

By default log files are written at Windows into the directory c:\opsi.org\log which opsi-script tries to create. If opsi-script has no access to this directory it uses the user-TEMP directory.

At Linux: If running as root (default): /var/log/opsi-script If running as any other user: /tmp

The log file name and location will be overwritten via the specific command line option.

In the case, that opsi-script executes a script in /batch mode and with a specified (and working) usercontext, the default logging path is the opsi/tmp in the appdata directory of the user. This will be overwritten by an explicit given log path.

Beside the normal log file there is also a log file named opsi-script.history. This log file contains one line for every run of a product script since the first run. These lines have the pattern:
<timestamp> handled: <productid> Version: <version> Request: <request> Result: <result>
Example:
2022-01-18 00:09 handled : gimp Version: 2.10.30-1 Request: setup Result: success

5.2. Central configuration via opsi Configs (Host Parameter)

Using opsi Configs (Host-Parameter) you may now change the logging:

  • opsi-script.global.debug_prog : boolean
    If false log messages that are only relevant for debugging the opsi-script program it self are not written excepting Warnings and Errors.
    Default: false
    This will keep the log files smaller because you will find only messages that are relevant for understanding what your script is doing.
    The adjustment of all log messages to this new way is in progress and will be take a while since all (about 1700) log calls inside the code are reviewed.

  • opsi-script.global.debug_lib : boolean
    If false log messages from defined functions that are imported from external library files will be suppressed excepting Warnings and Errors.
    Default: false

  • opsi-script.global.default_loglevel : intstr
    Sets (overrides) the default log level that is imlemented inside the opsi-script code. This config has no effect on scripts where the loglevel is explicit set by a setLogLevel statement.
    Default: '6'
    see also SetLogLevel
    see also [opsi-script-configs_force_min_loglevel]

  • opsi-script.global.force_min_loglevel : intstr
    Forces a minimal log level.
    This can be used while debugging or development to set temporary and for selected clients a higher log level wthout changing the script. Default: '0'
    see also SetLogLevel
    see also [opsi-script-configs_default_loglevel]

  • opsi-script.global.ScriptErrorMessages : boolean
    This config overwrites the opsi-script internal default value for ScriptErrorMessages if opsi-script is running in the context of the opsi web service. If the value is true, syntactical errors trigger a pop up window with some informations on the error. This is in productive environments no good idea. Therefore the default value for this config is 'false'.
    Inside a script the statement ScriptErrorMessages may be used to set this different from the defaults.
    Default: false
    see also : ScriptErrorMessages

  • opsi-script.global.AutoActivityDisplay : boolean
    If true shows a marquee (endless) progressbar while external processes (winbatch/dosbatch sections) are running.
    Default: true
    see also : AutoActivityDisplay

  • opsi-script.global.SupressSystemEncodingWarning : boolean
    If true the warning: Encoding=system makes the opsiscript not portable between different OS will be supressed.
    Default: false
    see also: encoding

  • opsi-script.global.ReverseProductOrderByUninstall : boolean
    If true the product list is reordered so that uninstall actions will be conducted first and in reverse order as the prodcuts were installed
    Default: false

  • opsi-script.global.log_rotation_count : string (number) // seit 4.12.4.29
    Defines the number of opsi-script.log backups that will be stored in the log directory on the client. (opsi-script_0.log, opsi-script_1.log, …​)
    Default = 8 ; Max = 999

  • opsi-script.global.writeProductLogFile : boolean // seit 4.12.4.35
    If true logs for every single opsi product will be created. You will find these log in the sub directory lastprodlogs of the opsi-script log directory (E.g. c:\opsi.org\log\lastprodlogs). The name of these log files is <productId>.log. There is always only the last log for every product. If the product script contains reboots in (not after) the script, the log contains only the part after the last reboot.
    Default: false

6. Additional Configurations

6.1. Central Logging of Error Messages

If the opsi-script running in opsi web service mode, it sends the log file via opsi web service to the opsi server.

6.2. Skinnable opsi-script [W/L/M]

Since version 3.6 the opsi-script GUI can be customized. The elements for customizing are to be found in the winstskin subdirectory of the opsi-script directory. The configuration file for customization is skin.ini.

Since version 4.12.4.15 the opsi-script searches the skin directory in the following order (directory with the first skin.ini to be found wins):

Windows:

%OpsiScriptDir% = C:\Program Files (X86)\opsi.org\opsi-client-agent\opsi-script

  1. %OpsiScriptDir%\..\custom\customskin

  2. %OpsiScriptDir%\skin

  3. %OpsiScriptDir%\winstskin(for backward compatibility)

Linux:

%OpsiScriptDir% = /opt/opsi-script

  1. '/usr/share/opsi-script/skin'

  2. '/usr/share/opsi-script/customskin' (for backward compatibility)

  3. %OpsiScriptDir%/skin

macOS:

%OpsiScriptDir% = /Applications/opsi-script/Contents/macOS

  1. '/usr/share/opsi-script/skin'

  2. %OpsiScriptDir%/../Resources/skin

With the Command SetSkinDirectory the SkinDirectory to be used can be defined in the script. If the path specified is empty or not valid, the default path will be used.

Example:

SetSkinDirectory "%ScriptPath%\testskin"
sleepseconds 1
SetSkinDirectory ""
Adaptation to Corporate Identity

All graphical components of opsi-script are based on the display components applied for displaying graphics and thus adapted in the same way. Colors can be specified in three different ways: As a symbolic name (clRed), as a hexadecimal value ($FF00FF) or as rgb value list 255,0,0. A utility for selecting colors and their corresponding notation can be found in the following opsi color chooser.

As background graphic formats a wide array of different bitmap formats such as .bmp, .png, jpeg etc. can be utilized. All these formats are again container formats, i.e. PNG is not necessarily equal to PNG. It is possible that one is displayable and the other is not. A utility to quickly check if a given bitmap graphic will be displayed correctly can be also found at following opsi bitmap viewer.

The files that you can customize in opsi-script can be found in the directory /var/lib/opsi/depot/opsi-client-agent/files/opsi-script/skin:

bg.png +

The background graphic of 'opsi-script' in which the text messages as well as the product logos are displayed at runtime.

skin.ini +

The configuration file in which is specified in which font and color text messages are displayed.

Since opsi-script version 4.12.4.35 it’s possible to choose between two themes. If Theme = default, or nothing is specified the standard appearance of opsi-script is kept as previously known, still you have the following detailed setting possibilities over the skin.ini (here occupied with the delivered default values):

[Form]
Theme = default #this line can also be omitted here
Color = $00FFB359

[LabelVersion]
Left = 20
Top = 367
Width = 85
Height = 16
FontName = Arial
FontSize = 7
FontColor = $00E2A973
FontBold = false
FontItalic = false
FontUnderline = false

[LabelProduct]
Left = 260
Top = 100
Width = 315
Height = 100
FontName = Arial
FontSize = 32
FontColor = $00E7E7E7
FontBold = false
FontItalic = false
FontUnderline = false

[LabelInfo]
Alignment=Center
Left = 60
Top = 260
Width = 520
Height = 24
FontName = Arial
FontSize = 11
FontColor = $00E7E7E7
FontBold = true
FontItalic = false
FontUnderline = false

[LabelDetail]
Left = 60
Top = 285
Width = 520
Height = 20
FontName = Arial
FontSize = 8
FontColor = $00E7E7E7
FontBold = false
FontItalic = false
FontUnderline = false

[LabelCommand]
Left = 60
Top = 310
Width = 520
Height = 20
FontName = Arial
FontSize = 8
FontColor = $00E7E7E7
FontBold = false
FontItalic = false
FontUnderline = false

[LabelProgress]
Left = 60
Top = 335
Width = 520
Height = 40
FontName = Arial
FontSize = 8
FontColor = $00E7E7E7
FontBold = false
FontItalic = false
FontUnderline = false

[ActivityBar]
Left = 60
Top = 350
Width = 420
Height = 10
BarColor = clBlue

[ImageBackground]
File = bg.png

[ImageProduct]
File = product.png
Left = 40
Top = 65
Width = 160
Height = 160

[Image1Over]
File =
Left = 0
Top = 0
Width = 0
Height = 0

[Image2Over]
File =
Left = 0
Top = 0
Width = 0
Height = 0

[ProgressBar]
Left = 275
Top = 160
Width = 280
Height = 20
BarColor = $00E7E7E7
StartColor = $00E7E7E7
FinalColor = $00E7E7E7
ShapeColor = $00E7E7E7
Shaped = true
ShowFullBlock = false
RoundCorner = true
BlockSize = 10
SpaceSize = 3
Cylinder = true
Glass = true

Set Theme = WindowsSimple to only display a simple interface when installing opsi products. This is similar to the one used by Windows when installing OS updates. The following settings possibilities are available (here occupied with the delivered default values):

[Form]
Theme = WindowsSimple #This line is necessary here and may not be changed
Color = clHotLight

[LabelInfo]
Caption = Software is being installed. Please wait.
Protecting your changes from updates: The custom directory

In case you want to avoid changes being made to the files mentioned above when you install a new version of the opsi-client agent, you can do this using the custom directory /var/lib/opsi/depot/opsi-client-agent/files/custom (previously /var/lib/opsi/depot/opsi-client-agent/files/opsi/custom). The complete custom directory is saved and restored when a new version of the opsi-client agent is installed, so that the changes made here are not lost.

  • custom/opsi-script/skin/*.*
    The contents are copied to C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\skin when installing the opsi-client-agent on the client.

6.3. opsi-script encoding [W/L/M]

Some technical notes about the wording:

  • ASCII, plain ASCII
    ASCII stands for: American Standard Code for Information Interchange
    'plain ascii': 7 Bit / per char for 128 different chars. This will be found as base of the following.

  • ANSI, Codepages
    Using 8 Bit (Byte) / per char for 255 different chars. Lower 128 chars = ASCII, Upper 128 Chars according to selected 'Code page'. Well known 'code pages':
    Windows-1252 = CP1252 = ISO 8851-1 = Western Europe code page.
    The first 256 Chars of CP1252 are also part of Unicode.
    'ANSI' stands for American National Standards Institute:
    https://stackoverflow.com/questions/701882/what-is-ansi-format :
    'ANSI encoding is a slightly generic term used to refer to the standard code page on a system, ( …​ )The name "ANSI" is a misnomer, since it does not correspond to any actual ANSI standard, but the name has stuck.'
    So what is an an ANSI-String ?
    https://wiki.freepascal.org/Character_and_string_types#AnsiChar says:
    'A variable of type AnsiChar, also referred to as char, is exactly 1 byte in size, and contains one "ANSI" (local code page) character.'
    The problems with using code pages are:

    • You have to use different encoding in different places of the world.

    • Maximum 255 Chars can be coded, but some languages have a lot more characters.

  • Unicode, UTF-8
    'Unicode' is (like 'ANSI') a encoding family (and not a encoding). The most important difference to using code pages is, that here we use to encode one char (possibly) more than one byte (exactly: up to 4 bytes).
    The most important members of the Unicode family are:

    • UTF-16-LE (also some times called 'Windows Unicode'):
      Uses a minimum length of 2 Bytes per char up to 4 Bytes. The 'LE' stands for 'Little Endian' and tell us that the most significant byte of a char is the last one. (char 'n' : LE='6E 00', BE='00 6E')

    • UTF-8:
      Uses for the chars out of 'plain ASCII' one byte but for every thing else 2 up to 4 bytes.
      So in fact: a file that uses only plain ASCII is the same binary wether you save it in cp1252 or utf8.

    • BOM
      A file with 'Unicode' encoding may contain in the first 4 Bytes the information about the used (unicode-)encoding. This is the 'BOM' ('Byte Order Mark'). If there is a 'BOM', opsi-script will detect and use it.

The default encoding for a script is the encoding of the running operating system. So for example one script will be interpreted on a Greek windows system as encoded with cp1253 on a German windows system as cp1252 and under Linux as UTF-8.

We strongly recommend to create all your opsiscript files in UTF-8 encoding and add the line encoding=utf8 to the file.
This makes your files portabel.
See also below.

  • encoding=<encoding>
    Since Version 4.11.4.1 it is possible to define the encoding in the script. This may be done in the main script and in the sub scripts, includes and libraries as well. You have to give the command:
    encoding=<encoding>
    This command can be at any position in the code (Even before [actions]).
    If the command encoding= is missing, than the expected encoding is the system encoding of the running operating system. At Linux and macOS this would be UTF-8. At Windows the system encoding a cp* and depends on the localization. In Western Europe for example z.B. cp1252.
    If the input file contains umlauts (is not pure 'plain ASCII') and there is no line: encoding=utf8, then you will get a warning:
    'Encoding=system makes the opsiscript not portable between different OS'.
    This Warning may be suppressed by the config (Host Parameter):
    opsi-script.global.supresssystemencodingwarning = true.
    siehe auch opsi-script.global.ScriptErrorMessages

    If the input file contains umlauts (is not pure 'plain ASCII') and there is a discrepancy between the detected encoding (c.f. by a BOM) and the implicit encoding 'system' or the given encoding by encoding=, then you will get the following warning:
    'Warning: Given encodingString <> is different from the expected encoding <>'

    Using the command: encoding=<encoding>
    the <encoding> may be one of the following values:

Table 2. Encodings
encoding allowed alias Remark

system

use the encoding of the running OS

auto

try to guess the encoding

UTF-8

utf8

UTF-8BOM

utf8bom

Ansi

ansi

8 Bit encoding with Codepage

CP1250

cp1250

Central and East European Latin

CP1251

cp1251

Cyrillic

CP1252

cp1252

West European Latin

CP1253

cp1253

Greek

CP1254

cp1254

Turkish

CP1255

cp1255

Hebrew

CP1256

cp1256

Arabic

CP1257

cp1257

Baltic

CP1258

cp1258

Vietnamese

CP437

cp437

Original IBM PC hardware code page

CP850

cp850

"Multilingual (Latin-1)" (Western European languages)

CP852

cp852

"Slavic (Latin-2)" (Central and Eastern European languages)

CP866

cp866

Cyrillic

CP874

cp874

Thai

CP932

cp932

Japanese (DBCS)

CP936

cp936

GBK Supports Simplified Chinese (DBCS)

CP949

cp949

Supports Korean (DBCS)

CP950

cp950

Supports Traditional Chinese (DBCS)

ISO-8859-1

iso8859-1

Latin-1

ISO-8859-2

iso8859-2

Latin-2

KOI-8

koi8

Kyrillisches Alphabet

UCS-2LE

ucs2le

(UTF-16-LE, Windows Unicode Standard)

UCS-2BE

ucs2be

(UTF-16-BE)

7. The 'opsi-script' Script

On principle: 'opsi-script' is an interpreter for a specific, easy to use scripting language which is tailored for the requirements of software installations. A script should be an integrated description, and a means of control, for the installation of one piece of software.

The following section sketches the structure of a 'opsi-script' script. The purpose is to identify the book marks of a script: in which way we to have to look into it, to understand its processing.

All elements shall be described more in detail in the further section. The purpose then will be to show how scripts can be modified or developed.

7.1. An Example

'opsi-script' scripts are roughly derived from .INI files. They are composed of sections, which are marked by a title (the section name) which is written in brackets [].

Schematically a 'opsi-script' script looks like this one (here with a check which operating system is installed):

[Actions]
Message "Installation of Mozilla"
SetLogLevel=6

;which Windows-Version?
DefVar $MSVersion$

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

[sub_install_winnt6]
Files_copy_winnt6
WinBatch_Setup

[Files_copy_winnt6]
copy "%scriptpath%\files_win10\*.*" "c:\temp\installation"

[WinBatch_Setup]
c:\temp\installation\setup.exe

How can we read the sections of this script?

7.2. Primary and Secondary Subprograms of a 'opsi-script' script

The script as a whole serves as a program, an instruction for an installation process. Therefore each of its sections can be seen as a a subprogram (or "procedure" or "method"). The script is a collection of subprograms.

The human reader as well as an interpreting software has to know at which element in this collection reading must start.

Execution of a 'opsi-script' script begins with working on the [Actions] section. All other sections are called as subroutines. This process is only recursive for Sub sections: Sub sections have the same syntax as Actions sections and may contain calls for further subroutines.

If a script is run as 'userLoginScript' and it contains a section [ProfileActions], so the script interpretation will be started at the ProfleActions section.

This gives reason to make the distinction between primary and secondary subprograms:

The primary or general control sections comprise

  • the Actions section

  • Sub sections (0 to n subroutines called by the Actions section which are syntactical and logical extensions of the calling section).

  • the ProfileActions section, which will be interpreted in different ways according to the script mode (Machine/Login).

The procedural logic of the script is determined by the sequence of calls in these sections.

The secondary or specific sections can be called from any primary section but have a different syntax. The syntax is derived from the functional requirements and library conditions and conventions for the specific purposes. Therefore no further section can be called from a secondary section.

At this moment there are the following types of secondary sections:

  • Files sections,

  • WinBatch sections,

  • DosBatch/DosInAnIcon/ShellInAnIcon sections,

  • Registry sections

  • Patches sections,

  • PatchHosts sections,

  • PatchTextFile sections,

  • XMLPatch sections (discouraged),

  • XML2-Sektionen,

  • LinkFolder sections,

  • opsiServiceCall sections,

  • ExecPython sections,

  • ExecWith sections,

  • LDAPsearch sections.

Meaning and syntax of the different section types are treated in Syntax and Meaning of Primary Sections of a opsi-script Script and Secondary Sections.

7.3. String Expressions in a opsi-script Script

Textual values (string values) in the primary sections can be given in different ways:

  • A value can be directly cited, mostly by writing in into (double) citation marks. Examples:
    '"Installation of Mozilla"'
    '"n:\home\user name"'

  • A value can be given by a String variable or a String constant, that "contains" the value:
    The variable '$MsVersion$' may stand for "6.1" – if it has been assigned beforehand with this value.

  • A function retrieves or calculates a value by some internal procedure. E. g. EnvVar ("Username")
    fetches a value from the system environment, in this case the value of the environment variable 'Username'. Functions may have any number of parameters, including zero:
    GetMsVersionInfo
    On a win7 system, this function call yields the value "6.1" (not as with a variable this values has to be produced at every call again).

  • A value can be constructed by an additive expression, where string values and partial expressions are concatenated - theoretically "plus" can be seen as a function of two parameters:
    '$Home$ + "\mail"'

There is no analogous way of using string expressions in the secondary sections. They follow there domain specific syntax. e.g. for copying commands similar to the windows command line copy command. Up to this moment it is no escape syntax implemented for transporting primary section logic into secondary sections.

The only way to transport string values into secondary sections is the use of the names of variables and constants as value container in these sections. Lets have a closer look at the variables and constants of a 'opsi-script' script:

8. Definition and Use of Variables and Constants in a opsi-script Script

8.1. General

In a opsi-script script, variables and constants appear as "words", that are interpreted by opsi-script and "contain" values. "Words" are sequences of characters consisting of letters, numbers and some special characters (in particular ".", "-", "_", "$", "%"), but not blanks, but no brackets, parentheses, or operator signs ("+") .

opsi-script variables and constants are not case-sensitive.

There exist the following types of variables or constants:

  • Global text constants, shortly constants,
    contain values which are present by the opsi-script program and cannot be changed in a script. Before interpreting the script opsi-script replaces each occurrence of the pure constant name with its value in the whole script (textual substitution).
    An example will make this clear:
    The constant %ScriptPath% is the predefined name of the location where opsi-script found and read the script that it just executes. This location may be, e.g., p:\product. Then we have to write
    "%ScriptPath%"
    in the script when we want do get the value
    "p:\product".

    • observe the citations marks which include the constant delimiter.

  • Text or String variables, shortly variables,
    have an appearance very much like any (String) variables in a common programming language. They must be declared by a DefVar statement before they can be used. In primary sections, values can be assigned to variables (once ore more times). They can be used as elements in composed expressions (like addition of strings) or as function arguments.
    But they freeze in a secondary section to a phenomenon that behaves like a constant. There, they appear as a non-syntactical foreign element. Their value is fixed and is inserted by textual substitution for their pure names (when a section is called, whereas the textual substitution for real constants take place before starting the execution of the whole script).

  • Stringlist variables
    are declared by a DefStringList statement. In primary sections they can be used for many purposes, e.g. collecting strings, manipulating strings, building sections.

In detail:

8.2. Global Text Constants

Scripts shall work in a different contexts without manual changes. The contexts can be characterized by system values as OS version or certain paths. opsi-script introduces such values as constants into the script.

8.2.1. Usage

The fundamental characteristics of a text constant is the way how the values which it represents come intro the script interpretation process:

The name of the constant, that is the pure sequences of chars, is substituted by its fixed value in the whole script before starting the script execution.

The replacement does not take into account any syntactical context in which the name possibly occur (exactly like with variables in secondary sections).

8.2.2. Example

opsi-script implements constants %ScriptPath% for the location of the momentarily interpreted script and %System% for the name of the windows system directory. The following (Files) subsection defines a command that copies all files from the script directory to the windows system directory:

[files_do_my_copying]
copy "%ScriptPath%\system\*.*" "%System%"

At this moment the following constants are implemented:

8.2.3. System paths

Base system directories [W]

%ProgramFilesDir%: 'c:\program files'

%ProgramFiles32Dir%: 'c:\Program Files (x86)'

%ProgramFiles64Dir%: 'c:\program files'

%ProgramFilesSysnativeDir% : 'c:\program files'

%Systemroot% : 'c:\windows'

%System% : 'c:\windows\system32'

%Systemdrive% : 'c:'

%ProfileDir% : 'c:\Users'

Common (AllUsers) directories [W]

%AllUsersProfileDir% or %CommonProfileDir% : 'C:\Users\Public'

%CommonStartMenuPath% or %CommonStartmenuDir% : 'C:\ProgramData\Microsoft\Windows\Start Menu'

%CommonAppdataDir% : 'C:\ProgramData'

%CommonDesktopDir%

%CommonStartupDir%

%CommonProgramsDir%

Contstant

Win7 - Win10 (NT6)

%AllUsersProfileDir%

C:\Users\Public

%CommonProfileDir%

C:\Users\Public

%CommonStartMenuPath%

C:\ProgramData\Microsoft\Windows\Start Menu

%CommonAppDataDir%

C:\ProgramData

%CommonDesktopDir%

C:\Users\Public\Desktop

%CommonStartupDir%

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

%CommonProgramsDir%

C:\ProgramData\Microsoft\Windows\Start Menu\Programs

%AllUsersProfileDir%

C:\Users\Public

%DefaultUserProfileDir%

C:\Users\Default

%ProfileDir%

C:\Users

%Systemroot%

C:\Windows

%System%

C:\Windows\system32

Default User Directory [W]

%DefaultUserProfileDir%

Current (logged in or usercontext) user directories [W]

%AppdataDir% or %CurrentAppdataDir% : //since 4.10.8.13
NT6: 'c:\users\%USERNAME%\Appdata\Roaming'

%CurrentStartmenuDir%

%CurrentDesktopDir%

%CurrentStartupDir%

%CurrentProgramsDir%

%CurrentSendToDir%

%CurrentProfileDir% //since 4.11.2.1

/AllUserProfiles (/AllNtUserProfiles) directory constants [W]

In 'Files' sections that are called with option /AllUserProfiles there is a pseudo variable
%UserProfileDir%
When the section is executed for each user that exists on a work station this variable represents the name of the profile directory of the user just treated.
The parameter /AllUserProfiles exits since 4.12.4.27. The use of the older and still working synonym /AllNTUserProfiles is discouraged.

%CurrentProfileDir% // since 4.11.2.1
may be used instead of the older %UserProfileDir% in order to have Files-sections which may be used also for 'userLoginScripts'.

%UserProfileDir% or %CurrentProfileDir%
NT6: 'c:\users\%USERNAME%'

8.2.4. opsi-script Path and Directory [W/L/M]

%ScriptPath% or %ScriptDir% : represents the path of the current opsi-script script (without closing backslash). Using this variable we can build path and file names in scripts that are relative to the location of the script. So, everything can be copied, called from the new place, and all works as before.

%RealScriptPath% : If the script is called via symlink then it is the resolved version of %scriptpath% else it is the same as %ScriptPath% (since 4.12.4.21)

%ScriptDrive% : The drive where the just executed opsi-script script is located (including the colon).

%OpsiScriptDir% (since 4.12.3.6)
The location (without closing backslash) of the running opsi-script.
Identic with the outdated form: %WinstDir%

%OpsiscriptVersion% (since 4.12.3.6)
Version string of the running opsi-script.
Identic with the outdated form: %WinstVersion%

%opsiscriptProcname% (since 4.12.4.35)
Name of the running opsi-script process.
Can be used in combination with isProcessChildOf

%Logfile% : The name of the logfile which opsi-script is using.

%opsiTmpDir% // since 4.11.4.3
Directory which should be used for temporary files. (At Windows: c:\opsi.org\tmp)

%opsiUserTmpDir% // since 4.12.4.37
Directory which should be used for temporary files and for which you do not need administrator privileges. (At Windows: c:\opsi.org\usertmp)

%opsiLogDir% // since 4.11.4.3
Directory which should be used for log files. (At Windows: c:\opsi.org\log)

%opsiScriptHelperPath%
Corresponds to: %ProgramFiles32Dir%\opsi.org\opsiScriptHelper
Path in which the help program, libraries, and items needed for script execution could be installed.
Since 4.11.3.2

%opsidata% // since 4.12.0.12
Directory which should be used for opsi data files (e.g. disks, partitions). (At Windows: c:\opsi.org\data)

%opsiapplog% // since 4.12.0.12
Directory which should be used for log files from programs that running in the user context. (At Windows: c:\opsi.org\applog)

Example:
The code:

message "Testing constants: "+"%"+"OpsiscriptVersion" +"%"
set $ConstTest$ = "%OpsiscriptVersion%"
if $OS$ = "Windows_NT"
	set $InterestingFile$ = "%Opsiscriptdir%\opsi-script.exe"
	if not (FileExists($InterestingFile$))
		set $InterestingFile$ = "%Opsiscriptdir%\winst32.exe"
	endif
	set $INST_Resultlist$ = getFileInfoMap($InterestingFile$)
	set $CompValue$ = getValue("file version with dots", $INST_Resultlist$ )
	if ($ConstTest$ = $CompValue$)
		comment "passed"
	else
		set $TestResult$ = "not o.k."
		LogWarning "failed"
	endif
endif

results to the following log:

message Testing constants: %OpsiscriptVersion%
Set  $ConstTest$ = "4.12.4.27"
  The value of the variable "$ConstTest$" is now: "4.12.4.27"
If
  $OS$ = "Windows_NT"   <<< result true
Then
  Set  $InterestingFile$ = "C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\opsi-script.exe"
    The value of the variable "$InterestingFile$" is now: "C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\opsi-script.exe"
  If
      Starting query if file exists ...
    FileExists($InterestingFile$)   <<< result true
    not (FileExists($InterestingFile$))   <<< result false
  Then
  EndIf
  Set  $INST_Resultlist$ = getFileInfoMap($InterestingFile$)
    The value of the variable "$INST_Resultlist$" is now:
    (string   0)Language name 0=Englisch (Vereinigte Staaten)
    (string   1)Language ID 0=1033
    (string   2)file version=1125951446712347
    (string   3)file version with dots=4.12.4.27
    (string   4)product version=1125908496777216
    (string   5)Comments=Compiled with Lazarus 2.2.0 / FPC 3.2.2
    (string   6)CompanyName=uib gmbh
    (string   7)FileDescription=opsi-script
    (string   8)FileVersion=4.12.4.27
    (string   9)InternalName=opsi-script
    (string  10)LegalCopyright=AGPL v3
    (string  11)LegalTrademarks=opsi, opsi.org, open pc server integration
    (string  12)OriginalFilename=opsi-script
    (string  13)PrivateBuild=
    (string  14)ProductName=opsi
    (string  15)ProductVersion=4.2
    (string  16)SpecialBuild=
  Set  $CompValue$ = getValue("file version with dots", $INST_Resultlist$ )
    The value of the variable "$CompValue$" is now: "4.12.4.27"
  If
    $ConstTest$ = $CompValue$   <<< result true
    ($ConstTest$ = $CompValue$)   <<< result true
  Then
    comment: passed
  Else
  EndIf
EndIf

8.2.5. Network Information [W/L/M]

%Host% : (discouraged) The value of a environmental variable host (traditionally meaning the opsi server name, not to confuse with %HostID% (meaning the client network name).

%PCName%: The value of the environmental variable PCName, when existing. Otherwise the value of the environmental variable computername. (Should be the netbios name of the PC)

%IPName% : The dns name of the pc. Usually identical with the netbios name and therefore with %PCName% besides that the netbios names uses to be uppercase.

%IPAddress% : (discouraged) may be the IP-Address of the machine. Use function GetMyIpByTarget() instead.
see also : GetMyIpByTarget

%Username% : Name of the logged in user.

8.2.6. Data for and from opsi service [W/L/M]

%HostID% : FQDN of the client in opsi service context (as it is supplied e.g. from the command line), otherwise the computer name.
If running in opsi service context it is better to use %opsiserviceUser%.

%FQDN% : FQDN of the computer in network (not opsi service) context

%opsiserviceURL% : The (usually https://) URL of the opsi service.(https://<opsiserver>:4447)

%opsiServer% : The server name derived from the %opsiserviceURL%.

%opsiDepotId% : Depot Server (FQDN) //since 4.11.4

%opsiserviceUser% : The user ID for which there is a connection to the opsi service. If running in opsi service context this is usally the clint FQDN used by opsi.

%opsiservicePassword% : The user password used for the connection to the opsi service. The password is eliminated when logging by the standard opsi-script logging functions.

%installingProdName%: The 'productid' of the product that is actually installed via call by the opsi-service. Empty if the Script ist not started by the opsi-service.

%installingProdVersion%: A String combinated from <productversion>-<packageversion> for the product that is actually installed via call by the opsi-service. Empty if the Script ist not started by the opsi-service.

%installingProduct% : (discouraged) The name (productId) of the product for which the service has called the running script. In case that there the script is not run via the service the String is empty.

8.3. String (or Text) Variables [W/L/M]

8.3.1. Declaration

String variables must be declared before they can be used. Since 4.12.4.32 it is also possible to pass an optional inital value. The syntax for the declaration reads

DefVar <variable name> [= <inital value>]

e.g.

DefVar $MsVersion$
; since 4.12.4.32 also possible:
DefVar $MsVersion$ = '10.0'

Explanation:

  • Variable names do not necessarily start or end with a dollar sign, but this is strongly recommended as a convention to avoid problems by the replacement of variable names by their value in secondary sections.

  • Variables can only be declared in primary sections (Actions section, sub sections and ProfileActions).

  • The declaration should not depend on a condition. That is it should not placed into a branch of an if – else statement. Otherwise, it could happen that the DefVar statement is not executed for a variable, but an evaluation of the variable is tried in some if clause (such producing a syntax error).

  • The variables are initialized with an empty string ("").

Recommendation:

  • The first and last letter of the name should be '$'.

  • Define all variables at the beginning of the script.

8.3.2. Value Assignment

As it is appropriate for a variable, it can take on one value resp. a series of values while a script is progressing. The values are assigned by statements with syntax

Set <Variablenname> = <Value>

<Value> means any (String valued) expression.

Examples (For Examples see String Values, and String Functions):

Set $OS$ = GetOS
Set $WinVersion$ = "unknown"

if $OS$ = "Windows_NT"
  Set $WinVersion$ = GetMsVersionInfo
endif

DefVar $Home$
Set $Home$ = "n:\home\user name"
DefVar $MailLocation$
Set $MailLocation$ = $Home$ + "\mail"

8.3.3. Use of variables in String expressions

In primary sections of a opsi-script script, a variable "holds" a value. When it is declared it is initialized with the empty String "". When a new value is assigned to it via the set command, it represents this value.

In a primary section a variable can replace any String expression resp. can be a component of a String expression, e.g.

Set $MailLocation$ = $Home$ + "\mail"

In a primary section the variable name denotes an object that represents a string, If we add the variable we mean that the underlying string shall be added somehow.

This representational chain is shortcut in a secondary section. Just the variable name now stands for the string.

8.3.4. Secondary vs. primary sections

When a secondary section is loaded and opsi-script starts its interpretation the sequence of chars of a variable name is directly replaced by the value of the variable.

Example:
A copy command in a files section shall copy a file to
"n:\home\user name\mail\backup"
kopiert werden.

We first set $MailLocation$ to the directory above it:

DefVar $Home$
DevVar $MailLocation$
Set $Home$ = "n:\home\user name"
Set $MailLocation$ = $Home$ + "\mail"

$MailLocation$ is now holding
"n:\home\user name\mail"

In a primary section we may now express the directory
"n:\home\user name\mail\backup"
by
$MailLocation$ + "\backup"

The same directory has to be designated in a secondary section as:
"$MailLocation$\backup"

A fundamental difference between the thinking of variables in primary vs. secondary sections is that, in a primary section, we can form an assignment expression like
$MailLocation$ = $MailLocation$ + "\backup"

As usual, this means that $MailLocation$ first has some initial value and takes on a new value by adding some string to the initial value. The reference from the variable is dynamic, and may have a history.

In a secondary section any such expression would be worthless (and eventually wrong), since $MailLocation$ is bound to be replaced by some fixed string (at all occurrences virtually in the same moment).

8.4. Stringlist Variables [W/L/M]

Variables for string lists must be declared in a DefStringList statement. Since 4.12.4.32 it is also possible to pass an optional inital value. The syntax for the declaration reads

DefStringList <VarName> [= <inital value>]

DefStringList $MsVersionList$
; since 4.12.4.32 also possible:
DefStringList $MsVersionList$ = '["6.1","10.0"]'

A string list can serve e.g. as container for the captured output of a shell program. The collected strings can be manipulated in a lot of ways. In detail this will be treated in the section on string list processing (see String List Functions and String List Processing).

9. Syntax and Meaning of Primary Sections of a opsi-script Script [W/L/M]

As shortly presented in chapter Primary and Secondary Subprograms of a opsi-script script the Actions section of a script can be regarded as a the main method of the opsi-script script and describes the global processing sequence. It may call subroutines - the Sub sections which may then recursively call Sub sections themselves.

The following sections explain syntax and use of the primary sections of a opsi-script script.

9.1. Primary Sections [W/L/M]

There are possibly three kinds of primary sections in a script

  • an Initial section (may be omitted),

  • an Action section,

  • any number of Sub sections

  • an ProfileActions section

Initial and Action section are syntactically equivalent (but Initial has to keep the first place). By convention, in the Initial section some parametrizations of the script execution (e.g. the loglevel) are made. The Action section can be regarded as the main program in a opsi-script script. It contains the sequence of actions that are controlled by the script.

Sub sections are as well syntactically equivalent. But they are a called from the Action section. Then, they can call themselves Sub sections.

A Sub section is determined by creating a name that begins with "Sub", e.g. Sub_InstallBrowser. By writing its name in the Action section we produce a call to the Sub section. The meaning of this call is defined by the content of the section in the script that begins with the bracketed name, in the example [Sub_InstallBrowser]

Subsections of second and higher order cannot host internal sections. Instead, their procedure calls must refer to sections defined in the main script file or defined as external sections (cf. Subprogram Calls).
If (nested) sub sections are externalized to external files, the called sections has to be in that file where they are called from. According to the complexity of the script they may sometimes have to be placed also in the main file.

A ProfileActions section at a normal installation script may be used as a sub section with a special syntax. In a 'userLoginScript' this section will be used as script start (instead of Actions). See chapter 'User Profile Management' at the opsi-manual and Commands for userLoginScripts / User Profile Management.

9.2. Parametrizing opsi-script [W/L/M]

9.2.1. Specification of Logging Level [W/L/M]

The old function LogLevel= is discouraged since opsi-script version 4.10.3. For backward compatibility reasons Loglevels ste by this old function will be increased by 4 before they are used.

There are two syntactical variants for specifying the logging level:

  • SetLogLevel = <number>

  • SetLogLevel = <String expression>
    I.e. the number can be given as an integer value or as a string expression (cf. String Expressions, String Values, and String Functions). In the second case, opsi-script tries to evaluate the string expression as a number. There exist ten levels from 0 up to 9.

0 = nothing (absolute nothing)
1 = essential ("essential information")
2 = critical (unexpected errors that my cause a program abort)
3 = error (Errors that don't will abort the running program)
4 = warning (you should have a look at this)
5 = notice (Important statements to the program flow)
6 = info (Additional Infos)
7 = debug (important debug messages)
8 = debug2 (a lot more debug informations and data)
9 = confidential (passwords and other security relevant data)

The logging at the different log levels is:

  • Log level 5:
    comments,messages, Execution of sections

  • Log level 6:
    Statements, New values for stringvars , results of complete boolean expression

  • Log level 7:
    new values for stringlist vars, output from external processes (shellInAnIcon) if the out put is not assinged to a stringlist variable, results of parts of a boolean expression

  • Log level 8:
    other stringlist output eg. string lists from stringlist functions and output from external processes (shellInAnIcon) that is assinged to a stringlist variable.

The default value is "7".
see also : opsi-script-configs_default_loglevel see also : opsi-script-configs_force_min_loglevel

9.2.2. Logdatei im Append-Mode senden

forceLogInAppendMode = <boolean value> //since 4.12.3.6 (default=false); if true, log will be send in append mode

9.2.3. Required opsi-script Version [W/L/M]

The statement

requiredOpsiscriptVersion <RELATION SYMBOL> <NUMBER STRING>

since 4.12.3.6

e.g.

requiredOpsiscriptVersion >= "4.12.3.6"

makes opsi-script check if the desired version state is given. Otherwise an error message windows pops up or is written to the log and the script result is failed.

There is no default.
A identical but outdated version is (since 4.3):
requiredWinstVersion <RELATIONSSYMBOL> <ZAHLENSTRING>

9.2.4. Reacting on Errors [W/L/M]

There are two kinds of errors which are treated in different ways:

  1. illegal statements which cannot be interpreted by opsi-script (syntactical errors),

  2. failing statements which cannot be executed because of external, objective reasons (execution errors).

In principal, syntactical errors lead to a 'script is failed' situation, execution errors are logged in a log file to be analysed later.

The behaviour of opsi-script when it recognizes a syntactical error is defined by the configuration statement

  • ScriptErrorMessages = <boolean value>
    If the value is true (default), syntactical errors trigger a pop up window with some informations on the error.
    The boolean value may be 'true' or 'false'. Delimiters 'on' or 'off' can be used as well.
    Default=true
    see also: opsi-script-configs_ScriptErrorMessages

  • FatalOnSyntaxError = <boolean value>

    • 'true' = (default) If a syntax error occurs, then the script execution will be stopped and the script result will be set to 'failed'. Also, the message 'Syntax Error' will be passed to the opsi-server.

    • 'false' = If a syntax error occurs, then the script execution will not be stopped and the script result will be set to 'success'.

In either case above, the syntax error will be logged as 'Critical'.
In either case above, the error counter will be increased by 1.
Since 4.11.3.2
In older versions there was no logging of syntax errors, no increase of error counter, and the result was always set to 'success'.

  • FatalOnRuntimeError = <boolean value>
    A Runtime Error is an script logic error that leads to an forbidden or impossible operation. An Example: You try to get the 5th string from a string list that have only 3 elements.

    • 'true' = If a runtime error occurs, then the script execution will be stopped and the script result will be set to 'failed'. Also, the message 'Runtime Error' will be passed to the opsi-server.

    • 'false' = (default) If a runtime error occurs, then the script execution will not be stopped and the script result will be set to 'success'. The runtime error will be logged as 'Error' and the error counter will be increased by 1.
      Since 4.11.4.3

There two configuration options for execution errors.

  • ExitOnError = <boolean value>
    This statement defines if the script execution shall terminate when an error occurs. If the value is true or yes the program will stop execution, otherwise errors are just logged (default).

  • TraceMode = <boolean value>
    In TraceMode (default false) every log file entry will additionally be shown in message window with an O.K. button.

9.2.5. Staying On Top [W]

  • StayOnTop = <Wahrheitswert>

With StayOnTop = true (or = on) we request, that - in batch mode - the opsi-script window be on top on the windows which share the screen. That means it should be visible in the "foreground" as long as no other window having the same status wins.

According to the system manual the value cannot be changed while the program is running. But it seems that we can give a new value to it once.

StayOnTop has default false in order to avoid that some other process raises an error message which eventually can not be seen if opsi-script keeps staying on top.

9.2.6. Show window mode / Skin / Activity [W/L/M]

  • SetSkinDirectory <skindir> // [W/L/M]
    Sets the skin directory to use and loads the skin. If this command is used wit an empty or invalid path, the default skin dir is used. The default skin dir %OpsiScriptDir%\skin.

Example:

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

To change the modes of how the opsi-script window is displayed, use these commands:

  • NormalizeWinst
    Sets the opsi-script window to the 'normal' mode

  • IconizeWinst
    Sets the opsi-script window to the 'minimized' mode

  • MaximizeWinst //since 4.11.5
    Sets the opsi-script window to the 'maximized' mode

  • RestoreWinst
    Sets the opsi-script window to the mode before the last change

  • AutoActivityDisplay = <boolean value> // (default=false) //since 4.11.4.7
    If true shows a marquee (endless) progressbar while winbatch/dosbatch sections are running.
    see also: AutoActivityDisplay

9.2.7. Reloading the product list [W/L/M]

  • reloadProductList //since 4.12.6.1
    Reloads the product list from the opsi-server after executing the script in opsi-script. If the product list is not empty, opsi-script will process it again. loadProductList can be placed anywhere in the Actions section of the script. However, the recommendation is, according to logic, to put the command at the end of the section.

9.3. String Expressions, String Values, and String Functions [W/L/M]

A String expression can be

  • an elementary String value

  • a nested String value

  • a String variable

  • the concatenation of other String expressions

  • a String valued function call

9.3.1. Elementary String Values

An elementary String value is any sequence of characters that is enclosed in double or single citations marks, formally:

'"<sequence of characters>"'

or

''<sequence of characters>''

Example:

DefVar $ExampleString$
Set $ExampleString$ = "my Text"

9.3.2. Strings in Strings (Nested String Values)

If the sequence of chars itself contains citation marks we have to use the other kind of citation marks to enclose it:

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

If the sequence of chars is containing both kinds of citation marks we must use the following special expression:
EscapeString: <sequence of characters>
E.g. we can write:

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

Then the variable $Meta_citation$ will exactly contain the complete sequence of chars that follows the colon after "EscapeString" (including the blank). Such, $Meta_citation$ will contain the complete statement:
Set $citation$ = 'he said "Yes"'

9.3.3. String Concatenation

String concatenation is written using the addition sign ("+")

<String expression> + <String expression>

Example:

DefVar $String1$
DefVar $String2$
DefVar $String3$
DefVar $String4$
Set $String1$ = "my text"
Set $String2$ = "and"
Set $String3$ = "your text"
Set $String4$ = $String1$ + " " + $String2$ + " " + $String3$

$String4$ then has value "my text and your text".

9.3.4. String Variables

A String variable in a primary section "contains" a String value. In an String expression, it can always substitute an elementary string. For how to define and set String variables cf. String (or Text) Variables.

The following sections present the variety of string functions.

9.3.5. String Functions which Return the OS Type

  • GetOS : string [W/L/M]
    The function tells which type of operating system is running.
    GetOS` returns one of the following values:

    • "Windows_NT" (including Windows 2000 to Windows 10)

    • "Linux"

    • "macos"

  • GetNtVersion [W]
    Deprecated - please use use GetMSVersionInfo.
    A Windows NT operating system is characterized by a the Windows type number and a subtype number. GetNtVersion returns the precise subtype name. Possible values are
    "NT3"
    "NT4"
    "Win2k" (Windows 5.0)
    "WinXP" (Windows 5.1)
    "Windows Vista" (Windows 6)
    If the NT operating system has higher versions as 6 or there are version not explicitly known the function returns "Win NT" and the complete version number (5.2, …​ resp. 6.0 ..) . E.g. for Windows Server 2003 R2 Enterprise Edition, we get
    "Win NT 5.2"
    If the operating system is no Windows NT system the function returns the error value
    "No OS of Windows NT type"

  • GetMsVersionInfo [W]
    returns for systems of type Windows NT the Microsoft version info as indicated by the API, e.g. a Windows 7 system produces the result
    "6.1"

Table 3. Windows Versions
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

see also GetMSVersionMap

  • GetMsVersionName [W] // since 4.12.4.35
    returns for Windows systems the marketing version info, e.g. a Windows 7 system produces the result: "7.0". Window 11 gives "11.0".

Table 4. 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

see also GetMSVersionMap
see also GetMsVersionInfo

  • getLinuxDistroType : string [L]
    returns the type of the running Linux distribution an can be used to determine which general syntax we have to use. It may return one of the following values

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

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

    • 'suse' (→ use zypper) (see getLinuxVersionMap) [L]

  • getMacosVersionInfo : string //macOS Version Information //since 4.12.1.0 [M]
    (see getMacosVersionMap) [M]

  • GetSystemType : string [W/L/M]
    checks the installed OS if it can be assumed that the system is 64 Bit. In this case the value is '64 Bit System' otherwise 'x86 System'.

  • getOSArchitecture // OS Architecture //since 4.12.4.17 checks the installed OS for the processor architecture it is build for. Possible values are:

    • 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)

9.3.6. String Functions for Retrieving Environment or Command Line Data [W/L/M]

  • EnvVar (<environment variable>`) : string` [W/L/M]
    The function reads and returns the momentary value of a system environment variable. E.g., we can retrieve which user is logged in by EnvVar ("Username").

  • ParamStr [W/L/M]
    The function passes the the parameter string of the opsi-script command line i.e. the command line parameter which is indicated by /parameter. If there is no such parameter ParamStr returns the empty string.

  • getLastExitCode : string (exitcode) [W/L/M]
    returns a string that contains the value of the exitcode of the last process called by a WinBatch / DosBatch / ExecWith section.
    When using a DosBatch or ExecWith section, you will normally get the exitcode from the interpreter that was called. To get the exitcode of your script, you have to define it explicitly.

Example:

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

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

  • GetUserSID(<Windows Username>`)` [W]
    returns the SID for a given user (possibly with domain prefix in the form DOMAIN\USER).

  • GetUsercontext [W]
    returns the string which was given to the opsi-script by the optional parameter /usercontext. IF this parameter was not userd the returned string is empty.

9.3.7. Reading Values from the Windows Registry and Transforming Values into Registry Format [W]

  • getRegistryValue (<keystr>, <varstr> ) : string //since 4.12.0.16 [W]
    tries to use <keystr> as Registry key and open it and read there the variable <varstr> and return the value of this variable as a string.
    If there is no registry key <keystr> or the variable <varstr> does not exist the function produces a warning message in the log file and returns the empty string.
    If <varstr> is an empty string, the default entry of the key will be returned.
    By Default the registry access mode is sysnative. Using the optional third parameter <access str>, the access mode can be explicitly given. In this case it has to be one of the following values: 32bit, sysnative, 64bit.
    (see also: Chapter 64 Bit)

Example:

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

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

  • GetRegistrystringvalue(`"[key] var") : string` [W]
    This command is discouraged, please use: getRegistryValue
    tries to interpret the passed String value as an expression of format
    '[KEY] X'
    Then, the function tries to open the registry key KEY, and, in case it succeeds, to read and return the String value that belongs to the registry variable name X .

E.g.

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

usually yields "Explorer.exe", the default Windows shell program.

If there is no registry key KEY or the variable X does not exist the function produces a warning message in the log file and returns the empty string.

For example: If we made a 'standard entry' with the value standard entry at the key HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\opsi-script-test\test-4.0, we will get with

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

the following log:

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>`)`
    is useful for transforming path names into the format which is used in the Windows registry. That is, any backslash is duplicated. E. g.,

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

yields
'"c:\\windows\\system\\"'

  • which(<command string>`) : string` //since 4.12.3.6 [W/L/M]
    returns the complete path to the given <command string> (if <command string> is in the search path) Just like the well known Unix command 'which'.

9.3.8. Reading Values from ini files [W/L/M]

For historical reasons, there are three functions for reading values from configuration files which have ini file format. Since opsi 3.0 the specific product properties are retrieved from the opsi configuration demon (that may fetch it from a configuration file or from any other backend data container).

In detail:
Ini file format means that the file is a text file and is composed of "sections" each containing key value pairs:

[section1]
Varname1=Value1
Varname2=Value2
...
[section2]
...

The most general function reads the value belonging to some key in some section of some ini file. Any parameter can be given as an arbitrary String expression:

  • GetValueFromInifile (<file path>, <section>, <key>, <default value>, OPTIONAL <encoding>`) : string` [W/L/M]
    The function tries to open the ini file <file path>, retrieve the requested <section> and find the value belonging to the specified <key> which the function will return. If any of these operations fail, <default value> is returned.
    Starting from opsi-script 4.12.6.0, GetValueFromInifile supports a fifth, optional parameter <encoding>, which helps reading the ini file in the correct encoding. We recommend using it in case of special encodings.

GetValueFromInifile("myfile","mysec","mykey","")
GetValueFromInifile("myfile","mysec","mykey","", "utf16-le")

The second function borrows its syntax from the ini file format itself, and may sometimes be easier to use. But since this syntax turns complicated in more general circumstances it is discouraged. The syntax reads:

  • GetIni (<Stringausdruck> [ <character sequence> ] <character sequence>`)`
    (discouraged, use GetValueFromInifile) The <String expression> is interpreted as file name, the first <character sequence> as section name, the second as key name.

9.3.9. Reading Product Properties [W/L/M]

  • GetProductProperty (<PropertyName>, <DefaultValue>`)`
    where $PropertyName$ and $DefaultValue$ are String expressions. If opsi-script is connected to the opsi configuration service the product property is retrieved from the service.
    If there is no connection to the opsi server, then the resulting string is constructed in the following way:
    Since 4.12.4.32 it is checked if there ist a file properties.conf in the %ScriptPath% directory. If this file is found, we try to get the value from this file. The file will be interpreted as list of key=value pairs. In case of a string the entry should have the pattern <property name>=<string value> for examle: myproperty=myentry.
    If there is no file properties.conf or it does not contain the searched entry, so value <default value> is returned.

The product properties can be used to configure variants of an installation.

E.g. the opsi UltraVNC network viewer installation may be configured using the options

  • viewer = <yes> | <no>

  • policy = <factory_default> |

The installation script branches according to the chosen values for these options which can be retrieved by

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

Since 4.12.4.32: if the file %ScriptPath%\properties.conf exists with the content:

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

the following script will be (with out opsi service) successful:

[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
    like GetProductProperty but handles the resulting value as confidential string.
    Useful for getting passwords without logging. see also SetConfidential
    see also: asConfidential (string)
    see also: asConfidential (list)

  • IniVar(<PropertyName>`)`
    (discouraged: use GetProductProperty)

9.3.10. Retrieving Data from etc/hosts [W/L/M]

  • GetHostsName(<string>`)`
    returns the host name to a given IP address as it is declared in the local hosts file. If the operating system is "Windows_NT" (according to environment variable OS) "%systemroot%\system32\drivers\etc\" is assumed as host file location, otherwise "C:\Windows\".

  • GetHostsAddr(<string>`)`
    tells the IP address to a given host or alias name.

9.3.11. String Handling [W/L/M]

  • ExtractFilePath (<path>`) : string` [W/L/M]
    interprets the passed String value as file or path name and returns the path part (the string up to the last path delimiter, including it).

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]
    interprets the passed String value as file or path name and returns the extension part (the string after the last dot ('.'), including it).

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]
    interprets the passed String value as file or path name and returns the file name part (the string after the last path delimiter, not including it).

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]
    interprets the passed String value as path name and replaces all path delimiter to the char that is specific for the running Operating System (Windows: '\', Linux und macOS: '/').

  • resolveSymlink (<file name>`) : <file name>` // since 4.12.4.21 [W/L/M]
    If the given file <file name> is a symbolic link its targert will be (recursiv) resolved and the result will be returned. In any other case the return value ist the given <file name>.

  • [FileExists]

  • [FileOrFolderExists]

  • [DirectoryExists]

  • [fileIsSymlink]

  • StringSplit (`STRINGWERT1, STRINGWERT2, INDEX)`
    (deprecated: use splitString / takeString)
    see also : splitString
    see also : takeString

  • takeString (<index>, <list>`) : string` [W/L/M]
    returns from a string list <list> the string with the index <index>.
    Often used in combination with splitstring: takeString(<index>, splitString(<string1>, <string2>`)`
    (see also String List Functions and String List Processing).
    The result is produced by slicing <string1> where each slice is delimited by an occurrence of <string2>, and then taking the slice with index <index> (where counting starts with 0).

Example:

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

returns '"share"',
the given string slpitted at "\" returns the string list:
Index 0 - "" (empty string), because there is nothing before the first "\"
Index 1 - "" (empty string), because there is nothing before the second "\"
Index 2 - "server"
Index 3 - "share"
Index 4 - "directory"

takestring counts downward, if the index is negative, starting with the number of elements. Therefore,

takestring(-1, $list1$)

denotes the last element of String list $list1$.
see also : setStringInListAtIndex

  • SubstringBefore(<string1>, <string2>`)`
    (deprecated: use splitString / takestring) yields the sequence of characters of stringValue1 up to the beginning of stringValue2.
    Example:

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

returns '"C:\programme\staroffice"'.

  • getIndexFromListByContaining(<list> : stringlist,<search string> : string`)` : <number> : string //since 4.12.0.13 [W/L/M]
    Returns a string that holds the index of the first string in <list> which contains <search string>.
    Retruns a empty string if no matching string is found.
    The check is performed case-insensitive.
    see also : [takeFirstStringContaining]

  • takeFirstStringContaining(<list>,<search string>`) : string` [W/L/M]
    returns the first string from <list> which contains <search string>.
    Retruns a empty string if no matching string is found.
    see also : [getIndexFromListByContaining]

  • trim(<string>`) : string` [W/L/M]
    cuts leading and trailing white space from <string>.

  • lower(<string>`) : string` [W/L/M]
    returns <string> with lower case.

  • upper(<string>`)` [W/L/M]
    returns <string> with upper case.

  • contains(<str>, <substr>`) : bool` //since 4.11.3: true if <substr> in <str> [W/L/M]
    A boolean function which returns 'true' if <str> contains <substr>. This function is case sensitive.
    Available since 4.11.3
    Example:

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>`) : string` //since 4.11.3 [W/L/M]
    returns a string, which has all occurrences of <oldPattern> replaced with <newPattern> given then input string <string>. The pattern match is case insensitive.

Example:

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>`) : string (number)` //since 4.11.3 [W/L/M]
    Returns the number of chars in in <string>

Example:

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

  • strPos(<string>, <sub string>`) : string (numner)` //since 4.11.3 [W/L/M]
    returns the first position of <sub string> in <string>. If <sub string> is not found, then "0" is the return value. The function is case sensitive.

Example:

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>`) : string` //since 4.11.3 [W/L/M]
    returns the part of <string> starting with <start pos> and include the next <number of chars> chars. If there are fewer than <number of chars> after <start pos>, then the returned string will be the rest of the chars after <start pos>.
    The counting of chars starts with 1.

Example:

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>`) : string` //since 4.11.2.1 [W/L/M]
    returns the unquoted version of <string>, if <string> is quoted with <quote-string>
    Only one char (the first char) of <quote-string> is accepted as a quote char. The leading white spaces are ignored.
    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>`) : string` //since 4.11.5.2 [W/L/M]
    Acts like unquote(<string>,<quote-string>) with the following differences:
    If <quote-string> contains only one char, so this char will be used as 'start quote char' and 'end quote char'. If <quote-string> contains two chars, so the first char will be used as 'start quote char' and the second char as 'end quote char'. Example: a <quote-string> like "()" will unquote a string like '(hello)'.
    The function returns the unchanged <string> if not ('start quote char' AND 'end quote char') is found.
    see also : [unquote]

  • HexStrToDecStr (<hexstring>`) : string` [W/L/M]
    returns the decimal representation of the input string if this was the hexadecimal representation of an integer. Leading chars like '0x' or '$' will be ignored. In case of a converting error the function returns a empty string.

  • DecStrToHexStr ( <decstring>, <hexlength>`) : string` [W/L/M]
    returns a <hexlength> long string with the the hexadecimal representation of <decstring> if this was the decimal representation of an integer. In case of a converting error the function returns a empty string.

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>`) : string` [W/L/M]
    returns the base64 encoded value of <string>.

  • base64DecodeStr(<string>`) : string` [W/L/M]
    returns the base64 decoded value of <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` [W/L/M]
    Encrypted <datastring> with the Key <keystring> under application of Blowfish and returns the encrypted value.

  • decryptStringBlow(<keystring>,<datastring>`) : string` [W/L/M]
    Decrypts <datastring> with the Key <keystring> under the application of Blowfish and returns the decrypted value.

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` [W/L/M]
    Returns the md5sum that under <path to file> was found.
    In case of error returns an empty String.

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]
    This is a platform-independant hashing files functions, which supports 80 hashing algorithms.
    Insert in <Hashing Algorithm> one of these supported hashing algorithms : '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

  • GetShortWinPathName(<longpath string>) //since 4.11.5.2 [W]
    Returns the short path (8.3) from <longpath string>. If ther is no short path for <longpath string>, so you will get an empty string.
    Example: GetShortWinPathName("C:\Program Files (x86)") returns "C:\PROGRA~2"

9.3.12. Other String Functions

  • RandomStr (<usespecialchars>`): string` [W/L/M]
    returns a random String of length 10 where upper case letters, lower case letters and digits are mixed (for creating passwords). More exactly: if usespecialchars = true, it will create a string of 2 lower case chars, 2 upper case chars, 2 special chars and 4 digits. The possible special chars are:
    '!','$','(',')','*','+','/',';','=','?','[',']','{','}','ß','~','§','°' if usespecialchars = false, it will create a string of 3 lower case chars, 3 upper case chars and 4 digits.

  • RandomStrWithParameters (<minLength>,<nLowerCases>,<nUpperCases>,<nDigits>,<nSpecialChars>): string [W/L/M]
    returns a random String (useful for creating passwords) according to the input configuration in the parameters, where:

    • <minLength>: the length of the string,

    • <nLowerCases>: the count of lower case letters wanted,

    • <nUpperCases>: the count of upper case letters wanted,

    • <nDigits>: the count of digits wanted,

    • <nSpecialChars>: the count of special characters wanted.
      Possible special chars are: '!','$','(',')','*','+','/',';','=','?','[',']','{','}','ß','~','§','°'

  • RandomIntStr(<number str>) : string [W/L/M]
    returns a number between 0 and <number str> as string.

  • CompareDotSeparatedNumbers(<string1>, <string2>) : string [W/L/M]
    compares two strings of the form <number>[.<number>[.<number>[.<number>]]]
    It returns "0" if the strings are equal, "1" if <string1> is higher and "-1" if <string1> is lower than <string2>.
    see also: CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>) : [CompareDotSeparatedNumbers_bool]
    see also: [CompareDotSeparatedStrings_str]

Example:
The 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

leads to the following 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>`) : string` [W/L/M]
    compares two strings of the form <string>.<string>[.<string>[.<string>]]
    It returns "0" if the strings are equal, "1" if <string1> is higher and "-1" if <string1> is lower than <string2>. The function is not case sensitive.
    see also : [CompareDotSeparatedStrings_bool]
    see also : [CompareDotSeparatedNumbers_bool]

Example:
The 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

leads to the following 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]
    returns a string with the integer number of seconds since the last call of marktime.
    Available since 4.11.3.1

  • timeStampAsFloatStr : string (Floating Number - format: 'days.decimal days') //since 4.11.6 [W/L/M]
    Gives Date and Time from now as string that contains a decimal number in the format: 'days.decimal days'. This Format make it easier to claculate time differences.

  • SidToName(<well known sid>`)` [W]
    returns a string with the localized name of the group with the <well known sid>. For example, if <well known sid> is equal to 'S-1-5-32-544' then SidToName returns 'Administrators'.
    Available since 4.11.3.1

  • GetMyIpByTarget(<target ip addr>`)` [W/L/M]
    returns a list of interface IP-addresses, which are trying to reach the operating system at <target ip addr>. This function returns a value that is safer than the constant %IPAddress%.
    Since Version 4.11.3.1
    Example:

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

see also : [GetIpByName]
see also : [IPAddress]

* GetIpByName(<ip addr / ip name>`)` [W/L/M]
returns the IP-addresses of the computers with the <ip addr / ip name>
Since 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

see also : [GetMyIpByTarget]

  • stringinput(< message str>,< boolstr confidential>`) : string` //since 4.12.1.2 [W/L/M]
    Interactive function.
    Interactive function to get a string from the user. It outputs the < message str> and waits for the Input and returns the input string.
    In the grafical mode this is done in a modal Window, in the non grafical mode at the command line.
    If < boolstr confidential> = "true" then the input is masked by "*". A button with a eye icon can be used to get a unmasked, readble display.
    If < boolstr confidential> = "false" the the input is readable.

  • replaceOpsiConstants(<string>`) : string` //since 4.12.3.6 [W/L/M]
    returns a string, which has all occurrences of opsi constants in <string> replaced with their value.
    see also : [replaceOpsiConstants_list]

9.3.13. (String-) Functions for Licence Management [W/L/M]

  • DemandLicenseKey(`poolId [, productId [,windowsSoftwareId]])`
    asks the opsi service via the function getAndAssignSoftwareLicenseKey for a reservation of a licence for the client.
    The pool from which the licences is taken may be explicitly given by its ID or is identified via an associated product ID or Windows Software Id (possible, if these associations are defined in the licences configuration).
    'poolId', 'productId', 'windowsSoftwareId' are Strings (resp. String expressions).
    If no 'poolId' is explicitly given, the first parameter has to be an empty String "". The same procedure is done with other not explicit given Ids.
    The function returns the licence key that is taken from the pool.

Examples:

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

  • FreeLicense(`poolId [, productId [,windowsSoftwareId]]])`
    asks the opsi service via the function freeSoftwareLicense to release the current licence reservation. The syntax is analogous to the syntax for DemandLicenseKey

Example:

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

'$opsiresult$' becomes the empty String, if no error occurred, and, if an error occurred, the error info text.

9.3.14. Retrieving Error Infos from Service Calls [W/L/M]

  • getLastServiceErrorClass
    returns, as its name says, the class name of the error information of the last service call. If the last service call did not produce an error the function returns the value "None".

  • getLastServiceErrorMessage
    returns the message String of the last error information resp. "None".
    Since the message String is more likely to be changed, it is recommended to base script logic on the class name.

Example:

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

9.4. String List Functions and String List Processing [W/L/M]

A String list (or a String list value) is a sequence of String values. For this kind of values we have the variable of type String list. Since 4.12.4.32 it is also possible to pass an optional inital value. They are defined by the statement

DefStringList <VarName> [= <inital value>]

A String list value may be assigned to String list variable:

Set <VarName> = <StringListValue>

String list values can be given only as results of string list expressions. These string list expressions can be construced on different ways:

  • by a function that returns a string list

  • by a string list variable

  • since 4.12.4.32 by a json style string that can be read as string list

For the following examples we declare a String list variable '$list1$':

DefStringList $list1$

Since 4.12.4.32 the simplest way is a string in json style that can be read as string list:
["<string>"]
Example:
set $list1$ = '["ab","cd","de"]'

The same result we get by using the function CreateStringlist:
set $list1$ = createstringlist("ab","cd","de")

There are many ways to create or capture String lists, and many options for processing them, often yielding new String lists. They are presented in the following subsections.

If we refer to variables named like String0, StringVal, .. it is meant that these represent any String expressions.

We start with a special and rather useful kind of String lists: 'maps' – also called hashes or associative arrays – which consist of a lines of the form 'KEY'='VALUE'. In fact, each map should establish a function which associates a 'VALUE' to a 'KEY', and any 'KEY' should occur at most once as the first part of a line (whereas different 'KEY’s may be associated with identical 'VALUE' parts).

9.4.1. Info Maps

  • getHWBiosInfoMap //since 4.11.4 [L/W]
    get hardware information from BIOS and writes them to hash map string list.
    There are the folowing keys: (example):

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]

Example:

Set  $macOSinfomap$ = getMacosVersionMap

gives (for examle) the 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 : stringlist //since 4.11.4 [L]
    get OS information and writes them to hash map string list.
    There are the folowing keys: (example):

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 : stringlist [W]
    get OS information and writes them to hash map string list.

There are the folowing keys: * 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

The Results from 'suite_mask' and 'product_type_nr' are integers that can be build by 'or' operations of the following values.

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 which gives you the sub release of 'Windows 10' like e.g. '1511'. The Value comes from the Registry: "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ReleaseID"

  • prodInfoText which gives you a string to the edition type like e.g. 'PRODUCT_PROFESSIONAL'.

  • prodInfoNumber which gives you a string with a decimal number of the edition type like e.g. '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

Example:
The Code

DefStringList $INST_Resultlist$
DefStringList $INST_Resultlist2$

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

produces the following 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]

retrieves the version infos built into the file FILENAME and writes it to a Stringlist map.

At this moment, there exist the keys,

  • 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

Usage: If we define and call

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

we get the value associated with key "FileVersion" from the call

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

Example:
The code:

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

produce the 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]
    retrieves the system informations on the locale and writes it to a Stringlist map.

At this moment, there exist the keys:

  • language_id_2chars (two-letter version of the system default language name)

  • language_id (three-letter version of it, including subtype of language) 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 Language_Region (Posix Style)

  • system_default_lang_region Language-Region (BCP 47 Style)

The system_default keys gives information about the language of the installed OS. The other keys give information about the locale of the GUI.

Example:
The code:

message "Locale Infos"
set $INST_Resultlist$ = GetLocaleInfoMap

produces e.g the 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

Usage: If we define and call

DefStringList $languageInfo$
set  $languageInfo$ = GetLocaleInfoMap

we get the value associated with key "language_id_2chars" from the call

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

(for the function getValue cf. Simple String Values generated from String Lists or Files). We may now write scripts using a construct like

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

  • getProductMap // since 4.11.2.4 [W/L/M]
    returns a info map of the opsi product you are just installing.
    It works only if opsi-script is running in opsi service mode.
    keys are: id, name, description, advice, productversion, packageversion, priority, installationstate, lastactionrequest, lastactionresult, installedversion, installedpackage, installedmodificationtime, actionrequest

Example:

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

produces e.g the 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]
    Interactive function.
    Show the given < strlist> as <key>=<value> pair list to the user and gives the possibility to change values. Returned ist the edited version of <str list>, after the user user finished editing.
    In the grafical mode this is done in a modal Window, in the non grafical mode at the command line.

getListFromWMI(<wmi namespace str>,<wmi class str>,<property list>,<condition str>`) : stringlist` //since 4.12.1.0 [W]
Returns an info map of <wmi class str> that is limited to the properties in <property list> and also is limited by the <condition str>.
If <property list> is empty, all properties of <wmi class str> will be returned.
Attention: If <property list> contains properties that don’t exist in the called WMI class, the query will fail.
Calling with properties is faster than without.
If <wmi namespace str> is empty, it defaults to root\cimv2.
If an error occurs, an empty list will be returned

Example:

; 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$)

produces e.g the 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

Example:

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$)

produces e.g the 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

Example:

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

produces e.g the 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

Example:

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

produces e.g the log:

comment: Testing for drive count
Set  $list1$ = createStringList ('Name')
  The value of the variable "$list1$" is now:
  (string   0)Name
Set  $str1$ = ''
  The value of the variable "$str1$" is now: ""
Set  $str2$ = 'Win32_LogicalDisk'
  The value of the variable "$str2$" is now: "Win32_LogicalDisk"
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)Name=C:
  (string   1)Name=D:
  (string   2)Name=P:
Set  $CompValue$ = count($resultlist$)
  The value of the variable "$CompValue$" is now: "3"
Set  $resultlist$ = powershellCall('get-psdrive -psprovider filesystem | select-object -expand Name')
PowerhellCall Executing: get-psdrive -psprovider filesystem | select-object -expand Name ; mode: sysnative
ShellCall Executing: "C:\Windows\\cmd64.exe" /C "powershell.exe get-executionpolicy"
ExitCode 0
ShellCall Executing: "C:\Windows\\cmd64.exe" /C "powershell.exe set-executionpolicy RemoteSigned"
ExitCode 0

Execution of tmp-internal powershell.exe winst /sysnative
  Save to file with encoding: system
  trap { write-output $_ ; exit 1 }
  get-psdrive -psprovider filesystem | select-object -expand Name
  exit $LASTEXITCODE
  ExitCode 0
The file: c:\opsi.org\tmp\_opsiscript_Lw32Rh40.ps1 has been deleted

ShellCall Executing: "C:\Windows\\cmd64.exe" /C "powershell.exe set-executionpolicy Restricted"
ExitCode 0
  The value of the variable "$resultlist$" is now:
  (string   0)C
  (string   1)D
  (string   2)P
Set  $ConstTest$ = count($resultlist$)
  The value of the variable "$ConstTest$" is now: "3"
If
  $ConstTest$ = $CompValue$   <<< result true
  ($ConstTest$ = $CompValue$)   <<< result true
Then
  comment: getListFromWMI passed
Else
EndIf

The application works similar as the function getListFromWMI.

The user interface of 'opsi-wmi-test' is subdivided in two sections.

At the upper section ('Connection to WMI service') you are asked to input the data which is necessary to connect to the WMI service. Input here the name of the computer ('Computer') adressed, the WMI namespace ('NameSpace') of the WMI class which shall be used, and, if necessary, the username ('User') and the password ('Password'). At start of opsi-wmi-test.exe, some default values ('Computer' = localhost, 'NameSpace' = \root\cimv2, 'User' = < > , 'Password' = < >) are given. These parameters allow the connection to the local WMI service and access to the most used WMI classes. (Figure 9.1)
It is also possiple to connect to remote WMI services of other computers in the network by using network name, username and password, respectively.

opsi-wmitestgui-start
Figure 1. GUI of opsi-wmi-test. At the upper section ('Connection to WMI service') you are asked to input the data which is necessary to connect to the WMI service. At the lower section ('Request to WMI service'), you are asked to input the data which is necessary to make the desired query to the WMI service.

At the lower section ('Request to WMI service'), you are asked to input the data which is necessary to make the desired query to the WMI service. You must input the WMI class or its alias as well as the properties you like to query for. You can input the WMI class or its alias directly in the respective field ('Class' or 'Alias') or you can select it from a list.(Figure 9.2). You should know that not all WMI Classes have Aliases. If the class zou selected has one, its Alias will be automatically selected in the 'Alias' field. If not, <No Alias> will be displayed. After the WMI class is given, its properties will be displayed in the field 'Available WMI Properties'.

opsi-wmitestgui-2

Available properties can be selected and moved into the field 'Selected WMI Properties' using drag & drop or by clicking on the button opsi-wmitestgui-button-pfeil-rechts (Figure 9.3). Note: This works also the other way around. Properties can be moved from 'Selected WMI Properties' back to 'Available WMI Properties' via drag & drop or the button opsi-wmitestgui-button-pfeil-links.

opsi-wmitestgui-3
Figure 2. Available properties can be selected and moved into the field 'Selected WMI Properties' using drag & drop or by clicking on the button opsi-wmitestgui-button-pfeil-rechts. Note: This works also the other way around. Properties can be moved from 'Selected WMI Properties' back to 'Available WMI Properties' via drag & drop or the button opsi-wmitestgui-button-pfeil-links.
opsi-wmitestgui-4
Figure 3. After moving the desired properties to the field 'Selected WMI Properties' click on the Button 'Execute' to send the query to the WMI service. You can specify your query within the field 'Condition' using SQL statements.

After moving the desired properties to the field 'Selected WMI Properties' click on the Button 'Execute' to send the query to the WMI service. You can specify your query within the field 'Condition' using SQL statements (example: where <property> = <value>).

The final query will be dispalyed in the 'Query' field. It can be copied but not modified there. The result of your query is displayed in a second window (figure 9.4). If the query could not be processed the result is an error message.

opsi-wmitestgui-resultwindow
Figure 4. The result of the query is displayed in a second window

In a third window, you wil have all the data about your query : 'Namespace', 'Selected Class', 'Properties list', 'Selected Properties' and 'All available Properties'. You can use all those fields for copying and pasting in your opsi script.

opsi-wmitestgui-querywindow
Figure 5. In a third window, you wil have all the data about your query : 'Namespace', 'Selected Class', 'Properties list', 'Selected Properties' and 'All available Properties'.

9.4.2. Producing String Lists from Strings [W/L/M]

  • createStringList (<string0>, <string1> ,…​ ) : stringlist [W/L/M]
    forms a String list from the values of the listed String expressions. For example, by

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

we get a list of the first four letters of the alphabet.

The following two functions produce a String list by splitting some string: splitString (<string1>, <string2>`) : stringlist` [W/L/M]
generates the list of partial strings of <string1> (including empty strings) before resp. between the occurences of <string2>. E.g.,

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

defines the list
'"", "", "server", "share", "directory"'
If the given string is in the list of confidential strings, so the resulting string parts will also be added to the list of confidential strings.

  • splitStringOnWhiteSpace (<string>`) : stringlist` [W/L/M]
    slices StringVal by the "white spots" in it. E. g.

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

produces the list
'"Status", "Lokal", "Remote", "Netzwerk"'
no matter how many blanks or tabs constitute the white space between the words.
If the given string is in the list of confidential strings, so the resulting string parts will also be added to the list of confidential strings.

9.4.3. Loading Lines of a Text File into a String List

  • loadTextFile (<file name>`) : stringlist` [W/L/M]
    reads the file <file name> and generates the string list, that contains all lines of the file.

  • loadTextFileWithEncoding( <file name> , <encoding>`) : stringlist` [W/L/M]
    reads the file <file name> and generates the string list, that contains all lines of the file. The string will be reencoded from <encoding> to system encoding.

  • loadUnicodeTextFile (<file name>`) : stringlist` [W/L/M]
    reads the unicode text file <file name> and generates the string list, that contains all lines of the file.
    By this call, the strings are converted into the system default 8 bit code.

  • getSectionNames(<ini-file>`) : stringlist` [W/L/M]
    interprets the specified file as an inifile, looks for list of all lines of form
    '[<SectionName>]'
    and returns the pure section names (without brackets).

  • GetSectionFromInifile(<ini-file-section>`,<ini-file>) : stringlist` [W/L/M]
    +interprets the specified file as an inifile, looks for the list related to the + '[<ini-file-section>]' chosen in input
    +and returns the complete raw section content in a stringlist.

9.4.4. Simple String Values generated from String Lists or Files [W/L/M]

  • composeString (<string list>, <Link>`) : string` [W/L/M]
    With this function, the elements of any String list can be glued to one another, mediated by a "glue string".
    E.g. if '$list1$' represents the list 'a', 'b', 'c', 'd', 'e'
    by

$line$ = composeString ($list1$, " | ")

we assign the value '"a | b | c | d | e".' to '$line$'.

  • takeString (<index>, <list>`) : string` [W/L/M]
    For example, if '$list1$' represents the list of the first five letters of the alphabet, using

takeString (2, $list1$)

we get string "c" (since list counting starts with 0).
Negative values of index go downwards from the list count value. E.g.,

takeString (-1, $list1$)

return the last list element, that is "e".
see also : setStringInListAtIndex
see also : takeString

  • takeFirstStringContaining(<list>,<search string>`) : string` [W/L/M]
    returns the first string of the list which contains the <search string>.
    Returns an empty string if no matching string was found.

  • getValue(<key string>, <hash string list> ) : string [W/L/M]
    This function tries to interpret a String list as list of lines of the form 'key=value'
    It looks for the first line, where the string <key> is followed by the equality sign, and returns the remainder of the line (the 'value', the string that starts after the equality sign). If there is no fitting line, it returns the string 'NULL'.
    The function is required for using the GetLocaleInfoMap and getFileVersionMap string list functions (cf. Section 9.4.1).

  • setValueByKey(<key>, <value>, <targetlist> ) : stringlist [W/L/M]
    Sets the value of <key> to <value> in the string list <targetlist>. For this, the string list <targetlist> must be a key/value list, which means that every entry is of the form 'key=value'.
    If the key/value pairs in <targetlist> are not seperated by = but by another seperator, then this seperator must be given as an argument to the function.
    Example:

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']

  • getValueBySeparator(<key string>,<separator string>,<hash string list> ) : string //since 4.11.2.1 [W/L/M]
    works like getValue but you have to give the <separator string> so that can also work with hashes like
    'key:value'

  • getValueFromFile(<key string>, <file name>`) : string` //since 4.11.4.4 [W/L/M]
    Searches in <file name> for a key/value pair with key <key string> and separator string '=' and returns the value. If <key string> is not found it returns an empty string.

  • getValueFromFileBySeparator(<key string>,<separator string>,<file name>`) : string` //since 4.11.4.4 [W/L/M]
    Searches in <file name> for a key/value pair with key <key string> and separator string <separator string> and returns the value. If <key string> is not found it returns an empty string.

  • count (<list>`) : string (number)` [W/L/M]
    returns the number of elements of the string list <list> as string.
    e.g. for $list1$ composed as
    'a', 'b', 'c', 'd', 'e'
    count ($list1$) has the value "5".

9.4.5. Producing String Lists from opsi-script Sections [W/L/M]

  • retrieveSection (<section name>`) : stringlist` [W/L/M]
    gives the lines of the specified section as string list.

  • getOutStreamFromSection (<dos section name>`) : stringlist (output)` [W/L/M]
    invokes the section and – at this moment implemented only for DosInAnIcon (ShellInAnIcon),ExecWith and ExecPython calls – captures the output to standard out and standard error of the invoked commands writing them into a string list. For example:

set $list$ = getOutStreamFromSection ('DosInAnIcon_netstart')

[DosInAnIcon_netstart]
net start

$list1$ contains among some surrounding stuff the list of all mounted shares of a PC.
see also : getReturnListFromSection
see also: executeSection

There are 3 shortcuts for simple calls to the shell. At Windows these commands runs in the sysnative mode.

  • shellCall (<command string>`) : stringlist (output)` //since 4.11.4.2 [W/L/M]
    Executing <command string> with the standard shell (cmd.exe / bash)

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

Is a shortcut for this expression:

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

[DosInAnIcon_netstart]
net start

see also : shellCall_list

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

shellCall('net start')

Is a shortcut for this expression:

DosInAnIcon_netstart winst /sysnative

[DosInAnIcon_netstart]
net start

see also : 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:

DosInAnIcon_netstart winst /sysnative
set $exitcode$ = getLastExitcode

[DosInAnIcon_netstart]
net start

see also : shellCall_str

  • getReturnListFromSection ( section name ) [W/L/M]
    For some section types - at this moment implemented only for XMLPatch sections and opsiServiceCall sections - there is a specific return statement which yields some result of the execution of the section (assumed to be of String list type).
    E.g. we may use the statement

set list1 = getReturnListFromSection ('XMLPatch_mime "c:\mimetypes.rdf"')

to get a specific knot list of the XML file mimetypes.rdf. (More info to XMLPatch sections at XMLPatch Sections in this manual).
Or the list of opsi clients is produced by the reference to a opsi service call:

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

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

9.4.6. Stringlists from the registry [W]

  • getRegistryKeyList32(<regkey>`) : stringlist` [W]
    Returns a stringlist with the names of all keys within <regkey>.
    32 Bit mode (with redirection). Available since 4.11.3

  • getRegistryKeyList64(<regkey>`) : stringlist`
    Returns a stringlist with the names of all keys within <regkey>.
    64 Bit mode (without redirection). Available since 4.11.3

  • getRegistryKeyListSysnative(<regkey>`) : stringlist`
    Returns a stringlist with the names of all keys within <regkey>.
    Mode (redirection) depends on the architecture of the OS. Available since 4.11.3

  • getRegistryKeyList(<regkey>, <access str>`) : stringlist`
    Summes up the previous three functions, i.e. returns a stringlist with the names of all keys within <regkey>, where the Mode (32bit, 64bit, sysnative) is given as <access str>. Available since 4.12.5.0

  • getRegistryVarList32(<regkey>`) : stringlist`
    Returns a stringlist with the names of all value entries associated with key <regkey>.
    32 Bit mode (with redirection). Available since 4.11.3

  • getRegistryVarList64(<regkey>`) : stringlist`
    Returns a stringlist with the names of all value entries associated with key <regkey>.
    64 Bit mode (without redirection). Available since 4.11.3

  • getRegistryVarListSysnative(<regkey>`) : stringlist`
    Returns a stringlist with the names of all value entries associated with key <regkey>.
    Mode (redirection) depends on the architecture of the OS. Available since 4.11.3

  • getRegistryVarList(<regkey>, <access str>`) : stringlist`
    Summes up the previous three functions, i.e. returns a stringlist with the names of all value entries associated with key <regkey>, where the Mode (32bit, 64bit, sysnative) is given as <access str>. Available since 4.12.5.0

  • getRegistryVarMap32(<regkey>`) : stringlist`
    Provides a map of all name=value pairs in the given registry key <regkey>.
    32 Bit Mode (with redirection). Since 4.11.3

  • getRegistryVarMap64(<regkey>`) : stringlist`
    Provides a map of all name=value pairs in the given registry key <regkey>.
    64 Bit Mode (with redirection). Since 4.11.3

  • getRegistryVarMapSysnative(<regkey>`) : stringlist`
    Provides a map of all name=value pairs in the given registry key <regkey>.
    Mode depend on the architecture of the operating system. Since 4.11.3

  • getRegistryVarMap(<regkey>, <access str>`) : stringlist`
    Summes up the previous three functions, i.e. provides a map of all name=value pairs in the given registry key <regkey>, where the Mode (32bit, 64bit, sysnative) is given as <access str>. Available since 4.12.5.0

Example:
At first, we create entries in the registry with the following example code:

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:4294967295
; REG_QWORD is supported since 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]

Given the registry entries in the example above, and the following code:

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

or

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

we will see the following values in the 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

If we call:

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

or

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

we will see the following 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

If we call:

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

or

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

we will get the following key in the 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

9.4.7. Stringlists from the Product Properties [W/L/M]

  • getProductPropertyList(<propname>,<default value>`)` [W/L/M] // seit 4.11.3
    returns a stringlist of values that are referred to by the multivalue product property <propname>.
    If you call the function GetProductProperty with a multivalue property, then you will get the selected values in a comma-separated string format. This will lead to problems if the returned values contain any comma chars that are not meant to be parsed.
    If there is no connection to the opsi server, then the resulting stringlist is constructed in the following way:
    Since 4.12.4.32 it is checked if there ist a file properties.conf in the ScriptPath directory. If this file is found we try to get the value from this file. The file will be interpreted as list of key=value pairs. In case of a stringlist the entry should have the pattern <property name>=<list value> for examle: myproperty=["entry1","entry2","entry3"].
    If there is no file properties.conf or it does not contain the searched entry, so value <default value> is returned. <default value> decribes the return value if no connection to the opsi-server is available. If <default value> is a string expression this string is the first element of the returned list. Since 4.11.5.6 <default value> may also be a string list expression. Since 4.12.4.32 <default value> may also be a string list from the kind: '["ab","cd","de"]'

Example:

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"]')

Since 4.12.4.32: if the file %ScriptPath%\properties.conf exists with the content:

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

the following script will be (with out opsi service) successful:

[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

9.4.8. Other String Lists [W/L/M]

  • getProfilesDirList : stringlist //since 4.11.3.2 [W/L/M]
    Provides a list of paths to the local profiles.
    [W]: Profiles that contain the following words will not be considered:

    • 'localservice'

    • 'networkservice'

    • 'systemprofile'

The profile of 'Default Users' is included in the list.
All User or Public are not included in the list.

[L]: You get a list of the existing user directories from all users with a UID >= 1000.

Example:

set $list1$ = getProfilesDirList

results in the following 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 : stringlist //since 4.11.1.2; gives list of exename;pid;dom/user [W/L/M]
    Provides a list of running processes.
    For each process you get one line with a ';' separated list of the following process information:

    • [W]: 'Name of running exe'. [L]: short name of running process

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

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

    • [L]: 'full command line of the process'

  • listFiles (<Path>, <Searchmask>, <SearchSubDirectories>, [<Redirection>]) : stringlist [W/L/M]

Provides a stringlist of all files found in <Path> (e.g. "C:\Windows\system32") which fits to the given <Searchmask> (e.g. "*.dll"). <Searchmask> may contain multiple elements separated by semicolon.
If <SearchsubDirectories> is set to "True" then all subdirectories within the given <Path> are included in the search. Setting <SearchsubDirectories> to "False" excludes the subdirectories from the search.

[W] Optional the parameter <Redirection> can be set to "64bit" or "SysNative". This enables to search in (system) directories which otherwise are not searchable because of redirection of 32-bit programs at 64-bit systems (only 64bit Windows). See also 64 Bit Support on Windows [W]

example:

message "Test of function listFiles"

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

results in the following 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] returns a list, which has all occurrences of opsi constants in <string list> replaced with their value.
    see also : replaceOpsiConstants (string)

9.4.9. Transforming String Lists [W/L/M]

  • getSubList (<start index> : <end index>, <list>`) : stringlist` [W/L/M]
    returns a partial list of a given list.
    E.g., if list represents the list of letters 'a', 'b', 'c', 'd', 'e', by the statement:

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

we get the partial list 'b', 'c', 'd' . Begin index as well as end index have to be interpreted as the index of the first and last included list elements. The counting starts with 0.
Default start index is 0, default end index is the index of the last element of the list.
Therefore, (for the above defined list1) the command

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

yields the list 'b', 'c', 'd', 'e'.

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

produces a copy of the original list.
It is possible to count backwards in order to determine the last index:

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

defines the list of elements starting with the first and ending with the last element of the list – in the above example we again get list 'b', 'c', 'd','e'.

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

defines the list of elements starting with the first and ending with the second to last element of the list – in the above example we get list 'b', 'c', 'd'.

Since version 4.12.0.35 you may beside numbers also use string expressions: strings, string variables or string functions.

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]
    returns the first string from <list> which contains <search string>. Returns empty string if <seach string> is not found.

  • getListContainingList(<list1>,<list2>`) : stringlist` //since 4.11.3.7 [W/L/M]
    returns the intersection of list1 and list2.

  • getSubListByMatch (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of <target list> where the string matches with <search string>.
    The check is performed case-insensitive.

  • getSubListByMatch (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of <target list> where the string matches with one of the strings of <search list>.
    The check is performed case-insensitive.

  • getSubListByContaining ( <search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of <target list> where the string contains <search string>.
    The check is performed case-insensitive.

  • getSubListByContaining (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of <target list> where the string contains with one of the strings of <search list>.
    The check is performed case-insensitive.

  • getSubListByKey (<search string>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of <target list> where the string starts with '<search string>='.
    The check is performed case-insensitive.

  • getSubListByKey (<search list>, <target list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns the part of the key/value <target list> where the key is one of the strings of <search list>.
    The check is performed case-insensitive.

  • getKeyList (<list>`)` :stringlist //since 4.12.0.14 [W/L/M]
    returns from the the key/value list <list> (in the format key=value) the list of keys.
    Is an entry in <list> not in the format key=vakue, the complete string will be part of the result list.

  • takeFirstStringContaining(<list>,<search string>`) : string` [W/L/M]
    returns the first string from <list> which contains <search string>.
    Return en empty string if <search string> is not found.
    see also : [takeFirstStringContaining]

  • addtolist(<list>,<string>`) : stringlist` //since 4.10.8 [W/L/M]
    Appends <string> to the list <list>.

  • addListToList(<dest list>,<src list>`) : stringlist` //since 4.10.8 [W/L/M]
    Appends the list <list2> to the list <list1>.

  • reverse (<list>`) : stringlist` [W/L/M]
    produces the inverted list,
    if $list$ is 'a', 'b', 'c', 'd', 'e', by

set $list1$ = reverse ($list$)

we get the $list1$ 'e', 'd', 'c', 'b', 'a'.

emptylist (<list>`) : stringlist` //since 4.11.3.7 [W/L/M]
clears the list.

  • reencodestrlist(<list>, <from>, <to>`) : stringlist` //since 4.11.4.2 [W/L/M]
    assumes that <list> is encoded in <from> and returns the in <to> encoded version of <list>. <from> and <to> are encodings as listet in chapter opsi-script encoding.

  • removeFromListByContaining(<search string>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M]
    Returns a copy of <target list> where all lines that contains <search string> are removed. The match to <search string> is case insensitiv.

  • removeFromListByContaining(<search list>`,` <target list>`) : stringlist` //since 4.11.5.1 [W/L/M]
    Returns a copy of <target list> where all lines are removed that contains a string out of <search list>. The match to <search list> is case insensitiv.

Examples:

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 from 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

  • removeFromListByMatch(<searchstring>,<target list>`) : stringlist` //since 4.11.6 [W/L/M]
    Returns a copy of <target list> where all lines are removed that exactly match a line out of <search list>. The match to <search sting> is case insensitiv.
    see also : [removeFromListByContaining_str]
    see also : [removeFromListByContaining_list]

  • setStringInListAtIndex(<newstring>,<list>,<indexstr>`) : stringlist` //since 4.11.6 [W/L/M]
    Replaces in the existing stringlist <list> the existing string at <index> by <newstring>. If <index> is to hight, <newstring> will be appended. In case of an error the result is an empty string list.
    see also : [takeString]

  • areListsEqual(<strlist1>, <strlist2>, <flag>`) : boolean`
    Evaluates if the 2 stringlists <strlist1> and <strlist2> are equal according to the chosen flag :
    If flag='FLAG_AUTOMODE': The function will do a case insensitive comparaison. It handles key/value stringlists (with the structure : 'key1=value1') or simple stringlists.
    If flag='FLAG_AUTO_CS' : The function will do a case sensitive comparaison. It also handles both key/value stringlists (with the structure : 'key1=value1') or simple stringlists.
    If flag='FLAG_STRING_CS' : The function will do a case sensitive comparaison that only handles simple stringlists (So it does not take into consideration the key/value structure).

9.4.10. Iterating through String Lists [W/L/M]

An important usage of string lists is based on the possibility that the script runs through all elements of a list executing some operation on each string element.

The syntax to define this repetition is:

  • for %s% in <list> do <one statement | sub section>

This expression locally defines a string variable %s% that takes one by one the values of the list elements. <one statement> can be any single statement that can exist in a primary section or (and most interestingly) it may be a subsection call. The locally defined iteration index %s% exists in the whole context of statement, in particular in the subsection if statement is a subsection call.

The replacement mechanism for %s% always works like that for constants: The name of the variable is replaced by the element values. If we iterate through a list 'a','b','c' and the iteration index is named %s%, we get for %s% one by one a, b, c – not the String values. To reproduce the original list elements we have to enclose %s% in citation marks.

Example: Let $list1$ be the list 'a', 'b', 'c', 'd', 'e', and $line$ a String variable. The statement

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

iterates through the list elements internally executing

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

Such, finally line has value 'abcde' . If we omitted the citation marks around %s% we would get a syntax error for each iteration step.

Please note: The note variable is only valid in the directly called procedure. If it is needed in sub programs of it its value must be transferred to a global variable.

9.5. opsiservicecall and json Related functions [W/L/M]

This functions may be used to analyze and modify JSON expressions. In order to work with these functions, you have to understand the structure of the used JSON expression.
These function can help to use the opsiservicecall sections.

  • jsonIsValid(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    returns 'true' if <jsonstr> is a valid JSON expression.

  • jsonIsArray(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    returns 'true' if <jsonstr> is a valid JSON array.

  • jsonIsObject(<jsonstr>`) : boolean` //since 4.11.6: [W/L/M]
    returns 'true' if <jsonstr> is a valid JSON object.

  • jsonAsObjectHasKey(<jsonstr>,<keystr>`) : boolean` //since 4.11.6: [W/L/M]
    returns 'true' if <jsonstr> is a valid JSON object, which contains <keystr> as key.
    The following example returns 'true':

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

  • jsonAsArrayCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M]
    if <jsonstr> is a valid JSON array, the function returns the number of elements in the array.
    In case of an error, the result is '"0"'

  • jsonAsObjectCountElements(<jsonstr>`) : intstr` //since 4.11.6: [W/L/M]
    if <jsonstr> is a valid JSON object, the function returns the number of elements in the object.
    In case of an error, the result is '"0"'

  • jsonAsArrayGetElementByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6: [W/L/M]
    if <jsonstr> is a valid JSON array, the function returns the element at the index <indexstr>.
    The index starts with "0".
    In case of an error, the result is '""'

  • jsonAsObjectGetValueByKey(<jsonstr>, <keystr>`) : valuestring` //since 4.11.6: [W/L/M]
    returns from the JSON object <jsonstr>, the value of the key <keystr>.
    In case of an error, the result is '""'

  • jsonAsObjectSetValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M]
    returns a string with a JSON object. This object is the given <jsonstr>, where the value of the key <keystr> is set to <valuestring>. If the key <keystr> did not exist, it will be created.
    If you are sure that you want to create <valuestring> as string value (and not as number or boolean, …​) , than we recommend to use the function: [jsonAsObjectSetStringtypeValueByKey].
    In case of an error, the result is '""'

  • jsonAsObjectSetStringtypeValueByKey(<jsonstr>, <keystr>,<valuestring>`) : jsonstring` //since 4.11.6: [W/L/M]
    returns a string with a JSON object. This object is the given <jsonstr>, where the value of the key <keystr> is set to <valuestring> as a string (quoted). If the key <keystr> did not exist, it will be created.
    If you are not want to create <valuestring> as string value (but as number or boolean, …​) , than we recommend to use the function: [jsonAsObjectSetValueByKey].
    In case of an error, the result is '""'

  • jsonAsObjectDeleteByKey(<jsonstr>, <keystr>`) : jsonstring` //since 4.11.6.4: [W/L/M]
    returns a string with a JSON object. This object is the given <jsonstr>, where the value of the key - value pair with the key <keystr> is removed.

  • jsonAsArrayPutObjectByIndex(<jsonstr>, <indexstr>, <objectstr>`) : jsonstring` //since 4.11.6: [W/L/M]
    returns a string with a JSON array. This array is the given <jsonstr>, where at the index <indexstr> the object <objectstr> is set.
    In case of an error, the result is '""'

  • jsonAsArrayDeleteObjectByIndex(<jsonstr>, <indexstr>`) : jsonstring` //since 4.11.6.4: [W/L/M]
    returns a string with a JSON array. This array is the given <jsonstr>, where the object at the index <indexstr> is removed.
    In case of an error, the result is '""'

  • jsonAsArrayToStringList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M]
    returns a stringlist that contains the elements of the given JSON array <jsonstr>, with one element per line.

  • jsonStringListToJsonArray(<strlist>`) : jsonstr` //since 4.11.6: [W/L/M]
    returns a string that contains a JSON array that is constructed from the given string list <strlist>, where every line of this list is handled as one array element.

  • jsonAsObjectGetKeyList(<jsonstr>`) : stringlist` //since 4.11.6: [W/L/M]
    returns the list of keys that are found in the JSON object <jsonstr>.

Example: Restoring productOnClient entries from a file to the server:

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%',
					]

9.6. Calculating with numbers [W/L/M]

opsi-script scripts do not have a special type of varibles for numbers. But there are some functions to help calculating with numbers.

  • calculate(<arithmetic string expression>`) : string (number)`
    this string function calculates the arithemtic expression of the string <str> and returns the rounded result as a string.
    Internally the calculations are done with real numbers. This function acceptsthe operators +, -, , / and round brackets (,).
    In case of an error, an empty string is returned and the error counter is incremented. If the passed string contains any characters other than numbers, valid operators and brackets, this results in an error.
    If the second operand is missing, the first operand is also taken as the second operand and vice versa: 5+ = 10 ; 5
    = 25. So the strings that are used to assemble the argument should be validated by the funktion isNumber.
    (since version 4.11.3.5)
    see also : [isNumber]

Example:

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

For more examples refer to the product 'opsi-script-test' at the section '$Flag_calculate$ = "on"'

There is as well a comparison expression for comparing Strings as (integer) numbers. If any of them cannot be converted to a number an error will be indicated.
This number comparison expression has the same form as the String comparison but for an INT prefix of the comparison sign:
<String expression> INT<comparison sign> <String expression>
Such, we can build expressions as

if $Name1$ INT<= $Name2$

or

if $Number1$ INT>= $Number2$

  • isNumber(<str>`) : bool` //since 4.11.3: true if <str> represents an integer [W/L/M]
    Boolean function which returns 'true' if <str> represents an integer.
    see also : [calculate]

9.7. XML2 Functions [W/L/M]

The XML2 implementation is new (4.2019 Version 4.12.1). This means some parts of the implementation may be incomplete. So some things wil be subject of changes. If you find some problems or have need for additional features, do not hasitate to contact us.
These 'XML2' section and functions replaces the older and Windows only 'XMLPatch' section XMLPatch Sections.

For the wording in this chapter see the chapter 'XML2 Sections' / 'XML structure and wording' XML structure and wording

Encoding

XML files are normally encoded in UTF-8. So the 'XML2' functions expect the given XML files in UTF-8.
The XML2 Section also expect the encoding of the given xml file should be UTF-8 by default but here we have the possibility to work also with different encodings.

getXml2DocumentFromFile(<path to xml file>`) : xml2stringlist` //since 4.12.1
Reads the xml file <path to xml file> and returns a string list that may be used in other xml2 functions as <xml2stringlist>
For example see 'XML2 Sections' / 'Examples' XML2 Examples

getXml2Document(<stringlist with xml>`) : xml2stringlist` //since 4.12.1
If <stringlist with xml> contains valid xml data the function returns a string list that may be used in other xml2 functions as <xml2stringlist>

xml2GetFirstChildNodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1.
Searches in the given <xml2stringlist> the first occurence of a node with the name <node name str> and returns this node (with all child nodes) as a xml2stringlist.
For example see 'XML2 Sections' / 'Examples' XML2 Examples

getXml2UniqueChildnodeByName(<xml2stringlist>, <node name str>`) : xml2stringlist` //since 4.12.1.
Searches in the given <xml2stringlist> the occurences of a nodes with the name <node name str> and if there is only one, this one is returned (with all child nodes) as a xml2stringlist.
If there is none or more than one child found, a empty string list is returned.

getXml2AttributeValueByKey(<xml2stringlist>, <attr name str>`) : string` //since 4.12.1.
Searches in the given <xml2stringlist> the first node and in this node an attribute with the name <attr name str> and returns the value of this attribute.
If not found or on any other error, a empty string will be returned.
For example see 'XML2 Sections' / 'Examples' XML2 Examples

getXml2Text(<xml2stringlist>`) : string` //since 4.12.1.
Returns the xml data given by <xml2stringlist> as a single line string.

9.7.1. TOML files Functions [W/L/M]

Starting from opsi-script v. 4.12.5, opsi-script allows TOML files handling.

opsi-script currently does not support the handling of comments within TOML files. Pasting data into tables/areas with comments may delete them.
The official TOML spezifications can be found here: https://toml.io/en/
Encoding

TOML files are usually encoded in UTF-8. So the 'TOML' functions expect the given TOML files to be in UTF-8.

Description of the TOML functions available in opsi-script

The following functions can be used in an opsiscript file:

  • LoadTOMLFile(<TOMLfilePath: String>`) : StringList` //since 4.12.5.0
    Loads the TOML file <TOML file path> and returns a string list of the file content

  • ReadTOMLFile(<TOMLfilePath: String>`) : String` //since 4.12.5.0
    Reads the TOML file <TOML file path> and returns a string of the file content.
    This String is the one to be used for manipulating TOML files in the upcoming functions.

Please keep in mind that this function does not preserve comments.

  • GetTOMLAsStringList(<TOMLcontents: String>`) : StringList` //since 4.12.5.0
    Parses the TOML String contents <TOMLcontents> and returns a String List of the parsed TOML content.

  • GetTOMLAsString(<TOMLcontents: String>`) : String` //since 4.12.5.0
    Parses the TOML String contents <TOMLcontents> and returns a String of the parsed TOML content.

  • GetTOMLKeys(<TOMLcontents: String>`) : StringList` //since 4.12.5.0
    Searches in the given <TOMLcontents> String for all the keys of the root table and returns a stringList of the found keys.
    If no key is found, an empty string list will be returned.

This function only returns the keys of the given String, parsed as a root table, including the names of its sections(sub-tables). It does not include the keys of any sub-Table.

  • GetTOMLTableNames(<TOMLcontents: String>`) : StringList` //since 4.12.5.0
    Searches in the given <TOMLcontents> String for all the tables of the root table and returns a stringList of the found tables' names.
    If no table is found, an empty string list will be returned.

  • GetTOMLTable(<TOMLcontents: String> , <table name : String>`) : StringList` //since 4.12.5.0
    Searches in the given <TOMLcontents> for a table with the given <table name> and returns a String List of the found Table content.

  • GetTOMLTableAsString(<TOMLcontents: String> , <table name : String>`) : String` //since 4.12.5.0
    Searches in the given <TOMLcontents> for a table with the given <table name> and returns a String of the found Table content.

  • GetValueFromTOML(<TOMLcontents: String> , <keyPath: String> , <defaultValue: String>`) : String` //since 4.12.5.0
    Searches in the given <TOMLcontents> String for the key defined with the <keyPath>, which is :

    • A simple key name if the key is in the root table.

    • A composed key path : a succession of the tables' names containing the searched key-value pair. For example : "Table.subTable.key"
      and returns a String of the corresponding value, if found.

If the given key is not found, or the given key path is incorrect or incomplete, or no value was found, the input <defaultValue> string will be returned.

This function returns the exact value as a String output. So, for example if the searched value is a string with content "opsi", the result of this function is : '"opsi"'

  • ModifyTOML(<TOMLcontents: String> , <command: String> , <keyPath: String> , <value: String>`) : String` //since 4.12.5.0
    This function allows to modify the <TOMLcontents> String given as input with the help of 4 commands :

    • 'ADD' : Adds the input <keyPath>-<value> pair if the key does not exist. It returns a new modified TOMLcontens String.
      But, if the <keyPath> exists, this function does not do any modifications. The same input <TOMLcontents> String will be returned.

    • 'SET' : Sets a new <keyPath>-<value> pair if the key does not exist, and even if it exists. The corresponding value will be changed with the new input <value>.
      The function returns the new modified TOMLcontens String.

    • 'CHANGE ' : Changes the corresponding value of the input <keyPath> to the given <value>. It returns a new modified TOMLcontens String.
      But if the keyPath does not exist, nothing will be done. The same input <TOMLcontents> String will be returned.

    • 'DEL' : Deletes the <keyPath> and its found value. It returns a new modified TOMLcontens String.
      But if the keyPath does not exist, nothing will be done. The same input <TOMLcontents> String will be returned.

If any treatment exception occurs, the same input <TOMLcontents> String will be returned.
If any error occurs, an empty String will be returned.

Keep in mind that adding new values must respect the TOML notation within the input String parameter.

For example :

  • if you want to add a String type value with the content "New value", it should be written between double quotes as follows :
    <value> = ' "New value" '

  • if you want to add a Boolean type value with the content True, it should be written as follows :
    <value> = ' True '

  • if you want to add a Number type value with the content 1.1, it should be written as follows :
    <value> = ' 1.1 '

  • if you want to add an Array type value with the content ["first value", "second value"], it should be written as follows :
    <value> = ' ["first value", "second value"] '

  • if you want to add a Date type value with the content 2022-02-02T16:16:00Z-16:16, it should be written as follows :
    <value> = ' 2022-02-02T16:16:00Z-16:16 '

All detailed examples are included in the following opsi-script example.

  • DeleteTableFromTOML(<TOMLcontents: String> , <tablePath: String>`) : String` //since 4.12.5.0
    Deletes the whole given <tablePath>, with its key-values and sub-tables if they exist, from the given <TOMLcontents> String.
    If the given <tablePath> is not found, no modifications are done and the same input <TOMLcontents> string will be returned.

  • SaveToTOMLFile(<TOMLcontents: String> , <TOML file Path: String>`) : boolean` //since 4.12.5
    This function gives back the input <TOMLcontents> String to a formatted TOML file content and stores it in the given <TOML file Path>.
    If saving the file run without errors, "True" will be returned.
    If any errors occur, "False" will be returned.

  • ConvertTOMLtoJSON(<TOMLcontents: String>`) : String` //since 4.12.5.0
    Converts the given <TOMLcontents> String to a JSON formatted String.

  • ConvertTOMLfileToJSONfile(<TOMLfilePath: String> , <JSONfilePath: String>`) : boolean` //since 4.12.5.0
    This function converts the content of the first given <TOMLfilePath> to a JSON formatted content and saves it in the second given <JSONfilePath>.
    If saving the file run without errors, "True" will be returned.
    If any errors occur, "False" will be returned.

Example:

File "TOMLfile.toml" is:

# 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$))

After running the script, the content of the TOML-File is:

# 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" ]

9.8. Regular expression related functions [W/L/M]

Working with regular expressions has some disadvantages:
Finding the correct regular expression can be difficult. So use tools to test your expressions.
Code written with regular expressions is hard to read.
Make comments in your code that explain what you try to do.

There are different kinds of regular expressions: Perl, Javascript, Java, …​
The kind of regular expression implemented here is a variant of the perl style or PCRE.
A detailed documentation of the here used variant you will find at:
https://regex.sorokin.engineer/en/latest/regular_expressions.html

You should use a tool to test your regular expression.
We recommend the 'opsi-regexpr-tester.exe' application. You can download it here:
https://download.uib.de/opsi4.2/misc/helper/opsiRegExprTest.exe

  • opsi-regexpr-tester.exe

This application (opsi-regexpr-tester.exe) helps you test your Regular Expression.

opsi-regexpr-tester-start

The user interface of 'opsi-regexpr-tester' offers you two fields : First field ('Regular Expression :') is where you are asked to input the Regular Expression you want to test. Second field ('Text :') is where you should input the text on which you want to test your regular expression. Then, you can insert Pattern Modifiers Flags, explained in details in the documentation previously mentioned : https://regex.sorokin.engineer/en/latest/regular_expressions.html
We propose 6 flags :

  • i, case-insensitive

  • m, multi-line strings

  • s, single line strings

  • g, greediness

  • x, eXtended syntax

  • r, Russian ranges

You can select the ones you want to insert by checking the corresponding box. They will be automatically added at the beginning of the 'Regular Expression :' field. Please note that the flags are always put before the corresponding regular expression part !

Finally, you can click on the button "Examine" to test your Regular Expression.

opsi-regexpr-tester-input

If your regular expression matches the text or part of it, a successful result will appear, and the matches will be coloured in green on you text.

opsi-regexpr-tester-success

If your regular expression does not match the text or any part of it, a failure text result will appear.

opsi-regexpr-tester-failure

You can clear both the Regular Expression and the Text fields by clicking on the button "Clear".

  • isRegexMatch(<string>, <pattern>`) : boolean`
    It will return 'true' if the pattern matches the string and return 'false' if pattern does not matches the string,
    where pattern is the regular expression and the string would be searched for the matches.

Example:

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`
    It will extract a sublist from target list by matching a single pattern,
    where sublist is a list of whole lines containing the pattern.

  • getSubListByContainingRegex(<pattern list>, <target list>`) : stringlist`
    It will extract a sublist from target list by matching a list of patterns,
    where sublist is a list of whole lines containing any of the patterns in the pattern list.

Example:

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`
    It will extract a sublist from the target list by matching a single pattern,
    where sublist is a list of exact matches for the pattern.

  • getRegexMatchList(<pattern list>, <target list>`) : stringlist`
    It will extract a sublist from the target list by matching a list of patterns,
    where sublist is a list of exact matches for any of the patterns in the pattern list.

Example:

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`
    remove whole matching lines for a single pattern.

  • removeFromListByContainingRegex(<pattern list>, <target list>`) : stringlist`
    remove whole matching lines for any of the patterns in the pattern list.

Example:

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`
    Replace exact matches in string with the replacement string.

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`
    Replace exact matches in the target list with the replacement string.

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

For further examples see the product 'opsi-script-test' expecially the file sub-scripts/regex.opsiscript

9.9. URL related functions [W/L/M]

These functions can be used to analyze and create URLs.

They convert string URLs to a string list with the URL components:

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

  • parseUrl(<url string>`) : stringlist`
    Return url components as stringlist for the given <url string>.

Example:

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`
    return url string for the given urlcomponents.
    The <urlcomponents list> has not to be complete. You may give only the needed parts.

Example:

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

For further examples see the product 'opsi-script-test' expecially the file sub-scripts/urlparser.opsiscript

9.10. Network related functions [W/L/M]

  • isValidIP4 (<ip4adr>`) : boolean`
    return true if the IPv4 address is valid.

Example:

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`
    return true if the given ipv4 address is a valid network address
    Netmask can be given in both cidr and dotted-decimal notation.

Example:

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`
    return true if the given ipv4 address is a valid host address
    Netmask can be given in both cidr and dotted-decimal notation.

Example:

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`
    return network address for the given IP address and netmask.
    Netmask can be given in both cidr and dotted-decimal notation.

Example:

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`
    return default netmask for the given IPv4 address

Example:

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
    Returns the netmask (dotted decimal notation) for the given IPv4 CIDR-Suffix.
    cidr ⇐ 0 results to "0.0.0.0"
    cidr >= 32 results to "255.255.255.255"
    Empty or invalid input results to an empty string
    see also : [netmaskToCidr]
    see also : [getDefaultNetmaskByIP4adr]
    see also : [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
    returns true if the input string is a Fully Qualified Domain Name (FQDN) and false if not. A Fully Qualified Domain Name (FQDN) has the following conditions :

    • Its total length should not exceed 254 characters,

    • It should have at least 3 dot-separated labels,

    • Each label’s length should not exceed 63 characters,

    • Labels contain only letters, numbers and dashes,

    • The last label (TLD) should contain only letters and should have at least 2 characters,

    • Each label starts with a letter or a number (no dashes)

Example:

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$)

For further examples see the product 'opsi-script-test' expecially the file sub-scripts/networkcalc.opsiscript

9.11. Process and Script Related functions [W/L/M]

  • waitForPackageLock(<seconds timeout string>,<bool should we kill>`) : bool` //since 4.11.6.1 [L]
    Returns true if the Linux package system is not locked by an other process. If it is locked, it waits <seconds timeout string> to get the lock. If the timeout is reached and <bool should we kill> is true than the locking process is killed but using this feature ist not recommended.

  • processIsRunning(<process name>`) : boolean` //since 4.11.6.1 [W/L/M]
    Returns true if <process name> is found in the process list

isProcessChildOf(<searchprocstr>, <parentprocstr>): bool //since 4.12.4.35 [W/L/M]
Returns true if the process <searchprocstr> is a child of <parentprocstr>.
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]
    Executing <command string> with the standard shell (cmd.exe / bash)

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

Is a shortcut for this expression:

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

[DosInAnIcon_netstart]
net start

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

shellCall('net start')

Is a shortcut for this expression:

DosInAnIcon_netstart winst /sysnative

[DosInAnIcon_netstart]
net start

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

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

Is a shortcut for this expression:

DosInAnIcon_netstart winst /sysnative
set $exitcode$ = getLastExitcode

[DosInAnIcon_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]
    Runs <command string> with the powershell.
    More exactly the powershell runs a script that looks like:

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

The first line of the script makes sure that we get no exit code = 0 if the script fails with an exception. The last line gives the exit code of previous command back.
The architecture of the called powershell.exe is sysnative by default. Using the optional second parameter <access str> you may change this default. In this case it has to be one of the following values: 32bit, sysnative, 64bit.
(see also: Chapter 64 Bit)
By Windows default the powershell has the execution policy Retricted which do not allow to run any unsigned scripts. In order to run scripts the powershellCall function does by default the following: The current execution-policy is backuped and the execution-policy is set to RemoteSigned. Then the script will be executed and finally the execution-policy is restored. This default behaviour may be switched off by setting the optional third parameter <policy bool str> to "false".
If the powershellCall function is called where a stringlist is expected it returns a stringlist that contains the output of <commandstr>.
Since 4.12.4.35:
If the ExecutionPolicy AllSigned is detected, the powershell will be modified from calling the temporay script by -File to -Command Get-Content -Path <tempfilename> | Out-String | Invoke-Expression. In this mode the ExecutionPolicy is ignored. In this mode any given PASSPARAS are also ignored.
Since 4.12.4.28:
The optional <optionstr> may be used to pass additional modifiers to the function. Because the fucton powershellcall calls internal an Execwith section, all possible Excewith modifier maybe also given in the <optionstr>. For details see here: Section 10.16.1.

Example:

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

Is a shortcut for this expression:

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

  • 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]
    see [powershellCall_list]
    The function powershellCall may also be called where no result is expected.

Example:

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]
    see [powershellCall_list]
    If the powershellCall function is called where a string is expected it returns a string that contains the exit code of the executed script.

Example:

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

  • processCall(<string>`) : string (exitcode)` //since 4.11.6.1 [W/L/M]
    Starts the command binary <string> as process and returns te exitcode

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

Is a shortcut for this expression:

Winbatch_setup
set $exitcode$ = getLastExitcode

[Winbatch_setup]
setup.exe /S

In fact processCall is internal a winbatch call, so all the winbatch modifiers are also allowed for processCall

  • /LetThemGo
    This is the contrary to /WaitOnClose. It is used if opsi-script shall proceed while the started processes run in their own threads.

  • /TimeOutSeconds <seconds>
    A timeout setting. After waiting <seconds>, opsi-script will end the process.
    Since version 4.11.3, /TimeOutSeconds may be used without a waiting condition (e.g. /WaitForProcessEnding) but not in combination with /WaitSeconds.
    Since version 4.11.4.6 the time progress from start until timeout is displayed by the progressbar.

  • /WaitSeconds [number of seconds]
    If a call includes the parameter /WaitSeconds [number of seconds], then opsi-script is waiting for [number of seconds] before proceeding. In the default configuration, we also wait for any programs that are currently running to finish. If we combine the parameter /WaitSeconds with the option /LetThemGo, then opsi-script continues processing after the waiting time is finished.

  • /WaitForProcessEnding <program name>
    Waits for the process called <program name> to end.
    Should be combined with /TimeOutSeconds.

  • /32Bit //since 4.11.3.5 [W]
    This is the default. The paths within the section are assumed to be 32 bit pathes.
    Example: c:\windows\system32\regedit.exe calls (even when running on a 64 bit system) the 32 bit 'regedit.exe'.

  • /64Bit //since 4.11.3.5 [W]
    The paths within the section are assumed to be 64 bit paths.
    Example: c:\windows\system32\regedit.exe executes (running on a 64 bit system) the 64 bit 'regedit.exe'.

  • /SysNative //since 4.11.3.5 [W]
    The paths within the section are assigned according to the OS architecture interpretiert.
    Example: c:\windows\system32\regedit.exe running on a 64bit system calls the 64 bit 'regedit.exe' and running on a 32 bit system the 32 bit 'regedit.exe'.

9.12. Special Commands [W/L/M]

  • Killtask <process name> ` : noresult` [W/L/M]
    tries to stop all processes that execute the program named by the string expression.
    E.g.

killtask "winword.exe"

  • ChangeDirectory <directory> ` : noresult` //since 4.11.2.6 [W/L/M]
    Set the given directory as working directory of the opsi-script. Affects all subsequent actions (e.g. winbatch sections) and will be reset at the end of a script. Beispiel :

ChangeDirectory "%SCRIPTPATH%\programm"

  • UpdateEnvironment //since 4.11.5.1 [W]
    Sends Windows the signal to reload the environment values from the registry. This statement may be called after any rocess that may have changed the environment (e.g. Registry section or setup program). Even if the program that runs after the opsi-script get the new environment, the next process that is started (via DosBatch or Winbatch) from this opsi-script instance will still inherit the old environment. To start a subsequent process with the new environment you have to use winbatch with the /RunElevated parameter.
    Works only with NT6 and up.

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]
    breaks the program execution for <string> seconds. <string> has to represent an Integer Value

  • markTime [W/L/M]
    sets a time stamp for the current system time and logs it.

  • diffTime [W/L/M]
    logs the time passed since the last marktime.

Example:

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

9.13. Control the logging

  • comment <string> or comment = <const string> [W/L/M]
    writes the value of the String expression resp. the sequence of characters into the log file.

  • LogError <string> or LogError = <const string> [W/L/M]
    writes additional error messages to the log file and increments the error counter by one.

  • LogWarning <string> or LogWarning = <const string> [W/L/M]
    writes additional warning messages to the log file and increments the warning counter by one.

  • 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]
    Includes the file <file name> as a log file, where the last <tail size> lines of the full log are written into this log file. If you start another program that produces a log file, you could see that other program’s log file in the opsi-script script log using this command.
    Since version 4.11.3.2, a negative <tail size> can be given, which will then include the first <tail size> lines from the top of the log file (referred to as 'Head' mode).
    Since version 4.11.4.1 there is an optional third parameter which may be used to give the encoding of the file to include. You may give one of the well known encodings described in the encodings chapter. If you give 'auto' opsi-script try to detect the encoding (and may fail). The default is 'system' which means the default OS encoding is used.
    Example:

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

  • SetConfidential <secret string> [W/L/M]
    This is to prevent confidential information (like passwords) from being logged. In the logfile the confidential information will be replaced by '(confidential)'.
    When the loglevel is set to '9', the confidential information will be logged.
    (since version 4.11.3.5)

Example:

message "SetConfidential"
SetConfidential "forbidden"
comment "This is a forbidden string"
comment "shown in the 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]
    This function should be used to get confidential strings from an other string function without without logging the secret string. The Function work in the following sequence:

    1. Backup the current log level.

    2. Set the log level to Warning. (4)

    3. Resolve the given string expression (for example calling the given string function).

    4. Add the resulting string to the list of confidential strings that should be not logged..

    5. Restore of the inital log level.

    6. Return the resulting string.

Example:

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.

9.14. Commands for User Information and User Interaction [W/L/M]

  • Message <string expression>
    bzw.
    Message = <sequence of characters>
    lets opsi-script display the value of the String expression resp. the sequence of chars in the batch window in the top information line. The text is kept as long as no new message is set.
    Example:

Message "Installation von "+$productid$

  • ShowMessageFile <file name>
    interprets the String expression as text file name, tries to read the text and show it in a user information window. Execution stops until the user confirms reading. E.g. by a command like

ShowMessageFile "p:\login\day.msg"

one can realize a "Message of the Day" mechanism.

  • ShowBitMap [<image name>] [<inscription>]
    places the image denoted by the <image name> (in BMP, JPEG or PNG format, size 160x160 pixel) and shows the inscription.
    <image name> and <inscription> are String expressions.
    Example:

ShowBitmap "%scriptpath%\" + $ProductId$ + ".png"  "$ProductId$"

  • Pause <string> or Pause = <const string>
    display the text given as a String expression or as a sequence of chars in a information window waiting until the user confirms the continuation.

  • Stop <string> or stop = <const string>
    halt program execution if the user confirms it. The String expression resp. the (possibly empty) sequence of chars explain to the user what is supposed to be stopped.

  • setActionProgress <string> : noresult //since 4.11.3 [W/L/M]
    Transfers <string> as ActionProgress of the running script to the opsi server. By Default the ActionProgress is 'installing' while a script is running. The value of ActionProgreas is displayed at the configed.

9.15. Commands for userLoginScripts / User Profile Management

  • GetScriptMode //since 4.11.2.1
    give one of the possible values 'Machine','Login':

    • 'Machine' - the script is not running as 'userLoginScript'

    • 'Login' - the script is running as 'userLoginScript'

  • GetUserSID(<Windows Username>`)`
    see also : [GetUserSID]

  • GetLoggedInUser //since 4.11.1.2

  • GetUsercontext //since 4.11.1.2
    returns the username in whose context the opsi-script is just running.
    see also : [GetUsercontext]

  • saveVersionToProfile //since 4.11.2.1
    save productversion-packageversion to local profile
    It is designed to be used in 'userLoginScripts'.
    This command is used in combination with readVersionFromProfile or scriptWasExecutedBefore. It marks that the 'userLoginScript' for this product in this product version and package version was excuted for the actual user. The inrormation is saved at the file "%CurrentAppdataDir%\.opsi.org\userLoginScripts.ini"

  • readVersionFromProfile //since 4.11.2.1
    returns a string with the productversion-packageversion for the running opsi product which was read from local profile. See also: saveVersionToProfile
    It is designed to be used in 'userLoginScripts'.

  • scriptWasExecutedBefore //since 4.11.2.1
    This Boolean function scriptWasExecutedBefore checks if there is a version stamp in the profile (like you may do with the readVersionFromProfile command) It returns 'true' if saved and running productversion-packageversion are identical. Then it set a new stamp to the profile (like you may do with the saveVersionToProfile command). So you may just use this single command in a if statement.
    It is designed to be used in 'userLoginScripts'.

  • isLoginScript //since 4.11.2.1
    This booleasn function returns 'true' if the script is running as 'userLoginScript'. See also: GetScriptMode
    see also : [GetScriptMode]

9.16. for to do loop

Useful for multiple calls of a single command or of a sub-section

Syntax:

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

The temporary varibale %<temporary string variable>% must not be declared and is available in the called sub-section as constant.

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%'

produces the 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

9.17. Switch / Case Statement [W/L/M]

Syntax:

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

Switch / Case can not be nested (it is not allowed to have switch insied of a case).
There is an other possibillity for the same purpose: You may use the since 4.12.4.37 possible if-elseif-else statements. These if-elseif-else statements can be nested. see: [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

9.18. Conditional Statements (if Statements)

In primary sections, the execution of a statement or a sequence of statements can be made dependent on some condition.

Example

;Which 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

Since version 4.12.4.37 opsi-script also can handle a elseif statement.

Example:

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

9.18.1. General Syntax

The syntax of the complete if statement is:
if <condition>
<sequence of statements>
elseif
<sequence of statements>
else
<sequence of statements>
endif

The else part may be omitted.
The elseif part may be omitted.

if statements may be nested. That is, in the sequence of statements that depend on an if clause (no matter if inside the if or the else or the elseif part) another if statement may occur.

<condition> is a <Boolean expression> . A Boolean (or logical) expression can be constructed as a (String) value comparison, by Boolean operators, or by certain function calls which evaluate to true or false. Up to now these Boolean values cannot be explicitly represented in a opsi-script script).

9.18.2. Boolean Expressions

The String comparison (which is a Boolean expression) has the form
<String expression> <comparison sign> <String expression>
where <comparison sign> is one of the signs
< = >= >

String comparisons in opsi-script are case independent.

Inequality must be expressed by a NOT() expression which is presented below.

There is as well a comparison expression for comparing Strings as (integer) numbers. If any of them cannot be converted to a number an error will be indicated.
This number comparison expression has the same form as the String comparison but for an INT prefix of the comparison sign:
<String expression> INT<comparison sign> <String expression>
Such, we can build expressions as

if $Name1$ INT<= $Name2$

or

if $Number1$ INT>= $Number2$

Boolean operators are AND, OR, and NOT() (case does not matter). If b1, b2 and b3 are Boolean expressions the combined expressions
b1 AND b2
b1 OR b2
NOT( b3 )
are Boolean expressions as well denoting respectively the conjunction (AND), the disjunction (OR) and the negation (NOT).

A Boolean expression can be enclosed in parentheses (such producing a new Boolean expression with the same value).

The common rules of Boolean operator priority ("and" before "or") are at this moment not implemented. An expression with more than one operator is interpreted from left to right. For clarity, in a Boolean expression that combines AND and OR operators parentheses should be employed, e.g. we should explicitly write b1 OR (b2 AND b3)
or
(b1 OR b2) AND b3
The second example describes what would be executed if there were no parentheses - whereas the common interpretation would run as the other line indicates.

Boolean operators can be conceived as special Boolean valued functions (the negation operator demonstrates this very clearly).

There are some more Boolean functions implemented. Every call of such a function constitutes a Boolean expression as well:

  • FileOrFolderExists (<file or folder path> [,<access str>]) : boolean //since 4.12.4.14 [W/L/M]
    returns 'true' if the denoted file or directory exists, otherwise 'false'.+ The optional second parameter <access str> is only for Windows : You should enter '32bit', '64bit' or 'sysnative'.Otherwise, 'sysnative' is the default for <access str>. see Chapter 64 Bit support
    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>) // since 4.12.4.21 [W/L/M]
    returns 'true' if the denoted file exists and is a symbolic link, otherwise 'false'.

  • LineExistsIn (<string>, <file name>`) : bool` [W/L/M]
    returns 'true' if the text file denoted by <file name> contains a line as specified in the first parameter where each parameter is a String expression. Otherwise (or if the file does not exist) it returns 'false'.

  • LineBeginning_ExistsIn (<string>, <file name>`) : bool` [W/L/M]
    returns 'true' if there is line that begins with <string> in the text file denoted by <file name> (each parameter being a string expression). Otherwise (or if the file does not exist) it returns 'false'.

  • LineContaining_ExistsIn( <string>, <file name> ) : bool [W/L/M]
    returns 'true' if there is line that contains <string> in the text file denoted by <file name> (each parameter being a string expression). Otherwise (or if the file does not exist) it returns 'false'.

  • XMLAddNamespace(<XMLfilename>, <XMLelementname>, <XMLnamespace>)
    inserts a XML namespace definition into the first XML element with the given name (if not existing). It gives back if an insertion took place. (The opsi-script XML patch section need the definitions of namespace.)
    The file must be formatted that an element tag has no line breaks in it. For an example, cf. cookbook Section 12.7.

  • XMLRemoveNamespace(<XMLfilename>, <XMLelementname>, <XMLnamespace>)
    removes the XML namespace definition from the XML element. It gives back if an removal took place. We need this to simulate that an original file is unchanged. For an example, cf. cookbook Section 12.7.

  • HasMinimumSpace(<Laufwerksname>, <Kapazität>)
    returns true if at least a capacity capacity is left on drive drivename. capacity as well as drivename syntactically are String expressions. The capacity may be given as a number without unit specification (then interpreted as bytes) or with unit specifications "kB", "MB", or "GB" (case independent).
    Example:

if not (HasMinimumSpace ("%SYSTEMDRIVE%", "500 MB"))
  LogError "Not enough space on %SystemDrive%, 500MB on drive %SystemDrive% needed"
  isFatalError
endif

  • opsiLicenseManagementEnabled : bool
    returns 'true' if the opsi license management module is enabled.

  • runningAsAdmin
    Returns 'true' if the currently running script was executed with Administrator privileges.
    Available since 4.11.1.1

  • isLoginScript
    Returns 'true' if the currently running script was called as 'userLoginScript' using the opsi extension 'User Profile Management'.
    Available since 4.11.2.1
    see also : [isLoginScript]

  • contains(<str>, <substr>`) : bool` //since 4.11.3: true if <substr> in <str> [W/L/M]
    Boolean function which returns 'true' if <str> contains <substr>. This function is case sensitive.
    see also : [contains]

  • isNumber(<str>`) : bool` //since 4.11.3: true if <str> represents an integer [W/L/M]
    Boolean function which returns 'true' if <str> represents an integer.
    see also : [isNumber]

  • runningOnUefi
    Boolean function which returns 'true' if the running OS was booted in UEFI mode.
    Available since 4.11.4.3

  • runningInPE //since 4.12.0.13: [W/L/M]
    true if the running OS is a Windows PE

  • runningInWAnMode //since 4.12.4.16: [W/L/M]
    Boolean function which returns 'true' if at the running opsi-service context the opsiserver = localhost is.

  • isDriveReady(<drive letter>`)` //since 4.11.4.4: [W]
    true: if the drive can be accessed

  • saveTextFile(<list>, < filename>`) : bool` [W/L/M]
    true: if list is succesfully written to file

  • saveTextFileWithEncoding(<list>, < filename>, <encoding>`) : bool` //since 4.11.6.4 [W/L/M]
    true: if list is succesfully written to file [W/L/M]

  • saveUnicodeTextFile(<list>, < filename>, <encoding>`) : bool` //since 4.12.4.14 [W/L/M]
    specific for unicode encoding
    returns true: if list is succesfully written to unicode file [W/L/M]

  • CompareDotSeparatedNumbers(<str1>,<relation str>,<str2>`) : bool` //since 4.11.5.2: [W/L/M]
    compares two strings of the form <number>[.<number>[.<number>[.<number>]]]
    by the <relation str> which may be one of [<,⇐,=,>=,>].
    Since version 4.12.4.28:

  • While comparing a pair of <number>, if at least one of them has leading zeros, then the comparison is done as if these <number> were the fractional part of a floating number, i.e. 17 > 018 because 0.17 > 0.018.

  • While comparing a pair of <number>, if at least one of them has as last a non-numeric char then the comparison uses in the first step the leading number part. In case of equality, a comparison of the trailing chars is done. E.g. 1.23a < 1.23b and 1.24a > 1.23b. see also: string function CompareDotSeparatedNumbers(<string1>, <string2>`)` : [CompareDotSeparatedNumbers_str]
    see also: string function CompareDotSeparatedStrings(<string1>, <string2>`)` : [CompareDotSeparatedStrings_str]
    see also: [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

Additional since 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]
    Check if the given string expression <regkey> exists as registry key. If the registry key was found the result value ist true in all other cases false.
    By Default the registry access mode is sysnative. Using the optional second parameter <access str>, the access mode can be explicitly given. In this case it has to be one of the following values: 32bit, sysnative, 64bit.
    (see also: Chapter 64 Bit support)

Examples:

RegKeyExists("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon")

RegKeyExists("HKEY_LOCAL_MACHINE\SOFTWARE\opsi.org\general","32bit")

  • RegVarExists(<regkey>, <var str> ) : bool //since 4.12.0.16 [W]
    Check if the given string expression <regkey> exists as registry key and if there is a variable with name <var str>. If both was found the result value ist true in all other cases false.
    By Default the registry access mode is sysnative. Using the optional second parameter <access str>, the access mode can be explicitly given. In this case it has to be one of the following values: 32bit, sysnative, 64bit.
    (see also: Chapter 64 Bit support)

Examples:

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] true: if the running OS has a GUI (at Win+Mac always true)[M/L/W]

isPingReachable(<host>) : boolean //since 4.12.3.6 [W/L/M]
Gives back true if the host given by <host> is reachable by ping. <host> may be a IP-Number or a IP-Name.

9.19. Include Commands

Using include commands can lead to confusing code.
Use with caution if you are a beginner.

9.19.1. Include Commands: Syntax

The include_* commands may be used to add external script files to the currently-running script at runtime. The include_* command can include external script files either as an insert (after the current line) or as an append (after the last line). The include commands may be used anywhere in a primary section. The external script files may contain their own include commands.
The include commands are available since version 4.11.3

  • include_insert <file name>
    inserts <file name> after the current line into the running script. So the first line of the included file is the next line that will be executed by opsi-script.

  • include_append <file name>
    appends the content of <file name> to the running script. This kind of insert is normally used to include sections from a library.

In both cases <file name> is:

  • A complete path to an existing file. [W/L/M]

  • A existing file in %ScriptPath% [W/L/M]

  • A file in %opsiScriptHelperPath%\lib [W]
    Is equivalent to: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • A existing file in %ScriptPath%/../lib [W/L/M]

  • A existing file in %OpsiScriptDir%\lib [W]

The tests for the location of the <file name> are done in the order above. opsi-script uses the first file it finds that has a matching name.

Example:
When we run that contains the following commands:

[Actions]
include_append "section_Files_del_tmp_dummy.opsiinc"
include_insert "include-test1.opsiinc"

The file include-test1.opsiinc is run first. The contents of the included file include-test1.opsiinc are:

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

The contents of the included file section_Files_copy_inctest.opsiinc are:

[Files_copy_inctest]
copy "%scriptpath%\test-files\dummy.txt" "c:\opsi.org\tmp"

Since the call to Files_del_tmp_dummy happens inside of include-test1.opsiinc without section_Files_del_tmp_dummy.opsiinc being referenced inside of include-test1.opsiinc, we must call include_append "section_Files_del_tmp_dummy.opsiinc" at the very beginning of our script. Otherwise, opsi-script will report that Files_del_tmp_dummy is not defined.
The contents of the included file section_Files_del_tmp_dummy.opsiinc are:

[Files_del_tmp_dummy]
del -f "c:\opsi.org\tmp\dummyt.txt"

9.19.2. Include Commands: Library

The following include files are shipped with version 4.11.3, and are located in %OpsiScriptDir%\lib:

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 license pool 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

9.20. Subprogram Calls

Statements in primary sections which refer to instructions declared elsewhere are subprogram calls.,

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

In this example the statement:

sub_install_winXP

"calls" the section titled '[sub_install_winXP]' which is placed somewhere else in the script. E.g. we may have

[sub_install_winXP]
Files_copy_XP
WinBatch_SetupXP

Generally, there are three ways to place the referred instructions:

  • The most common target of a sub program call is some other internal section in the very script file where the calling statement is placed (as in the example).

  • We may put the referred instructions into another file which serves as an external section.

  • Any String list can be used as list of instructions for a sub program call.

We describe the syntax of sub program calls in detail:

9.20.1. Syntax of Procedure Calling

Formally, the syntax can be given by
'<proc. type>(<proc. name> | <External proc. file> | <String list function> )'

This expression may supplemented by one ore ore parameters (procedure type dependent).

That means: A procedure call consists of three main parts.

The first part is the subprogram type specifier.
Examples of type names are 'Sub' (we call a procedure of type sub that is a again a primary section) or 'Files' and 'WinBatch' (calls of special secondary sections). The complete overview of the existing sub program types is given at Subprogram Calls.

The second part determines where and how the lines of sub program are to be found.

  1. The subprogram is a sequence of lines situated in the executed opsi-script script as another internal section. Then a name (constituted from letters, digits, and some special characters) has to be appended to the type specifier (without space) in order to form an unique section name.
    sub_install_winXP
    or
    files_copy_winXP
    Section names are case independent as any other string.

  2. If the type specifier stands alone a String list expression or a String expression is expected. If the expression following the type specifier cannot be resolved as a String list expression (cf. case (3)) it is assumed to be a String expression. The string is then interpreted as a file name. opsi-script tries to open the file as a text file and interprets its lines as an external section of the specified type.
    E.g.
    sub "p:\install\opsiutils\mainroutine.ins" tries to execute the lines of mainroutine.ins as statements of a sub section.

The searche rule is:
<file name> may be:

  • A complete path to an existing file. [W/L/M]

  • A existing file in %ScriptPath% [W/L/M]

  • A file in %opsiScriptHelperPath%\lib [W]
    Is equivalent to: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • A existing file in %ScriptPath%/../lib [W/L/M]

  • A existing file in %OpsiScriptDir%\lib [W]

The tests for the location of the <file name> are done in the order above. opsi-script uses the first file it finds that has a matching name.

  1. If the expression following a pure section type specifier is resolvable as a String list expression the lines of the list are interpreted as the statements of the section.
    This mechanism can e.g. be used to load a file that has unicode format and then treat it by the usual mechanisms

registry loadUnicodeTextFile("%scriptpath%/opsiorgkey.reg") /regedit

Syntactically, this line is composed of three main parts:
* registry, the core statement specifying the section type,
* loadUnicodeTextFile(…​), a String list expression specifying how to get the lines of a registry section resp. its surrogate.
* /regedit, parametrizing the registry call.

In this example, the call parameter already gives an example for the third part of a subsection call:

The third part of a procedure call comprises type specific call options.

For a reference of the call options cf. the descriptions of the section calls in Secondary Sections.

9.21. Controlling Reboot

The command ExitWindows is used to control reboots , shutdown and similar actions which should take place after the opsi-script it self is terminated. The name of the command and the fact that there is no 'ExitWindows' without modifier has histrical reasons: Working on Windows 3.1 you could exit windows to go back to the DOS level.

  • ExitWindows /RebootWanted
    DEPRECATED: a reboot request is registered which should be executed when all installations requests are treated, and the last script has finished.
    In fact, this command is now treated as an ExitWindows /Reboot (since otherwise an installation could fail because a required product is not yet completely installed).

  • ExitWindows /Reboot
    triggers the reboot after opsi-script has finished the currently treated script.

  • ExitWindows /ImmediateReboot
    breaks the normal execution of a script anywhere inside it. When this command is called opsi-script runs as directly as possible to its end entailing the system ExitWindows call. In the context of an installed opsi-client-agent it is guaranteed that after rebooting opsi-script runs again into the script that was aborted. Therefore, the script has to take provisions that the execution continues after the point where it was left the turn before (otherwise we may get an infinite loop …​) Cf. the example in this section.

  • ExitWindows /ImmediateLogout
    The normal execution of a script breaks at the point of the call, and the opsi-script stops running. This behaviour is needed if an automated user log in for some other user shall take place (cf. Section 12.3).

  • ExitWindows /ShutdownWanted
    sets a flag in the registry that the PC shuts down when all installations requests are treated, and the last script has finished.

How flags may be set to ensure that the script does not run into an infinite loop when ExitWindows /ImmediateReboot is called we demonstrate by the following code fragment:

DefVar $OS$
DefVar $Flag$
DefVar $WinstRegKey$

set $OS$=EnvVar("OS")

if $OS$="Windows_NT"

  Set $WinstRegKey$ = "HKLM\SOFTWARE\opsi.org\winst"
  Set $Flag$ = GetRegistryStringValue("["+$WinstRegKey$+"] "+"RebootFlag")

  if not ($Flag$ = "1")
     ;=========================
     ; Statements BEFORE Reboot

     Files_doSomething

     ; initialize reboot ...
     Set $Flag$ = "1"
     Registry_SaveRebootFlag
     ExitWindows /ImmediateReboot

  else
     ;=========================
     ; Statements AFTER Reboot

     ; set back reboot flag
     Set $Flag$ = "0"
     Registry_SaveRebootFlag

     ; the work part after reboot:

     Files_doMore

  endif

endif


[Registry_SaveRebootFlag]
openKey [$WinstRegKey$]
set "RebootFlag" = "$Flag$"

[Files_doSomething]
; a section executed before reboot

[Files_doMore]
; a section executed after reboot

9.22. Abort script and keep track of failed installations

If a product installation fails, then this should be signaled to the server.

Due to the fact that there is no automatic method that detects a failed installation, testing for a failed installation has to be done using script commands.

To indicate in a opsi-script script that the installation is failed we have to call the statement:
isFatalError
If this statement is called, then opsi-script stops the normal execution of the script and sets the product result to 'failed' (otherwise it is 'success').

Since 4.11.3.2 there is a new variant of this command:

  • isFatalError <string>
    in this case, a short error message string is passed as 'actionProgress' to the opsi-server and displayed in the opsi-configed.
    For example, a "fatal error" shall be triggered if there is not as much space left as it is needed for an installation:

DefVar $SpaceNeeded$"
Set $SpaceNeeded$" = "200 MB"

DefVar $LogErrorMessage$
Set $LogErrorMessage$ = "Not enough space on drive . Required "
Set $LogErrorMessage$ = $LogErrorMessage$ + $SpaceNeeded$"

if not(HasMinimumSpace ("%SYSTEMDRIVE%", $SpaceNeeded$))
  LogError $LogErrorMessage$
  isFatalError
  ; finish execution and set ProductState to failed

 else
  ; we start the installation
  ; ...
 endif

It is also possible to state
isFatalError
depending on the number of errors which occured in some critical part of an installation script. In order to do this we initialize the error counting by the command

  • markErrorNumber
    Initialize the error counting.
    The number of execution errors which occur after setting the counter can be queried by the the number valued function errorsOccurredSinceMark+

  • errorsOccurredSinceMark
    We can evaluate the result in a numerical comparison condition (that as yet is only implemented for this expression). E. g. we may state
    if errorsOccurredSinceMark > 0

For increasing the number of counted errors depending on certain circumstances (that do not directly produce an error) we may use the logError statement.

We may test this by the following script example:

markErrorNumber
; Errors occuring after this mark are counted and
; will possibly be regarded as fatal

logError "test error"
; we write "test error" into the log file
; and increase the number of errors by 1
; for testing, comment out this line


if errorsOccurredSinceMark > 0
    ; we finish script execution as quick as possible
    ; and set the product state to "failed"

    isFatalError
    ; but comment writing is not stopped

    comment "error occured"

else
    ; no error occured, lets log this:

    comment "no error occured"
endif

  • isSuccess //since 4.11.3.7 [W/L/M]
    Abort the script as successful.

  • noUpdateScript //since 4.11.3.7 [W/L/M]
    Do not run an update script after setup even if there is one.

  • isSuspended //since 4.11.4.1 [W/L/M] Abort the script without notice to the server. The action request remain unchanged.

9.23. Local functions [W/L/M]

Since version 4.12, the opsi-script has also local functions.

An example:

DefFunc myFunc(val $str1$ : string, $str2$ : string) : string
	set $result$ = $str1$ + $str2$
endfunc

9.23.1. Concept

There are a lot possibilities to structure opsi-script code:

  • sub Sections

  • sub Sections in external files

  • 'include' Statements

But all these possibilities are not functional to create reusable external code that can be exchanged between scripts or opsi administrators without problems. The reason is, that this code is not encapsulated and use global variables.
The defined local functions presented here now solves this problem. With this concept it is possible to write functions that can be collected and maintained in external libraries.
In consequence we will start to build up a central opsi-script library which is maintained by uib and the opsi community.

In order to reach this target we have implemented the following concepts:

  • Functions with return value:
    The functions have a return value which is of the type string or stringlist. Executing such function can be performed wherever a string expression or a stringlist is expected.
    Functions with no return value are also allowed and have to be declared as void (since 4.12.0.16).

  • Freely definable function call parameters:
    Parameters can be passed to a function. These parameters are defined when the function is actually declared. The call parameters can be of type string or stringlist.
    The call parameters are available as local variables within the function.
    The call parameters can be passed as 'CallByValue' or 'callByReference'. 'CallByValue' is the default. That means, if no call method is specified explicitly, then 'CallByValue' will be applied. In the case that 'CallByValue' needs to be explicitly specified, then the keyword val should be used. 'CallByValue' means, that the value of a variable used during the call is copied to the call variable.
    'CallByReference' must be specified explicitly using the keyword ref. 'callByReference' means that a connection is created between the variable used as parameter when calling the function and the local variable that represents the call parameter inside the function. Changing the local variable of the call parameter has a direct effect on the variable used during such call.

  • Local Variables:
    A function contains local variables: Implicitly, the call parameters are available as local variables and the variable $result$ which is from the type of the returned value. Further variables can be defined within the function.
    All these variables are local, which means that they are only visible within this function. A local variable with the same name of a global variable masks the corresponding global variable within the function.

  • Nested functions:
    A local function can in turn have one or even more definitions of local functions. These functions are only visible within the function in which they are defined.

  • Recursive calls:
    A function can call itself recursively.

  • Primary and secondary sections within functions:
    The function body can contain its own sections of it. These are local to this function, that means that these sections are only visible within the function.

9.23.2. Syntax

Definition

DefFunc <func name>([calltype parameter ptype][,[calltype parameter ptype]]) : ftype
<function body>
endfunc

Where:

  • DefFunc is the keyword used to start defining a local function.

  • '<func name>' is the freely chosen name of the function.

  • 'calltype' is the call type of the parameter [val | ref]. val='Call by Value', ref='Call by Reference'. Default: val

  • 'parameter' is the freely selected name of the call parameter which is available as a local variable within the function under the aforementioned name.

  • 'ptype' is the type of data of the parameter and either string or stringlist.

  • 'ftype' is the type of data of the function and either string ,stringlist or void. void declares that no result is returned.

  • '<function body>' is the body of the function which must conform to the opsi-script syntax.
    In this part there is the automaticly decared local variable $result$ which should take the result of the function an so have the data type of the function.

  • endfunc is the keyword used to end defining a local function.

A local function has to be defined before you can call the function.

9.23.3. Examples

Simple function that connects two strings:

[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$)

Expected results:

  • 'heho'

  • 'he42921.809'

  • 'heha'

Function of the type stringlist which will deliver a string and a stringlist:

[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$)

Expected results:

  • $list1$ = [hi,opsi]

Function of type string to which a boolean string will be deliver:

[actions]

DefFunc myFunc2($str1$ : string) : string
	set $result$ = booltostring($str1$)
endfunc

if stringtobool(myfunc2('1 > 0'))
	comment "true"
else
 	comment "false"
endif

Expected results:

  • 'true'

Function of the type string to which a string is passed with local variable:

[actions]
DefVar $mystr$

DefFunc myFunc3($str1$ : string) : string
	DefVar $locstr1$
	set $locstr1$ = '123'
	set $result$ = $locstr1$ + $str1$
endfunc

set $mystr$ = myFunc3("he")

Expected results:

  • '123he'

Function of the type string to which a string is passed with local variable and nested function:

[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")

Expected results:

  • 'outerinner123'

Simple function of type string which pass a` string` by reference with a local 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$

Expected results:

  • '123setinlocal'

  • 'hasetinlocal'

Function of type stringlist which will pass a variable of type stringlist with a 'call by reference' also with a local 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$)

Expected results:

  • $list1$ = [,a,b,c,setinlocal]

  • 'setinlocal'

Function of type stringlist which pass a string with a local variable and a local secondary section:

[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')

Expected results:

  • $list1$ = [+ pwd, /home/uib/gitwork/lazarus/opsi-script]

Function of type void (no return value) which pass a string with a local variable:

[actions]
ScriptErrorMessages = false
DefVar $str1$

set $str1$ = 'haha'

DefFunc myNoResultFunc(ref $str1$ : string) : void
	set $str1$ = "huhu"
endfunc

myNoResultFunc($str1$)
comment "$str1$ is: "+$str1$

Expected results:

  • $str1$ is: huhu

Function of type string with no parameter:

[actions]
ScriptErrorMessages = false
DefVar $str1$

DefFunc myNoParamFunc() : string
	set $result$ = "huhu"
endfunc

set $str1$ = myNoParamFunc()

Expected results:

  • $str1$ is: huhu

9.24. Import of libraries of functions [W/L/M]

importLib <string expr> ; import library // since 4.12.0.0
<string expr> : <file name>[.<file extension>][::<function name>]
If no '.<file extension>' is given .opsiscript is used as default.
If no '::<function name>' is given, all function from the given file will be imported.

<file name> is:

  • A complete path to an existing file. [W/L/M]

  • A existing file in %ScriptPath% [W/L/M]

  • A file in %opsiScriptHelperPath%\lib [W]
    Is equivalent to: '%ProgramFiles32Dir%\opsi.org\opsiScriptHelper\lib'

  • A existing file in %ScriptPath%/../lib [W/L/M]

  • A existing file in %OpsiScriptDir%\lib [W] or /usr/share/opsi-script/lib [L]

The tests for the location of the <file name> are done in the order above. 'opsi-script' uses the first file it finds that has a matching name.

10. Secondary Sections

The secondary sections can be called from any primary section but have a different syntax. The syntax is derived from the functional requirements and library conditions and conventions for the specific purposes. Therefore from a secondary section, no further section can be called.

Secondary sections are specific each for a certain functional area. This refers to the object of the functionality, e.g. file system in general, the Windows registry, or XML files. But it refers even more to the apparatus that is internally applied. This may be demonstrated by the the variants of the batch sections (which call external programs or scripts).

The functional context is mirrored in the specific syntax of the particular section type.

10.1. Calling secondary sections

In most cases a secondary section is called by calling the section header as a statement. As a 'statement' means here: no return value is expected.

Example:

shellInAnIcon_say_hello

[shellInAnIcon_say_hello]
echo "Hello World"

In the case that you have to call the section with modifiers you have to add these modifiers behind the statement as text (no variables are allowed here):

shellInAnIcon_say_hello /timeoutseconds 20

[shellInAnIcon_say_hello]
echo "Hello World"

If you want to examine the output or return values of a section you may use one of the following functions:

  • getOutStreamFromSection(<section with params>)
    for DosInAnIcon (ShellInAnIcon),ExecWith and ExecPython calls. See also getOutStreamFromSection

  • getreturnListFromSection(<section with params>)
    for XMLPatch sections and opsiServiceCall sections. See also getReturnListFromSection

set $list$ = getOutStreamFromSection("shellInAnIcon_say_hello /timeoutseconds 20")

[shellInAnIcon_say_hello]
echo "Hello World"

Using this functions, the complete call of the section (inclusive all parameters and modifiers) has to be one string expression. This gives you the possibility to use variables and functions as part of the section call.

If you want to use this advantages without catching the out streams you may use the following statement:

executeSection(<string expr with section call>`)` //since 4.12.3.9 [W/L/M]
within this statement you may call the following section types:

  • winbatch

  • registry

  • DosBatch, DosInAnIcon, ShellBatch, ShellInAnIcon

  • ExecWith, ExecPython

  • Files

10.2. Files Sections

A Files section mainly offers functions which correspond to copy commands of the underlying operating system. The surplus value when using the opsi-script commands is the detailed logging and checking of all operations when necessary. If wanted overwriting of files can be forbidden if newer versions of a file (e.g. a newer dll-file) are already installed on the system.

10.2.1. Example

A simple Files section could be:

[Files_do_some_copying]
copy -sV "p:\install\instnsc\netscape\*.*" "C:\netscape"
copy -sV "p:\install\instnsc\windows\*.*" "%SYSTEMROOT%"

These commands cause that all files of the directory 'p:\install\instnsc\netscape' are copied to the directory C:\netscape, and then all files from p:\install\instnsc\windows to the windows system directory (its value is automatically inserted into the constant name %SYSTEMROOT%). Option -s means that all subdirectories are copied as well, -V activates the version control for library files.

10.2.2. Modifier

In most cases a Files section will be called without parameters.

There are only some special uses of Files sections where the target of copy actions is set or changed in a certain specified way. We have got the two optional parameters

  • /AllUserProfiles //since 4.12.4.27 [W/L/M]

  • /AllNTUserProfiles (discouraged)

  • /AllNTUserSendTo [W]

Both variants mean:
The called Files section is executed once for each local user. Every copy command in the section is associated with an user specific target directory.

In case other we need to build other user specific path names we can use the automatically set variable %UserProfileDir% or since opsi-script version 4.11.2 %CurrentProfileDir%. With option /AllUserProfiles (resp. /AllNTUserProfiles) the user specific target directory for copy actions is the user profile directory (that is usually denoted by the user name and is by default situated as a subdirectory of the userappdata directory. In case of option /AllNTUserSendTo the target directory is the path of the user specific 'SendTo' folder (for links of the windows explorer context menu).

The exact rule for determining the target path for a copy command has three parts:

  1. If only the source of a copy action is specified the files are copied directly into the user target directory. We have syntax
    copy <source file(s)>
    It be equivalent as
    copy <source file(s)> "%UserProfileDir%"
    or since 4.11.2
    copy <source file(s)> "%CurrentProfileDir%"

  2. If some targetdir is specified and targetdir is a relative path description (starting neither with a drive name nor a backslash) then targetdir is regard as the name of a subdirectory of the user specific directory. I.e.
    copy <source file(s)> <targetdir>
    is interpreted like:
    copy <source file(s)> "%UserProfileDir%\targetdir"
    or since 4.11.2
    copy <source file(s)> "%CurrentProfileDir%\targetdir"

The use of %CurrentProfileDir% has the advantage that you may the same 'Files' section with /AllUserProfiles if it is not running as 'userLoginScript' (in 'Machine' script mode) and without /AllUserProfiles if it is running as 'userLoginScript' (in 'Login' script mode).

  1. If targetdir is an absolute path it is used as the static target path of the copy action.

There are also the Options:

  • /32Bit (Default)

  • /64Bit

  • /SysNative

which manipulate the 'file redirection' on 64 Bit systems. For more details see opsi-script-64bit

10.2.3. Commands

In a Files section the following commands are defined:

  • Copy [W/L/M]

  • Delete / Del [W/L/M]

  • SourcePath

  • CheckTargetPath [W/L/M]

  • chmod [L/M]

  • hardlink [W/L/M]

  • symlink [W/L/M]

  • rename [W/L/M]

  • move [W/L/M]

  • zipfile [W/L/M]

  • unzipfile [W/L/M]

Copy and Delete roughly correspond the the Windows shell commands xcopy resp. del.

SourcePath and CheckTargetPath set origin and destination of the forthcoming copy actions (as if we would open two explorer windows for copy actions between them). If the target path does not exist it will be created.

The syntax definitions are:

  • Copy [-svdunxwnrh] <source(mask)> <target path>

    The source files can be denoted explicitly, using the wild card sign (”* ”) or by a directory name.

    The <target path> is always understood as a directory name. Renaming by copying is not possible. If the target path does not exist it will be created (if needed a hierarchy of directories).

    The optional options of the Copy command mean (the ordering is insignificant):

    • s → We recursive into subdirectories. [W/L/M]

    • e → Empty Subdirectories.
      If there are empty subdirectories in the source path they will be created in the target directory as well.

    • V → Version checking [W]
      A newer version of a windows library file is not overwritten by an older one (according primarily to the internal version counting of the file). If there are any doubts regarding the priority of the files a warning is added to the log file.

    • v → (do not use)
      With Version checking: [W]
      Deprecated: Don’t use it on Systems higher than win2k. Because it checks not only against the target directory but also against %System%. use -V instead.

    • d → With date check: [W]
      A newer .exe file is not overwritten by an older one.

    • u → We are only updating files: [W]
      A file is not copied if there is a newer or equally old file of the same name.

    • x → x-tract (do not use) [W]
      Use the command unzip instead of copy -x.
      If a file is a zip archive it will be unpacked (Xtracted) on copying.
      Caution: Zip archives are not characterized by its name but by an internal definition. E.g. a java jar file is a zip file. If it is unpacked the application call will not work.

    • w → weak [W]
      We respect any write protection of a file such proceeding "weakly" (in opposite to the default behaviour which is to try to use administrator privileges and overwrite a write protected file).

    • n → no over write [W]
      Existing files are not overwritten.

    • c → continue [W]
      If a system file is in use, then it can be overwritten only after a reboot. The opsi-script default behaviour is therefore that a file in use will be marked for overwriting after the next reboot, AND the opsi-script reboot flag is set. Setting the copy option -c turns the automatic reboot off. Instead normal processing continues, the copying will be completed only when a reboot is otherwise triggered.

    • r → read-only Attribute [W]
      If a copied file has a read-only attribute it is set again (in opposite to the default behaviour which is to eliminate read-only attributs).

    • h → follow symlinks [L] //since 4.11.6.14
      At Linux symlinks to files or directories will be resolved before copy. So not the symlink but its target will be copied.

  • Delete [-sfd[n]r[c]] <path>

or

  • Delete [-sfd[n]r[c]] <source(mask)>

    deletes files and directories.

Possible options are (with arbitrary ordering)

  • s → subdirectories
    We recurse into subdirectories. Everything that matches the path name or the source mask is deleted.

    The command
    delete -s c:\opsi
    Do not mean: remove the directory 'c:\opsi' recursive, but it means: delete starting frm 'c:\' all occurences of 'opsi'. This may lead to a complete hard disk scan.
    If you want to delete the directory 'c:\opsi' recursive use the command:
    delete -s c:\opsi\
    by using a trailing backslash you define that 'opsi' is a directory.
    It is safer to use the command del instead.
  • f → force
    forces to delete read only files

  • r → del on reboot [W] since 4.12.4.3 If a file is in use, it can not be deleted at Windows. With the option r in this case the file will be marked for deletion at the next reboot. If this is done then opsi-script default behaviour is also that the opsi-script reboot flag is set. This leads to a reboot after the script is finished. see also option: c

  • c → continue with out reboot [W]+ If a file is in use, it can not be deleted at Windows. With the option r in this case the file will be marked for deletion at the next reboot. If this is done then opsi-script default behaviour is also that the opsi-script reboot flag is set. Setting the copy option -c turns the automatic reboot off. Instead normal processing continues, the deleting will be completed only when a reboot is otherwise triggered. Option c make no sense without r and will be ignored.

  • d [n] → date
    Only files of age n days or older are deleted. n defaults to 1.

    • del [Options] <path[/mask]] //since 4.11.2.1
      Works like delete but on
      del -s -f c:\not-exists
      if c:\not-exists not exists it do not search complete c:\ for not-exits

Example (you may forget the trailing Backslash):
del -sf c:\delete_this_dir

  • SourcePath = < source directory>
    Sets <source directory> as default directory for the following Copy and (!) Delete commands.

  • CheckTargetPath = <target directory>
    Sets <target directory> as default directory for Copy command . If the specified path does not exist it will be created.

  • chmod <mode> <path> //since 4.11.4.1 [L]
    Sets the access rights for <path> to <mode>.
    Since opsi-script 4.12.5, <mode> supports different formats :

    • the numerical (octal) representation (ex: "755") (since 4.11.4.1)

    • the '-rwxrwxrwx' mode format (ex: "-r—​r—​r--", "--wx-w-r-x")

    • the 'ugo=+-rwx' mode format (ex: "ugo=rwx", "ug+r", "go-wx")

Please respect the order of both the 'rwx' (read, write, execute) and the 'ugo' (user, group, others)
Do not forget the '-' in the beginning of the -rwxrwxrwx format

Since opsi-script 4.12.5, there is an optional parameter:

  • /AllSubFiles
    If chmod command is called with this parameter, it expects a Directory <path> and chmod will be applied to all the sub files of the given directory.

Example :

encoding=utf8

[Actions]

DefVar $DirectoryPath$
DefVar $FilePath$

Set $DirectoryPath$ = "/home/opsi/chmod_tests/"
Set $FilePath$ = "/home/opsi/chmod_tests/test1.txt"

if FileExists($FilePath$)
	Files_chmod
else
	LogWarning "File does not exist"
endif

[Files_chmod]
chmod "777" $DirectoryPath$ /AllSubFiles
chmod "-rw-rw-rw-" $FilePath$
chmod "ugo=rx" $FilePath$
chmod "go+w" $FilePath$
chmod "ugo-rw" $FilePath$
  • hardlink <existing file> <new file> // since 4.11.5 [W/L/M]
    A existing <new file> will be over written.
    hardlink works only on filesystems that support hard links like NTFS and standard Linux filesystems.

  • symlink <existing file> <new file> // since 4.11.5 [W/L/M]
    A existing <new file> will be over written.
    At Windows is symlink only available since NT6 and up !

  • rename <old filename> <new filename> // since 4.11.5 [W/L/M]
    move <old filename> <new filename> // since 4.11.5 [W/L/M]
    There is no difference between rename and move, that are just two names for the same function
    A existing <new file> will be over written.
    Since 4.12.4.31 it is also possible to move or rename directories.

    Windows: <new filename> may be located in a differen directory or volume / disk. In the second case (different volume / disk) the file will be copied and than the original file will be deleted.
    If it is not possible to create the target file becaus the file is in use, then it can be overwritten only after a reboot. The opsi-script default behaviour is therefore that a file in use will be marked for overwriting after the next reboot, AND the opsi-script reboot flag is set. Setting the copy option -c turns the automatic reboot off. Instead normal processing continues, the copying will be completed only when a reboot is otherwise triggered.
    Creating Junctions at Windows is not supported right now.

    Linux: <new filename> may be located in a different directory but not in a different filesystem. The Option -c will be ignored at Linux.

    Example:

[Files_link_move]
hardlink "$HomeTestFiles$\files\dummy.txt" "$HomeTestFiles$\files\hardlink.txt"
symlink "$HomeTestFiles$\files\dummy.txt" "$HomeTestFiles$\files\symlink.txt"
rename "$HomeTestFiles$\files\temp\dummy2.txt" "$HomeTestFiles$\files\temp\rename.txt"
move "$HomeTestFiles$\files\temp\dummy2.txt" "$HomeTestFiles$\files\temp\move.txt"

zipfile <source dir> <zip file> // since 4.12.1 [W/L/M]

unzipfile <zip file> <target dir> // since 4.12.1 [W/L/M]

Example:

[Files_zip_unzip]
zipfile "$HomeTestFiles$\" "%opsiTmpDir%\testdir.zip"
zipfile "$HomeTestFiles$\dummy.msi" "%opsiTmpDir%\testfile.zip"
Del -s -f "$HomeTestFiles$\"
checktargetpath = "$HomeTestFiles$\"
unzipfile "%opsiTmpDir%\testdir.zip" "$HomeTestFiles$\"
unzipfile "%opsiTmpDir%\testfile.zip" "$HomeTestFiles$\"

10.3. Patches-Sections [W/L/M]

A Patches section modifies a property file in ini file format. I. e. a file that consists of sections which are a sequence of entries constructed as settings '<variable> = <value>'. where sections are characterized by headings which are bracketed names like '[sectionname]'.

10.3.1. Example

Patches_DUMMY.INI $HomeTestFiles$+"\dummy.ini"

[Patches_dummy.ini]
add [secdummy] dummy1=add1
add [secdummy] dummy2=add2
add [secdummy] dummy3=add3
add [secdummy] dummy4=add4
add [secdummy] dummy5=add5
add [secdummy] dummy6=add6
set [secdummy] dummy2=set1
addnew [secdummy] dummy1=addnew1
change [secdummy] dummy3=change1
del [secdummy] dummy4
Replace dummy6=add6 replace1=replace1

produces the following log:

Execution of Patches_DUMMY.INI
      FILE C:\tmp\testFiles\dummy.ini
      Info: This file does not exist and will be created
  addEntry [secdummy] dummy1=add1
    addSection [secdummy]
      done
      done
  addEntry [secdummy] dummy2=add2
      done
  addEntry [secdummy] dummy3=add3
      done
  addEntry [secdummy] dummy4=add4
      done
  addEntry [secdummy] dummy5=add5
      done
  addEntry [secdummy] dummy6=add6
      done
  setEntry [secdummy] dummy2=set1
    Entry      dummy2=add2
    changed to dummy2=set1
  addNewEntry [secdummy] dummy1=addnew1
    appended entry
  changeEntry [secdummy] dummy3=change1
    entry      dummy3=add3
    changed to dummy3=change1
  delEntry [secdummy] dummy4
    in section secdummy deleted  dummy4=add4
  replaceEntrydummy6=add6 replace1=replace1
    replaced in line 7
  C:\tmp\testFiles\dummy.ini saved back

For more examples, please check the opsi standard product 'opsi-script-test' and in this product the part '$Flag_winst_patches$ = "on"'

10.3.2. Call Parameter

The name of the file to be patched is passed as a parameter.

There are optional modifiers:

  • /AllUserProfiles (old synonym: /AllNTUserProfiles)
    If a patch section is called with this modifier, then all directories under %UserProfileDir% will be patched, which means that this patch is performed for all user profiles.
    When a 'Patches' is called within a [ProfileActions] section, then the modifier /AllUserProfiles is implicit. In logscript mode, %UserProfileDir% will be interpreted as %CurrentProfileDir%.
    (Since Version 4.11.3.2)

  • /encoding <encoding> //since 4.12.4.17 [W/L/M]
    You can add an encoding parameter for the 'Patches' section. This is needed if the file that you want to modify is not in system encoding. Example :

Patches_my_win_ini "C:/my_file.ini" /encoding "utf16le"

For allowed encodings see opsi-script encoding

10.3.3. Commands

For a Patches section, we have commands:

  • add

  • set

  • addnew

  • change

  • del

  • delsec

  • replace

Each command refers to some section of the file which is to be patched. The name of this section is specified in brackets [] (which do here not mean "syntactically optional"!!).

In detail:

  • add [<section name>`]` <variable1> = <value1>
    This command adds an entry of kind <variable1> = <value1> to section <section name> if there is yet no entry for <variable1> in this section. Otherwise nothing is written. If the section does not exist it will be created.

  • set [<section name>`]<variable1> `= <value1>
    If there is no entry for <variable1> in section <section name> the setting <variable1> = <value1> is added. Otherwise, the first entry <variable1> = <valueX> is changed to <variable1> = <value1>.

  • addnew [<section name>`]<variable1> `= <value1>
    No matter if there is an entry for <variable1> in section <section name> the setting <variable1> = <value1> is added.

  • change [<section name>`]<variable1> `= <value1>
    Only if there is any entry for <variable1> in section <section name> it is changed to <variable1> = <value1>.

  • del [<section name>`]` <variable1> = <value1>
    resp.
    del [<section name>`]` <variable1>
    removes all entries <variable1> = <value1> resp. all entries for <variable1> in section <section name>.

  • delsec [<section name>`]`
    removes the section <section name>.

  • replace <variable1>`=<value1> <variable2>=`<value2>
    means that <variable1> = <value1> will be replaced by <variable2> = <value2> in all sections of the ini file. There must be no spaces in the value or around the equal signs.

10.4. PatchHosts Sections [W/L/M]

By virtue of a PatchHosts section we are able to modify a hosts file which is to understand as any file with lines having format
'IPadress hostName aliases # comment'

'Aliases' and 'comment' (and the comment separator #) are optional. A line may also be a comment line starting with # .

The file which is to be modified can be given as parameter of a 'PatchHosts' call. If there is no parameter a file named HOSTS is searched in the directories c:\nfs, c:\windows and %systemroot%\system32\drivers\etc. If no such file is found the 'PatchHosts' call terminates with an error.

In a PatchHosts section there are defined commands:

  • setAddr

  • setName

  • setAlias

  • delAlias

  • delHost

  • setComment

Example:

PatchHosts_add $HomeTestFiles$+"\hosts"

[PatchHosts_add]
setAddr ServerNo1 111.111.111.111
setName 222.222.222.222 ServerNo2
setAlias ServerNo1 myServerNo1
setAlias 222.222.222.222 myServerNo2
setComment myServerNo2 Hallo Welt

produces the following log:

Execution of PatchHosts_add
   FILE C:\tmp\testFiles\hosts
  Set ipAddress 111.111.111.111 Hostname "ServerNo1"
  Set Hostname "ServerNo2" for ipAddress 222.222.222.222
  Alias "myServerNo1" set for entry "ServerNo1"
  Alias "myServerNo2" set for entry "222.222.222.222"
  SetComment of Host "myServerNo2" to "Hallo Welt"
  C:\tmp\testFiles\hosts saved back

For more examples, please check the opsi standard product 'opsi-script-test' and in this product the part '$Flag_winst_patch_hosts$ = "on"'.

In detail:

  • setaddr <hostname> <ipaddresse>
    sets the IP address for host <hostname> to <IPaddress>. If there is no entry for host name as yet it will be created.

  • setname <ipaddresse> <hostname>
    sets the host name for the given IP address. If there is no entry for the IP address as yet it will be created.

  • setalias <hostname> <alias>
    adds an alias for the host named <hostname>.

  • setalias <IPadresse> <alias>
    adds an alias name for the host with IP address <IPadress>.

  • delalias <hostname> <alias>
    removes the alias name <alias> for the host named <hostname> .

  • delalias <IPadresse> <alias>
    removes the alias name <alias> for the host with IP address <IPadress>.

  • delhost <hostname> removes the complete entry for the host with name <hostname>.

  • delhost <IPadresse>
    removes the complete entry for the host with IP address <IPadress>.

  • setComment <ident> <comment>
    writes <comment> after the comment sign for the host with host name, IP address or alias name <ident>.

10.5. IdapiConfig Sections

A IdapiConfig section were designed to write parameters in idapi*.cfg files which are used by the Borland Database Engine.

This section type is not supported any more.

10.6. PatchTextFile Sections [W/L/M]

A PatchTextFile section offers a variety of options to patch arbitrary configuration files which are given as common text files (i.e. they can be treated line by line).

An essential tool for working on text files is the check if a specific line is contained in a given file. For this purpose we have got the Boolean functions Line_ExistsIn and LineBeginning_ExistsIn (cf. Boolean Expressions).

10.6.1. Parameter

The text file which is to be treated is given as parameter.

There are optional modifiers:

  • /AllUserProfiles (old synonym: /AllNTUserProfiles)
    If a 'PatchTextFile' section is called with this modifier and the path of the file to be patched contains the constant %UserProfileDir%, the patch section will be executed for all the profiles.
    For a 'PatchTextFile' section which is called from a [ProfileActions] section in the 'Machine' mode the modifier /AllUserProfiles is implied. In the 'Loginscript' Mode the %UserProfileDir% is interpreted as %CurrentProfileDir%.
    (since version 4.11.3.5)

  • /encoding <encoding> //since 4.12.4.17 [W/L/M]
    You can add an encoding parameter for the PatchTextFile section. This is needed if the file that you want to modify is not in system encoding. Example :

PatchTextFile_my_txt "C:/my_file.text" /encoding "utf16le"

For allowed encodings see opsi-script encoding

10.6.2. Commands

We have got two commands especially for patching Mozilla preferences files plus the two deprecated and more restricted older versions of these commands:

  • Set_Mozilla_Pref ("<preference type>", "<preference key>", "<preference value>")
    sets for <preference type> the value associated with "<preference variable>" to "<preference value>".
    'preference type' takes any value.
    In current Mozilla preference files there are expressions like
    'user_pref("<key>", "<value>")
    pref("<key>", "<value>")
    lock_pref("<key>", "<value>")
    defaultPref("<key>", "<value>")
    lock_pref("<key>", "<value>")
    clearPref("<key>", "<value>")'
    Each of them, in fact, any (javascript) function call of the form
    'functionname (String1, String2)'
    can be patched with this command by setting the appropriate string for <preference type> (that is, resp. for functionname), If an entry starting with "functionname (String1" exists in the treated file, it will be patched (and left at its place). Otherwise a new line will be appended. Unusually in opsi-script, all strings are case sensitive.

  • Set_Netscape_User_Pref ("<preference variable>", "<value>")
    sets the line of the given user preference file for the variable <preference variable> to value <value>. The ASCII ordering of the file will be rebuilt.
    (Deprecated!)

  • AddStringListElement_To_Mozilla_Pref ("<preference type>", "<preference variable>", "<add value>")
    appends an element to a list entry in the given preference file. It is checked if the value that should be added is already contained in the list (then it will not be added).

  • AddStringListElement_To_Netscape_User_Pref ("<preference variable>", "<add values list>")
    (Deprecated!)

The other commands of 'PatchTextFile' sections are not file type specific. All operations are based on the concept that a line pointer exists which can be moved from top of the file i.e. above the top line down to the bottom (line).

There are three search commands:

  • FindLine <search string>
    Finds a line that matches complete (is identic) to <search string>.

  • FindLine_StartingWith <search string>
    Finds a line that starts with <search string>.

  • FindLine_Containing <search string>
    Finds a line that contains <search string>.

Each command starts searching at the current position of the line pointer. If they find a matching line the line pointer is moved to it. Otherwise the line pointer keeps its position.
The search is not case sensitive.

<search string> - as all other String references in the following commands - are String surrounded by single or double citation marks.

  • GoToTop
    move the line pointer to the top line.

(when we count lines it has to be noted that this commands move the line pointer above the top line). We step any - positive or negative - number of lines through the file by

  • AdvanceLine [line count]
    move the line pointer at [line count] lines forward or backward.

  • GoToBottom
    Advancing to the bottom line

By the following command :

  • DeleteTheLine
    we delete the line at which the line pointer is directed if there is such a line (if the line pointer has position top, nothing is deleted)

  • DeleteAllLines_StartingWith <search string>
    deleting all lines which begin with <search string>

  • AddLine <line> or Add_Line <line>
    The line is appended to the file.

  • InsertLine <line> or Insert_Line <line>
    <line> is inserted at the position of the line pointer.

  • AppendLine <line>`or `Append_Line <line>
    <line> is appended after the line at which the pointer is directed.

  • Append_File <file name>
    reads the file and appends its lines to the edited file.

  • Subtract_File <file name>
    removes the beginning lines of the edited file as long as they are identical with the lines of file <file name>.

  • SaveToFile <file name>
    writes the edited lines as a file <file name>.

  • Sorted
    causes that the edited lines are (ASCII) ordered.

  • setKeyValueSeparator <separator char> //since 4.11.4.4
    sets for key/value pairs (command setValueByKey) the separator char (Default is '=')

  • setValueByKey <keystr> <valuestr> //since 4.11.4.4
    looks for a key/value pair with the key <keystr> and set here as value <valuestr>. Is <keystr> not found, the entry will be created at the cursor position.

10.6.3. Examples

For more examples, please check the opsi standard product 'opsi-script-test' and in this product the part '$Flag_winst_patch_text_file$ = "on"'

10.7. LinkFolder Sections [W/L/M]

In a LinkFolder section start menus entries as well as desktop links are managed.

10.7.1. LinkFolder Sections in Windows

E.g. the following section creates a folder named "acrobat“ in the common start menu (shared by all users):

[LinkFolder_Acrobat]
set_basefolder common_programs

set_subfolder "acrobat"
set_link
  name: Acrobat Reader
  target: C:\Programme\adobe\Acrobat\reader\acrord32.exe
  parameters:
  working_dir: C:\Programme\adobe\Acrobat\reader
  icon_file:
  icon_index:
  shortcut:
end_link

In a 'LinkFolder' section first must be defined, in which virtual system folder the subsequent instructions are to operate. This expression defines the base folder:
set_basefolder '<virtual system folder>'

Virtual system folders to be used are:

'desktop, sendto, startmenu, startup, programs, desktopdirectory, common_startmenu, common_programs, common_startup, common_desktopdirectory'

These folders are virtual, for it depends on the operating system (and version), what the resulting physical directory name is.

In the context of standard 'maschine' installations, only the virtual system folders starting with common_ are relevant.

The system folders 'desktop, sendto, startmenu, startup, programs, desktopdirectory' can only be used in the context of a logged on user respectively in a 'userLoginScript' in the context of the opsi extension 'user Profile Management'.

The folders are 'virtual' since the operating system (resp. registry entries) determine the real places of them in the file system. Second, we have to open a subfolder of the selected virtual folder:
set_subfolder <folder path>
The subfolder name is to be interpreted as a path name with the selected virtual system folder as root. If some link shall be directly placed into the system folder we have to write
set_subfolder ""

In the third step, we can start setting links. The command is a multi line expression starting with
set_link
and finished by end_link.

Between these lines the link parameters are defined in the following format:

set_link
name: [link name]
target: <complete program path>
parameters: [command line parameters of the program]
working_dir: [working directory]
icon_file: [icon file path]
icon_index: [position of the icon in the icon file]
shortcut: [keyboard shortcut for calling the target]
end_link

The 'target' name is the only essential entry. The other entries have default values:

  • name defaults to the program name.

  • `parameters`defaults to a empty string.

  • icon_file defaults to the 'target'.

  • icon_index defaults to 0.

  • 'shortcut' defaults to empty. // since 4.11.6.7
    shortcut may be a combination of ['shift','alt','ctrl'] (not case sensitiv) divided by '" "' (Space) , '"-"' (minus char),'"+"' (plus char) and a 'Key' or a 'Virtual Key Code'.
    The 'Key' is a letter ('A' - 'Z') or a numeral ('0' - '9'). All other Keys must be given by there 'Virtual Key Code' identifier. To get these identifier (as well as the allowed combinations) just use the following helper program:
    http://download.uib.de/opsi4.0/helper/showkeys.exe
    Keep in mind that a shortcut refernces the keys and not there contry specific layout. The Key VK_OEM_3 is on an english keyboard the char ';' and on a german the letter 'Ö'.
    Examples for allowed shurtcuts:

    • 'O' (The Key 'O')

    • 'VK_O' (The Key 'O')

    • 'Ctrl-O' (The combination 'Ctrl O')

    • 'Ctrl-Alt-Shift-O' (The combination 'Ctrl Alt Shift O')

    • 'Ctrl+Alt+Shift+O' (The combination 'Ctrl Alt Shift O')

    • 'Ctrl Alt Shift O' (The combination 'Ctrl Alt Shift O')

    • 'Ctrl-Alt-Shift-VK_O' (The combination 'Ctrl Alt Shift O')

    • 'Ctrl-Alt-Shift-VK_F12' (The combination 'Ctrl Alt Shift F12')

If the referenced target does not lie on an mounted share at the moment of link creation windows shortens its name to the 8.3 format.
Workaround:
Create a correct link when the share is connected.
Copy the ready link file to a location which exists at script runtime.
Let this file be the target.
  • delete_element <Linkname>
    remove a link from the open folder.

  • delete_subfolder <Folderpath>
    folder is removed from the base virtual folder

10.7.2. Examples

set $list2$ = createStringList ('common_startmenu', 'common_programs', 'common_startup', 'common_desktopdirectory')
for $var$ in $list2$ do LinkFolder_Dummy

[LinkFolder_Dummy]
set_basefolder $var$
set_subfolder "Dummy"
set_link
	name: Dummy
	target: C:\Programme\PuTTY\putty.exe
	parameters:
	working_dir: C:\Programme\PuTTY
	icon_file:
	icon_index:
end_link

produces the following log:

Set  $list2$ = createStringList ('common_startmenu', 'common_programs', 'common_startup', 'common_desktopdirectory')
    retrieving strings from createStringList [switch to loglevel 7 for debugging]
        (string   0)common_startmenu
        (string   1)common_programs
        (string   2)common_startup
        (string   3)common_desktopdirectory

    retrieving strings from $list2$ [switch to loglevel 7 for debugging]
        (string   0)common_startmenu
        (string   1)common_programs
        (string   2)common_startup
        (string   3)common_desktopdirectory


~~~~~~ Looping through:  'common_startmenu', 'common_programs', 'common_startup', 'common_desktopdirectory'

  Execution of LinkFolder_Dummy
    Base folder is the COMMON STARTMENU folder
    Created "Dummy" in the COMMON STARTMENU folder
      ShellLink "Dummy" created

  Execution of LinkFolder_Dummy
    Base folder is the COMMON PROGRAMS folder
    Created "Dummy" in the COMMON PROGRAMS folder
      ShellLink "Dummy" created

  Execution of LinkFolder_Dummy
    Base folder is the COMMON STARTUP folder
    Created "Dummy" in the COMMON STARTUP folder
      ShellLink "Dummy" created

  Execution of LinkFolder_Dummy
    Base folder is the COMMON DESKTOPDIRECTORY folder
    Created "Dummy" in the COMMON DESKTOPDIRECTORY folder
      ShellLink "Dummy" created

~~~~~~ End Loop

For more examples, please check the opsi standard product 'opsi-script-test' and in this product the part '$Flag_winst_link_folder$ = "on"'.

10.7.3. LinkFolder-Sections in Linux

LinkFolder sections are supported also on Linux since version 4.11.5.2.

Possible bas folders are:
common_programs,common_autostart,desktop, autostart
Subfolder is always "" (empty).

The Link Option icon_index is ignored.
As additional Link Option we have: link_categories.
Here you may use the following values seperated and terminated by a semicolon:
AudioVideo, Audio, Video, Development, Education, Game, Graphics, Network, Office, Settings, System, Utility
The LinkFolder Sektion will work at Linux with different Desktop systems

10.8. XML2 Section [W/L/M]

A popular way to keep configuration data or data at all is a file in XML document format. Its syntax follows the conventions as defined in the XML (or "Extended Markup Language") specification (http://www.w3.org/TR/xml/).

opsi-script offers two different ways to handle XML files:

  • The xml2 sections that are described in this chapter
    Since opsi-script version 4.12.1

  • The deprecated, still working (but only at windows) XMLPatch sections (XMLPatch Sections) and functions which are more powerful but also more complicated than the newer xml2 methods. So we recommend to use the xml2 sections and functions.

The xml2 implementation is divided in

  • the xml2 section as described over here, with the goal to make it easy to manipulate xml data

  • the xml2 functions with the target to analyze given xml data
    see also : XML related functions (XML2)
    see also : XML2 Functions

10.8.1. XML structure and wording

Let’s have a look at a simple xml file:

<?xml version="1.0" encoding="UTF-8"?>
<rootnode>
    <node_level-1_number-1>
        <node_level-2_A color="blue">Hello World</node_level-2_A>
        <node_level-2_B color="green" count="65">
        </node_level-2_B>
        <node_level-2_C>
        </node_level-2_C>
    </node_level-1_number-1>
    <node_level-1_number-2>
    </node_level-1_number-2>
</rootnode>

To describe the structure in this xml file we use the following wording:

  • xml file
    A file that contains xml data.

  • xml header
    XML meta data at the beginning of an xml file, in our example:
    <?xml version="1.0" encoding="UTF-8"?>

  • node
    The xml node starts with an open element < followed by an identifier and > and ends with the close element <\ followed by the same identifier and >. Example:
    <mynode><\mynode>
    If (like in the example above) there is no additional information, this node can also be written as:
    <mynode\>
    In the open element the identifier may be followed by one or more attributes.
    Between the open and the close element you may find the nodetext.

  • root node
    The base node of the xml tree. In our example:
    <rootnode>

  • attribute is a key/value pair that is part of the open element and comes after the node identifier, like:
    color="blue" in <node_level-2_A color="blue">

  • nodetext
    is text that may come between the open and the close element, like :
    Hello World in <node_level-2_A color="blue">Hello World</node_level-2_A>

  • xml2path
    is an opsi xml2 specific notation to give a path through the xml tree.
    Example: <node_level-1_number-1> // </node_level-2_B>
    It is the sequence of nodes below the root node.

  • xml2stringlist
    The opsi-script xml2 functions do not work directly on an xml file, but on a stringlist representation of this file or parts of it (a node).
    So with the function getXml2DocumentFromFile(<path to xml file>`)` you get a stringlist that contains the representation of the content of this file in an xml2stringlist. This variable may be used to analyze the xml2stringlist by other xml2 functions.
    The result of those functions may be also a stringlist from type xml2stringlist.
    In fact the xml2stringlist is a stringlist that contains the content of the xml file in a special format and without the header. But do not try to construct it without using getXml2DocumentFromFile or getXml2Document.
    see : XML2 Functions

10.8.2. CallParameter

The name of the file to be patched is passed as a parameter.

Example:
xml2_test "%scriptpath%\dummy.xml"

If the given file does not exist, it will be created. While creating the file as name of the root node, we use the value of the command rootNodeOnCreate = <node name>. If this command is missing in the section, the fall back is the root node name: 'rootnode'. (since 4.12.4.27)

There are optional modifiers:

  • /AllUserProfiles // since 4.12.4.27
    If an XML2 section is called with this modifier, then all directories under %UserProfileDir% will be patched, which means that this patch is performed for all user profiles.
    When an XML2 section is called within a [ProfileActions] section, then the modifier /AllUserProfiles is implicit. In logscript mode, %UserProfileDir% will be interpreted as %CurrentProfileDir%.

  • /encoding <encoding> //since 4.12.4.27 [W/L/M]
    By default the given XML file is expected in the encoding "UTF-8".
    You can add an encoding parameter for the 'XML2' section. This is needed if the file that you want to modify is not in "UTF-8" encoding. Example :

XML2_my_xml "C:/my_file.xml" /encoding "utf16le"</