Definition and Use of Variables and Constants in a opsi-script Script

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:

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.

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).

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:

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%'

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

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.

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.

String (or Text) Variables [W/L/M]

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.

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"

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.

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).

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).