Integrating custom Software

The installation of software using opsi is managed either by the Client Agent or the setup program opsi-script. When packaging your own software for deployment through opsi, it’s necessary to create an opsi-script script for each product. This script, along with the installation files and metadata, should be packed. As a result, you’ll get an opsi product which is then installed on the opsi server (see the chapter Adding Products (opsi Server)).

Tutorial: Creating an opsi-script Script

This tutorial serves as an introductory guide and should not be considered a complete substitute for formal training or a thorough study of the manuals. For more in-depth learning and resources, we recommend the following:

Non-interactive software installation (Windows)

Basically, there are three different ways to integrate a software package into the automatic software distribution for Windows operating systems. Additionally, there’s a variant that uses the Windows Installer service:

  • Unattended/Silent Setup:
    This approach involves using the original setup program and configuring it for non-interactive mode via command line parameters. A notable example is the silent installation of an MSI package using the /quiet option of the msiexec tool.

  • Interactive Setup with recorded Answers:
    Begin by running the original setup program once to observe the window titles and the sequence of questions and responses during the setup. Record these details in a script. During software distribution, an automation tool such as AutoIt or AutoHotkey interacts with the setup program as dictated by the script.

  • Recreate Setup Routine with opsi-script:
    While the original setup program is active, use a tool like Process Monitor/Procmon to log all system changes. You then craft the opsi-script script based on the logged data and the changes you’ve recorded.

opsi supports all three variants. In practice, a combination of several methods is often used.

Structure of an opsi-script Script

The following sections will detail the key components of an opsi-script script tailored for Windows computers. As an illustration, here is an example of a basic opsi-script script:

[Actions]
WinBatch_tightvnc_silent_install

[WinBatch_tightvnc_silent_install]
"%ScriptPath%\tightvnc-1.3.9-setup.exe" /silent

An opsi-script script is structured into two main types of sections: primary and secondary sections. Similar to INI files, each section is introduced by its name enclosed in square brackets.

The core activities of software installation are carried out in the secondary sections, which are invoked by the primary sections. Each secondary section is designated for specific topics and follows a unique syntax: the section name starts with the type, followed by a user-defined name.

In the provided example, the primary section [Actions] triggers the secondary section [WinBatch_tightvnc_silent_install]; this section belongs to the WinBatch type. The contents of a WinBatch section are executed using the Windows API. Here, the msiexec tool is employed to install (/i) the 64 bit version of TightVNC silently (using the /quiet option). The /norestart option is included to prevent the computer from rebooting after the installation, which is a specific requirement for TightVNC.

Primary Sections

  • Actions: The [Actions] section is essentially the main program, marking the commencement of script processing.

  • Sub-Sections: Sections of the program required to be executed multiple times can be organized into sub-sections. These sub-sections can also be externalized into separate files for ease of use and reference.

Avoide duplicate Code via distributed Sub-sections.
Figure 1. Avoide duplicate Code via distributed Sub-sections.

The primary sections, which function as the main programs, dictate the script’s flow. In these sections, you can use variables, conditional statements, functions, and other programming constructs. For more detailed information on these elements, please refer to the section Important Commands for Primary Sections.

Secondary Sections

  • Files: For file operations, such as

    • Copying (with version control, recursive, etc.)

    • Deleting

    • Creating directories

    • etc.

  • WinBatch: For executing through the Windows API. Typically, setup programs are run in a non-interactive mode within these sections.

  • ShellScript: This section’s content is executed by the operating system’s standard shell. For Windows, this shell is cmd.exe, whereas for Linux and macOS, it’s typically bash. So, this is the place to put regular batch scripts.

  • ExecWith: The content of this section is passed on to an external program (like an interpreter) for execution. For instance, ExecWith is used to integrate AutoIt scripts into the opsi-script script.

  • Registry: These sections contain specific instructions for modifying the Windows registry.

  • LinkFolder: These sections are used to create or delete shortcuts, such as those on the desktop or in the start menu.

Global constants

opsi-script also supports the use of global constants. These constants act as placeholders and you can use them in primary and secondary sections. By employing global constants, you can ensure that paths are correctly set across various environments, such as systems with different languages or operating system versions.

Below are some examples of global constants:

  • %ProgramFiles64Dir%: c:\program files at 64 Bit

  • %ProgramFiles32Dir%: c:\program files (x86) at 64 Bit

  • %SystemRoot%: c:\windows

  • %System%: c:\windows\system32

  • %opsiTmpDir%: c:\opsi.org\tmp

  • %ScriptPath%: <path to running script>

Example: installing TightVNC

In order to illustrate this concept, let’s consider another example script. For installing the program, a silent execution of setup.exe in the secondary section WinBatch_tightvnc_silent_install would typically suffice. However, if the installation is repeated, an interactive dialog will appear (because of a running service). In such cases, AutoIt can be used to automatically close the dialog box:

[Actions]
Message "Installing tightvnc 1.3.9 ..."
ExecWith_autoit_confirm "%ScriptPath%\autoit3.exe" WINST /letThemGo
WinBatch_tightvnc_silent_install
KillTask "autoit3.exe"

[WinBatch_tightvnc_silent_install]
"%ScriptPath%\tightvnc-1.3.9-setup.exe" /silent

[ExecWith_autoit_confirm]
; Wait for the confirm dialog which only appears if tightvnc was installed before as service
; Waiting for the window to appear
WinWait("Confirm")
; Activate (move focus to) window
WinActivate("Confirm")
; Choose answer no
Send("N")

More details on using AutoIt with opsi you will find here:
Automated Answers for the setup program.

Important Commands for Primary Sections

The next sections provide a concise overview of the fundamental commands used in primary sections of opsi-script scripts. This includes the use of variables, statements, conditional statements, functions, and more. For a comprehensive reference and detailed explanations, please refer to the opsi-script chapter.

String Variables
Variable Declaration

DefVar <variable name> [= <initial value>]

Variable Assignment

Set <variable name> = <value>

In the following example, a variable $ProductId$ is declared and assigned the value "firefox":

DefVar $ProductId$
Set $ProductId$ = "firefox"

Alternatively, it’s shorter to write:

DefVar $ProductId$ = "firefox"
The handling of string variables differs between primary and secondary sections. In primary sections, string variables are treated as independent objects. However, in secondary sections, they are replaced by the content of the variable before the section is executed. This distinction is crucial, especially when copying and pasting string expressions within the script.

Consequently, string variables can only be declared and assigned values in primary sections. When combining variables and strings into a string expression, the operator "+" is required:

"Installing "+ $ProductId$ +" ..."

In secondary sections, string variables are replaced by the content of the variable before the section is executed:

"Installing $ProductId$ ..."

This has the advantage that you can easily work with opsi-script variables in sections that are executed outside the script (ExecWith, ShellScript).

Statements: Message and ShowBitmap

To display text during installation, use the command Message <string>. Here, substitute <string> with the specific text message you wish to show:

Message "Installing "+ $ProductId$ +" ..."

Instead of text messages, you can also display graphics using the ShowBitmap statement. The images should be in BMP, JPG, or PNG formats, ideally sized at 160 x 160 pixels. Additionally, you can include a caption with the subtitle parameter:

ShowBitmap "%ScriptPath%\python.png" "Python"
Conditional Statements: if, elseif/else, and endif

You can conditionally execute code based on specific criteria:

  • if: This initiates the conditional statement. If the specified condition is true, the script executes the instructions within the subsequent block. If the condition is false, the block is bypassed.

  • ;statement(s): These are the instructions executed when the condition in the if statement is true. This block can contain one or multiple statements that run only if the specified condition is met.

  • elseif <condition>: This is an optional part. If the condition in the if statement isn’t met, this condition is then evaluated. If it’s true, the script executes the instructions in the subsequent block. It allows for additional, sequential conditions to be checked if earlier conditions aren’t fulfilled.

  • else: This optional section executes if all the preceding conditions are false. It acts as a fallback, containing instructions that run when none of the previous conditions are met.

  • endif: This marks the end of the conditional structure, indicating the conclusion of the conditional checks.

if <condition>
	;statement(s)
[elseif <condition>
;statement(s)]
[
else
	;statement(s)
]
endif
Functions
  • HasMinimumSpace: Checks for free space on the hard disk.

  • FileExists: Checks if a file or directory exists.

Comments, Errors and Logging
  • Comment Marker: Lines starting with a semicolon (;) are not interpreted.

  • Comment: Writes a comment to the logfile.

  • LogError: Writes an error message to the logfile.

  • IsFatalError: Cancels the execution of the running script and reports the installation as failed.

Condition for Execution
  • requiredOpsiscriptVersion: This specifies the minimum version of opsi-script that is required for the script to function properly:

requiredOpsiscriptVersion >= "4.12.3.6"
Other important opsi-script Functions
  • String Lists: String lists are quite powerful and particularly useful for processing output from external programs (refer to the section Processing String Lists for more details).

  • Function ExitWindows: This function is used to restart or shut down the system and exit opsi-script.

    • ExitWindows /Reboot: Triggers a system reboot upon completion of the script.

    • ExitWindows /ImmediateReboot: Executes an immediate system reboot.

    • ExitWindows /ImmediateLogout: Immediately terminates script processing and exits opsi-script.

  • Product Properties: Certain products may require the configuration of options, which are evaluated on a client-specific basis at runtime (see section Creating opsi Products for more information).

Access to the property values is provided through the GetProductProperty function:

if GetProductProperty("example-property", "no") = "yes"
    Files_copy_extra_files
endif
  • Encoding: Use UTF-8 encoding in your scripts and place the instruction at the beginning of the file:

encoding=utf8
Special Commands for Windows
  • GetOS: This function retrieves the operating system type. It returns values such as Linux, Windows_NT (covering Windows NT through Windows 11), or macOS.

  • GetMsVersionInfo: This function provides detailed information about the internal Windows version. For instance, Windows 7 is identified as "6.1", while Windows 11 is recognized as "10.0", etc.

  • GetMsVersionName: This function returns the commercial version name of a Windows system. For example, Windows 7 returns "7.0", and Windows 11 returns "11.0", and so on.

  • getMSVersionMap: This function locally queries the operating system information and records it into a string list.

For more comprehensive details about these string functions, refer to the section String Functions which return the OS Type.

Example: Windows Template opsi-template

You can create this template with the opsi-setup-detector tool (see the section opsi-setup-detector: Creating a Script).

Scripts created by opsi-setup-detector using the template channel: 'training'

setup.opsiscript: Installations-Skript/Script for Installation
; ----------------------------------------------------------------
; This is an opsi-script file.
; See https://opsi.org    https://uib.de
; This code was originally created by opsi-setup-detector 4.3.1.2
; ----------------------------------------------------------------
encoding=utf8

;here we start
[Actions]

;check if the running opsiscript version is not too old
requiredOpsiscriptVersion >= "4.12.5.0"

;fetch helper libraries
importlib "uib_exitcode.opsiscript"
importlib "osd-lib.opsiscript"

; ----------------------------------------------------------------
comment "retrieve infos from script environment"
; ----------------------------------------------------------------
; the values are found automatically when the script is running
;
DefStringList $productInfos$ = getProductMap
DefVar $ProductId$ = getValue("id", $productInfos$)
DefVar $ProductName$ = getValue("name", $productInfos$)

DefVar $OS$ = GetOS
; the operating system, in which the interpreter is running
; supported values are  "Windows_NT", "Linux", "MacOS"

; ----------------------------------------------------------------
comment "put fixed infos into the script (maybe produced by the setup detector maybe manually)"
; ----------------------------------------------------------------
; the values can be manually edited or automatically suggested by the opsi setup detector
;
DefVar $InstallDir$ = "%ProgramFiles32Dir%\<path to the product files>"
; dependent on the installes software it could be
; "%ProgramFiles64Dir% [,,,]
; "%ProgramFilesSysNatives% [,,,]
DefVar $MinimumSpace$ = "5 MB"
DefVar $MsiId$ = "00000"
DefVar $UninstallProgram$ = "uninstall.exe"
DefVar $ExitCode$
DefVar $ErrorString$
DefVar $targetprogram$


set $targetprogram$ = ""
; ---------------------------------------------------------------
comment "inform the user at the PC about product installation"
; ----------------------------------------------------------------
; for a better visual appearance, show some graphic (at most of size 160x160 [px] )
; we set a image path which could be as follows
DefVar $ImagePath$ = "%ScriptPath%\" + $ProductId$ + ".png"
ShowBitmap $ImagePath$ $ProductName$

Message "Installing " + $ProductId$ + " ..."

; ----------------------------------------------------------------
comment  "check if the script is adequate to the environment"
; ----------------------------------------------------------------
if not ($OS$ = "Windows_NT")
	logError "Installation aborted: wrong OS version: only Windows"
	isFatalError "wrong OS"
	; Stop process and set installation status to failed
endif

if not(HasMinimumSpace ("%SystemDrive%", $MinimumSpace$))
	LogError "Not enough space on %SystemDrive%, " + $MinimumSpace$ + " on drive %SystemDrive% needed for " + $ProductId$
	isFatalError "No Space"
	; Stop process and set installation status to failed
endif



; ---------------------------------------------------------------
comment "uninstall an existing installation if possible"
; ---------------------------------------------------------------

if FileExists("%ScriptPath%\delinc.opsiinc")
	comment "Start uninstall part"
	include_insert "%ScriptPath%\delinc.opsiinc"
endif

; show  a title for the installation
Message "Installing " + $ProductId$ + " .."

DefVar $installerSourceDir$ = "%SCRIPTPATH%"



; ---------------------------------------------------------------
comment "run  the setup program"
; ----------------------------------------------------------------

; the call to the installer is more stable if we set the path
ChangeDirectory $installerSourceDir$

; call the setup program
Winbatch_install

; ---------------------------------------------------------------
comment "check the result"
; ----------------------------------------------------------------
; check the outcome of the call, produce either a "failed" state of the script or log the result
set $ExitCode$ = getlastexitcode
if "true" = isGenericExitcodeFatal($exitcode$, "true", $ErrorString$ )
	LogError $ErrorString$
	isfatalerror $ErrorString$
else
	Comment $ErrorString$
endif


; ---------------------------------------------------------------
comment "do tasks  which supplement the installation"
; ----------------------------------------------------------------

;e.g. copy some files
Files_install /sysnative

;e.g. configure some registry entries
Registry_install /sysnative

;e.g.. supplement or remove start menu or desktop links
LinkFolder_install


; ---------------------------------------------------------------
; end of  actions section
; ---------------------------------------------------------------
; ---------------------------------------------------------------
; ---------------------------------------------------------------



[Winbatch_install]
; Choose one of the following examples as basis for your installation
; You can use $LicenseKey$ var to pass a license key to the installer
;
; === Nullsoft Scriptable Install System ================================================================
; "%ScriptPath%\Setup.exe" /S
;
; === MSI package =======================================================================================
; You may use the parameter PIDKEY=$Licensekey$
; msiexec /i "%ScriptPath%\some.msi" /l* "%opsiLogDir%\$ProductId$.install_log.txt" /qb-! ALLUSERS=1 REBOOT=ReallySuppress
;
; === InstallShield + MSI=====================================================================================
; Attention: The path to the logfile should not contain any whitespaces
; "%ScriptPath%\setup.exe" /s /v" /l* %opsiLogDir%\$ProductId$.install_log.txt /qb-! ALLUSERS=1 REBOOT=ReallySuppress"
; "%ScriptPath%\setup.exe" /s /v" /qb-! ALLUSERS=1 REBOOT=ReallySuppress"
;
; === InstallShield =====================================================================================
; Create setup.iss answer file by running: setup.exe /r /f1"c:\setup.iss"
; You may use an answer file by the parameter /f1"c:\setup.iss"
; "%ScriptPath%\setup.exe" /s /sms /f2"%opsiLogDir%\$ProductId$.install_log.txt"
;
; === Inno Setup ========================================================================================
; http://unattended.sourceforge.net/InnoSetup_Switches_ExitCodes.html
; You may create setup answer file by: setup.exe /SAVEINF="filename"
; You may use an answer file by the parameter /LOADINF="filename"
; "%ScriptPath%\setup.exe" /sp- /silent /norestart /nocancel /SUPPRESSMSGBOXES

[Files_install]
; Example of recursively copying some files into the installation directory:
;
; copy -s "%ScriptPath%\files\*.*" "$InstallDir$"

[Registry_install]
; Example of setting some values of an registry key:
;
; openkey [HKEY_LOCAL_MACHINE\Software\$ProductId$]
; set "name1" = "some string value"
; set "name2" = REG_DWORD:0001
; set "name3" = REG_BINARY:00 af 99 cd

[LinkFolder_install]
; Example of deleting a folder from AllUsers startmenu:
;
; set_basefolder common_programs
; delete_subfolder $ProductId$
;
; Example of creating a shortcut to the installed exe in AllUsers startmenu:
;
; set_basefolder common_programs
; set_subfolder $ProductId$
;
; set_link
	; 	name: $ProductId$
	; 	target: <path to the program>
	; 	parameters:
	; 	working_dir: $InstallDir$
	; 	icon_file:
	; 	icon_index:
; end_link
;
; Example of creating a shortcut to the installed exe on AllUsers desktop:
;
; set_basefolder common_desktopdirectory
; set_subfolder ""
;
; set_link
	; 	name: $ProductId$
	; 	target: <path to the program>
	; 	parameters: <some_param>
	; 	working_dir: $InstallDir$
	; 	icon_file: <path to icon file>
	; 	icon_index: 2
; end_link


[Winbatch_uninstall]

; Choose one of the following examples as basis for program uninstall
;
; === Nullsoft Scriptable Install System ================================================================
; maybe better called as
; Winbatch_uninstall /WaitforProcessending "Au_.exe" /Timeoutseconds 10
; "$UninstallProgram$" /S
;
; === Inno Setup ========================================================================================
; "$UninstallProgram$" /silent /norestart /SUPPRESSMSGBOXES /nocancel


[Files_uninstall]
del -sf "$InstallDir$\"

[Sub_check_exitcode_generic]
set $ExitCode$ = getlastexitcode
if "true" = isGenericExitcodeFatal($exitcode$, "true", $ErrorString$ )
	LogError $ErrorString$
	isfatalerror $ErrorString$
else
	Comment $ErrorString$
endif
delinc.opsiinc: Deinstallations-Skript (Include)/Script for Deinstallation (Include)
; ----------------------------------------------------------------
; This is a opsi-script file.
; See https://opsi.org    https://uib.de
; This code was originally created by opsi-setup-detector 4.3.1.2
; ----------------------------------------------------------------
encoding=utf8

Message "Check for existing installation of " + $ProductId$ + " ..."

DefVar $MsiId$ = '{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'
DefVar $UninstallProgram$ = $InstallDir$ + "\uninstall.exe"

; ---------------------------------------------------------------
comment "run the uninstall program"
; ----------------------------------------------------------------

if FileExists($UninstallProgram$)

	comment "Uninstall program found, starting uninstall"
	Winbatch_uninstall
	set $ExitCode$ = getlastexitcode
	if "true" = isGenericExitcodeFatal($exitcode$, "true", $ErrorString$ )
		LogError $ErrorString$
		isfatalerror $ErrorString$
	else
		Comment $ErrorString$
	endif


endif
if not (getRegistryValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + $MsiId$ , "DisplayName","32bit") = "")

	comment "MSI id " + $MsiId$ + " found in registry, starting msiexec to uninstall"
	Winbatch_uninstall_msi
	set $ExitCode$ = getlastexitcode
	if "true" = isMsiExitcodeFatal($exitcode$, "true", $ErrorString$ )
		LogError $ErrorString$
		isfatalerror $ErrorString$
	else
		Comment $ErrorString$
	endif

endif


comment "Delete files"
if not(($InstallDir$ = '') or ($InstallDir$ = 'unknown'))
	Files_uninstall
endif

comment "Cleanup registry"
Registry_uninstall

comment "Delete program shortcuts"
LinkFolder_uninstall

;-----------------------------------------------------
uninstall.opsiscript: Deinstallations-Skript/Script for Deinstallation
; ----------------------------------------------------------------
; This is a opsi-script file.
; See https://opsi.org    https://uib.de
; This code was originally created by opsi-setup-detector 4.3.1.2
; ----------------------------------------------------------------
encoding=utf8

;here we start
[Actions]

;check if the running opsiscript version is not too old
requiredOpsiscriptVersion >= "4.12.5.0"

;fetch helper libraries
importlib "uib_exitcode.opsiscript"
importlib "osd-lib.opsiscript"


; ----------------------------------------------------------------
comment "retrieve infos from script environment"
; ----------------------------------------------------------------
; the values are found automatically when the script is running
;
DefStringList $productInfos$ = getProductMap
DefVar $ProductId$ = getValue("id", $productInfos$)
DefVar $ProductName$ = getValue("name", $productInfos$)

DefVar $OS$ = GetOS
; the operating system, in which the interpreter is running
; supported values are  "Windows_NT", "Linux", "MacOS"

; ----------------------------------------------------------------
comment "put fixed infos into the script (maybe produced by the setup detector maybe manually)"
; ----------------------------------------------------------------
; the values can be manually edited or automatically suggested by the opsi setup detector
;
DefVar $InstallDir$ = "unknown"
; dependent on the installes software it could be
; "%ProgramFiles64Dir% [,,,]
; "%ProgramFilesSysNatives% [,,,]
DefVar $MinimumSpace$ = "0 MB"
DefVar $MsiId$ = "00000"
DefVar $UninstallProgram$ = "uninstall.exe"

DefVar $targetprogram$


; ---------------------------------------------------------------
comment "inform the user at the PC about product installation"
; ----------------------------------------------------------------
; for a better visual appearance, show some graphic (at most of size 160x160 [px] )
; we set a image path which could be as follows
DefVar $ImagePath$ = "%ScriptPath%\" + $ProductId$ + ".png"
ShowBitmap $ImagePath$ $ProductName$

Message "Uninstalling " + $ProductId$ + " ..."

; ----------------------------------------------------------------
comment  "check if the script is adequate to the environment"
; ----------------------------------------------------------------
if not ($OS$ = "Windows_NT")
	logError "Installation aborted: wrong OS version: only Windows"
	isFatalError "wrong OS"
	; Stop process and set installation status to failed
endif



; ---------------------------------------------------------------
comment "uninstall an existing installation if possible"
; ---------------------------------------------------------------

if FileExists("%ScriptPath%\delinc.opsiinc")
	comment "Start uninstall part"
	include_insert "%ScriptPath%\delinc.opsiinc"
endif



[Winbatch_uninstall]

; Choose one of the following examples as basis for program uninstall
;
; === Nullsoft Scriptable Install System ================================================================
; maybe better called as
; Winbatch_uninstall /WaitforProcessending "Au_.exe" /Timeoutseconds 10
; "$UninstallProgram$" /S
;
; === Inno Setup ========================================================================================
; "$UninstallProgram$" /silent /norestart /SUPPRESSMSGBOXES /nocancel

[Winbatch_uninstall_msi]
msiexec /x $MsiId$ /qb-! REBOOT=ReallySuppress

[Files_uninstall]
; Example for recursively deleting the installation directory:
;
; del -sf "$InstallDir$\"

[Registry_uninstall]
; Example of deleting a registry key:
;
; deletekey [HKEY_LOCAL_MACHINE\Software\$ProductId$]

[LinkFolder_uninstall]
; Example of deleting a folder from AllUsers startmenu:
;
; set_basefolder common_programs
; delete_subfolder $ProductId$
;
; Example of deleting a shortcut from AllUsers desktop:
;
; set_basefolder common_desktopdirectory
; set_subfolder ""
; delete_element $ProductId$


; ----------------------------------------------------------------
; ----------------------------------------------------------------

Creating opsi Products

The following sections outline the steps for packaging software, specifically for creating opsi products. The fundamental process involves:

  1. Creating the basic framework of a package using the opsi-setup-detector (refer to section opsi-setup-detector: Creating a Script).

  2. Testing the opsi-script script (see section Testing and improving a Script).

  3. Using the opsi PackageBuilder (oPB) to transform the initial form into a complete opsi package, which is then stored on the opsi server.

Preparation

To create opsi packages, you will require the following tools:

Installing opsi-setup-detector

The opsi-setup-detector is currently available for Windows, Linux, and macOS. You can install this program directly through opsi. It’s one of the standard localboot products and is typically available on the opsi server. If it’s not already installed, you can deploy the product using the following command:

opsi-package-updater install opsi-setup-detector
The localboot product opsi-setup-detector also requires the installation of the product opsipackagebuilder_wlm, because the setup detector uses the PackageBuilder (if available).

You should therefore also install the product opsipackagebuilder_wlm:

opsi-package-updater install opsipackagebuilder_wlm

You can then deploy the two products to the desired clients, for example, using the opsi-configed management interface.

For Windows computers, we provide the setup detector as a stand-alone package, which can be installed independently of opsi: https://tools.43.opsi.org/stable/
Differences Across Windows, Linux, and macOS

While the opsi-setup-detector generally operates similarly across Windows, Linux, and macOS, there are distinct differences in how it analyzes installation files, using various auxiliary programs specific to each operating system:

  • On Windows, detailed analyses of Inno Setups are conducted using the integrated tool innounpack.exe. Such in-depth analysis of Inno Setups is thus exclusive to the Windows environment.

  • For working with the Windows Installer XML (commonly known as the WiX Toolset), the integrated tool Dark.exe is employed under Windows. Therefore, this level of detailed analysis is also specific to Windows.

  • On Linux systems, .deb or .rpm packages are analyzed using the standard package management tools on Linux. Consequently, this type of detailed analysis is possible only on Linux systems.

Installing opsi PackageBuilder

The opsi PackageBuilder (oPB) is available for Windows, Linux, and macOS.

The product opsipackagebuilder_wlm is one of the opsi standard products. If it is not yet installed on your server, use this command to install it:

opsi-package-updater install opsipackagebuilder_wlm

You can proceed to deploy the localboot product to the clients, for instance, using the opsi-configed management interface.

The opsi PackageBuilder (oPB) is a Localboot Product which you can deploy on the Clients..
Figure 2. The opsi PackageBuilder (oPB) is a Localboot Product which you can deploy on the Clients.

Alternative approach to using the product:

You can install the opsi PackageBuilder (oPB) either as an opsi product on the opsi server and then deploy it to clients via opsi-configed. Alternatively, you can use one of the installation packages available at forum.opsi.org - opsi PackageBuilder.

The opsi PackageBuilder (oPB) is a community-driven product, developed by Holger Pandel. Many thanks!

You can find the source code and license details at GitHub: opsi PackageBuilder (oPB).

Installing opsi-logviewer

The opsi-logviewer is compatible with Windows, Linux, and macOS and is a component of the opsi-configed management interface.

The opsi-configed package is one of the standard opsi products and is typically pre-installed on your opsi server. If it’s not already installed, you can do so with this command:

opsi-package-updater install opsi-configed
You can find an executable version of the management interface opsi-configed for Windows, Linux, and macOS on our website at opsi Tools.

opsi-setup-detector: Creating a Script

The following sections explain in detail how to use the opsi-setup-detector to analyze a setup file and create an opsi product.

Start and Condfigurartion

On Windows, you can launch the opsi-setup-detector from the Start menu, where it is located at opsi.org / opsi-setup-detector. For macOS users, the opsi-setup-detector can be accessed via Programs, while on Linux, it is typically found in the start menus at System Tools. Additionally, on most Linux desktop environments, you have the option to directly enter the full path to the executable file (/opt/opsi-setup-detector/opsisetupdetector) in a quick launcher ([Alt]+[F2]) or terminal window.

In Windows, the opsi-setup-detector can be conveniently started directly from the Explorer. By right-clicking on an installation file for an application, you will find an option in the context menu that allows you to initiate the tool for analysis.
You can start the *opsi-setup-detector* via the Explorer’s Context Menu.
Figure 3. You can start the opsi-setup-detector via the Explorer’s Context Menu.

Upon the initial launch of the program, a configuration dialog will appear. It’s essential to provide information for the following three entries:

  • fullName: Enter your full name as you wish it to appear in the changelog.txt file.

  • email_address: Provide your email address, which will also be included in the changelog.txt file.

  • workbench_Path: Specify the path to the directory where you will create the opsi packages.
    Ideally, this should be the path to the share where your opsi server’s workbench is mounted (see the chapter Samba).

After the first start, configure the *opsi-setup-detector*.
Figure 4. After the first start, configure the opsi-setup-detector.

Additionally, you can configure further (optional) settings. For the opsi web service opsiconfd (https://<opsi-server>:4447, see the chapter The opsiconfd Service), you should complete the following fields:

  • Service_URL: Enter the URL of the opsi web service, formatted as https://<opsi-server>:4447.

  • Service_user: Specify the username required for connecting to the opsi web service.

  • Service_pass: Input the password associated with the Service_user for the web service connection. Skip this, and the the opsi-setup-detector will prompt for it when necessary.

Possible security risk: Even if the password is stored in encrypted form, it can still be decrypted after analyzing the (open) source code.

Other optional settings include:

  • control_in_toml_format: Check this box if you want to create a control file in TOML format (refer to the section Example: control File for more details).
    Attention: This option requires at least opsi 4.3!

  • dependencies_for_all_actionrequests: This setting determines whether dependencies should be allowed for action requests other than setup.
    Attention: This feature requires at least opsi 4.3 and should be used with extreme caution!

  • preferMsiUninstall: If the analyzed file is an wrapper around a MSI file: Should we use the uninstall code for the msi or the uninstall program from the installer ?

For a comprehensive explanation of all the available settings, refer to the chapter [opsi-setup-detector configuration.

Once the configuration is saved, you will see the start page.

Online Help

Click on the question mark to display the online help.

Click this Icon to access the Manual.
Figure 5. Click this Icon to access the Manual.

A click to this question mark icon will open the general or context sensitive online help pages.

*opsi-setup-detector* Start Page
Figure 6. opsi-setup-detector Start Page

Select the task that fits your needs. The dialog offers tasks for Windows, Linux, and macOS, as well as options that are operating system-independent. There is also a dedicated section for packages designed for multi-platform compatibility.

The following tasks are available for Windows:

  • Analyze File and create opsi Package: Starting from a setup file, the entire process is executed until an opsi package is created (see the section Analyze File and Create a Package).

  • Analyze 2 Files (32 / 64 bit) and create O. Package: The procedure is similar, but here two setup programs for the two architectures (32 bit and 64 bit) are queried and analyzed. The product receives an additional property: install_architecture (possible values: 32bitonly, 64bitonly, both, and systemspecific).

  • Create an opsi Package Template: Doesn’t ask for a setup file, but creates an opsi template product for Windows and takes the information from the product configuration.

  • Analyze File and Create Package 'with user': Similar to Analyze File and create opsi Package, creates the package for an installation with a logged in user (see section opsi_template_with_userlogin). The product receives additional properties:

    • execution_method, possible values: loginOpsiSetupUser, runAsOpsiSetupUser, and runOpsiScriptAsOpsiSetupUser.

    • boolean properties: uninstall_before_install, copy_files_locally, and debug

  • Create an opsi Package Template 'with user': Doesn’t ask for a setup file, but creates an opsi template product for an installation with a logged in user and takes the information from the product configuration.

Analyzing File & Creating the Package

The following sections describe how to analyze a setup file and create an opsi product from it. To do this, click the Analyze File and Create opsi Package button on the start page (Figure 6, “opsi-setup-detector Start Page”). Then navigate to the desired installer file in the file selection dialog. The opsi-setup-detector starts the analysis immediately.

Analysis

The opsi-setup-detector uses his own engine and the tool Detect it Easy (DIE) for analysis. Files that can be detected based on their file name extension will not be analyzed.
After successfully analyzing a setup file, you will see this dialog:

The *opsi-setup-detector* has successfully analyzed a File.
Figure 7. The opsi-setup-detector has successfully analyzed a File.

If the analysis was not successful, you will see this dialog instead:

The *Sorry Unknown Installer* Dialog
Figure 8. The Sorry Unknown Installer Dialog

No installer type could be detected in the selected file.
Now, you have the option to either terminate the process by clicking on Cancel or to proceed with creating the package by selecting an installer type from the drop-down menu.

Or you will see this dialog:

The *Detected Installer not known* Dialog
Figure 9. The Detected Installer not known Dialog

A installer type was detected, but the opsi-setup-detector has no information how to handle this type.
Now, you have the option to either terminate the process by clicking on Cancel or to proceed with creating the package by selecting an installer type from the drop-down menu.

Should the analysis prove successful, a window might pop up providing additional details about the identified installer type. This informational window is typical for installer types like InstallShield, Qt Installer, or InstallAnywhere.

Additional Info: InstallShield
Additional Info: Qt Installer
Additional Info: InstallAnywhere

If the analysis has been successful, the opsi-setup-detector will display the result:

This Tab shows the Result of a successful Analysis.
Figure 10. This Tab shows the Result of a successful Analysis.

On the 1. Setup tab, you will find detailed information and various functions as follows:

  • Detected Setup type: Type of installer detected

  • Prefer Silent Install: Activate this checkbox to prefer a silent installation to an unattended installation (if possible).

  • MST allowed: Should additional mst files be used to customize the settings for Microsoft Windows Installer (MSI) applications?

  • Info: Link with further information about the installer

  • Setup File: Path and name of the analyzed setup file

  • MST File: To specify the MST file to be integrated into the MSI call

  • MsiId: Product code for MSI installers or installers that contain MSI

  • MsiName: Product name for MSI installers or installers that contain MSI; stored in the registry as DisplayName.

  • MsiUpgrade: Upgrade code for MSI installers or installers that contain MSI

  • Software version: Version of the software to be installed (if this can be determined)

  • Setup file size MB: Size of the setup file in MB

  • Required Space MB: Estimated value (size of the setup file times 6), can be adjusted if necessary

  • InstallDir: Directory where the software will be installed, assuming it is correctly identified. If the installation directory is not accurately recognized, you can manually specify the correct directory by clicking the folder icon next to this field to open a file selection dialog. Standard paths like C:\program Files or C:\program Files (x86) are automatically substituted with the relevant opsi-script constants, such as %ProgramFiles32Dir%.

  • Install Command: This represents the command determined for a non-interactive installation. The specifics of this command vary depending on whether the Prefer Silent Install checkbox is selected.

  • Uninstall Command: The command determined for a non-interactive uninstallation. The specifics of this command vary depending on whether the Prefer Silent Install checkbox is selected.
    See also: Configuration: preferMsiUninstall

  • Uninstall Program: Program detected for uninstallation; if not detected correctly, you can open a file selection dialog via the folder icon next to the field and navigate to the desired application. MSI files do not (usually) have an uninstall program.

  • Target Program: Main executable of the software being installed. It’s commonly used for creating desktop shortcuts or start menu entries. The main program is not automatically determined. If the software is already installed on the computer, you can select the executable file using the folder icon to open a selection dialog.

After the analysis is complete, any values that have been determined can be adjusted or supplemented as needed. Once you have made any necessary changes, click on the Next Step button to proceed to the first tab of the product configuration.

There is a high probability that the values obtained from the analysis might be incomplete or partially incorrect. After conducting an initial installation, it is crucial to thoroughly review and verify the accuracy of values such as InstallDir, Uninstall Program, Target Program, and Software Version in your script!

Product Configuration 1

Make the following settings on this tab:

Configure the opsi Product.
Figure 11. Configure the opsi Product.
  • opsi Product ID: This is the identifier for the new opsi package, generated from the product name specified in the opsi Product Name field. Spaces and special characters in the product name are replaced with hyphens. You can modify the suggested product ID.

  • Import control File: Click on this button to open a file selection dialog allowing you to import data from an existing control file (control, control.toml) into your current project. Note that information like version numbers, script names, or required disk space is not imported.

  • opsi Product Name: This field allows you to correct or adjust the name of the software that is being installed.

  • Product Version: Here, you can correct the version number that was determined from the setup file’s name. It should only include digits and periods, as it is used for the versioning of the opsi package.

  • Package Version: This version number differentiates between opsi products that contain the same software version but may have varying scripts or properties. Like the product version, it should only contain digits and periods.

  • Description: In this field, provide a brief description of the application. With opsi 4.3 and later, this text can be formatted using Markdown. An editing area is provided on the left side and a preview on the right.

  • Advice: Provide extra details about the software, such as its origin, download link, licensing information, etc. Starting with opsi 4.3, this text can be formatted using Markdown. An editing area is provided on the left side and a preview on the right.

  • Template Channel: Choose from the following templates in the drop-down menu to generate the scripts:

    • default: Serves as the standard and fallback option. If another selected template does not provide the necessary files for your project, default will be automatically employed. Key scripts of the product include: setup.opsiscript, uninstall.opsiscript, declarations.opsiinc, sections.opsiinc, and delinc.opsiinc.

    • training: Offers a simple structure with detailed comments; key scripts for the product are setup.opsiscript, uninstall.opsiscript, and delinc.opsiinc.

    • structured: Defaults to default; not useed in version 4.2.2 and above.

    • custom: Initially empty, this template provides space for your own template files. To use custom templates, copy them to the opsi-setup-detector/custom/template-files/ directory on the depot server, and then reinstall the opsi-setup-detector on the relevant clients.

At the bottom of the window, there are several checkboxes that allow you to integrate additional code and settings for specific purposes:

  • Support custom directory: This option adds an extra directory named custom to the product, which can hold (customer-specific) customizations. When a new version of the package is installed on the server, this custom directory will not be overwritten. The included code provides templates to include files from this directory (see the section Custom Directory).

  • Install from local temp dir: With this option, the installation files are initially copied to a local, temporary directory and installed from there. This approach is especially beneficial for components that might disrupt the network connection during installation, such as drivers (see the section Local, temporary Directory).

  • Handle License Key: This option generates an additional property dedicated to managing license keys (see the section License Key).

  • DesktopIcon: This creates an additional boolean property (defaulted to false) to manage the creation of desktop icons (see the section Desktop Icon).

  • Customize Profile: This option includes a ProfileActions section in the code, allowing for customizations in local user profiles. For an in-depth explanation, refer to the section Customize local User Profiles.

  • Uninstall_before_install: This creates an additional boolean property (defaulted to true) to control if we should uninstall before we try to install. (see section Uninstall_before_install).

Priority and Dependencies

You can define priorities and dependencies more precisely on the Product Configuration 2 tab:

Configure Priority and Dependencies.
Figure 12. Configure Priority and Dependencies.
For "standard" application software, it’s usually unnecessary to configure anything in this section, and you can proceed by clicking on Next Step.

The following settings can be adjusted on this tab:

  • Priority: This setting affects the installation order. Possible values range from 100 (indicating early installation) to -100 (signifying late installation). For application software, a priority of 0 is generally recommended. Note that the installation order can also be influenced by dependencies between products.

  • Dependencies: This area allows you to specify dependencies among products. If your opsi server’s access credentials are saved in the configuration, the tool will attempt to connect to the server. If the password hasn’t been stored for security reasons, a password prompt will appear at this stage (see the section Defining Dependencies).

Password Dialog
  • Properties: Here you can define variable properties of the producti (see the section Defining Propertys).

Defining Dependencies

Click the button Add Dependency to open the Depency Editor:

You can configure Dependencies in this Dialog.
Figure 13. You can configure Dependencies in this Dialog.

Here you can make the following settings:

  • create dependency for which action request: The default selection here is setup. Starting with opsi 4.3, other action requests are also supported, including uninstall, update, always, custom, and once. Exercise caution with this setting to avoid creating unsolvable or contradictory conditions!

This drop-down menu is only active if the dependencies_for_all_actionrequests option has been enabled in the opsi-setup-detector configuration (refer to section Start and Condfigurartion for more details).
  • productid of the dependent product: Through the drop-down menu, you can select the product that has a dependency. If there’s an active connection to the opsi server, the dialog will indicate this in green and will list the installed products. If the connection is not established, a red message will appear, and you’ll need to manually enter the product ID.

  • Require Mode: This setting is disabled when creating a meta product to prevent illogical configurations. There are two selectable options in this area:

    • Action: This option requests an ActionRequest (like setup) to be set for the product with which there is a dependency.

    • State: This refers to the product’s state that has a dependency (such as installed). If the status is different, the product is set to setup.

The actual order of installation is determined by a combination of the dependencies and the priority assigned to the products (see the section Dependencies and Order).
Defining Propertys

On the Product Configuration 2 tab, you can define modifiable properties (variables) for the product. To do this, simply click on the Add Property button:

You can configure Product Properties in this dialog.
Figure 14. You can configure Product Properties in this dialog.
Field/Function Description Notes

Property Name

Name of the product variable

Displayed as an identifier in the opsi-configed during product configuration; accessible in scripts using the GetProductProperty function.

Property Type

Type of the variable

Possible values are Text and Boolean.

Multivalue

Number of values

Determines whether the variable can take exactly one or multiple values; available only for Text type.

Editable

Values can be overwritten

Specifies whether the default values can be overwritten with new or additional values or not; available only for Text type.

Possible Values

Input values

A comma-separated list of possible input values. If set to True, you can later add to this list in opsi-configed; available only for Text type.

Default Values

Default value

For Text type: a free text field. For Multivalue type: a multiple-choice selection.

Selecting Product Icon

On this tab, you can select an icon for the product that will be displayed during installation:

Select an Icon for your Product.
Figure 15. Select an Icon for your Product.
Should you decide to skip this optional step, the opsi-setup-detector will default to selecting an icon with gears and automatically proceed to the next tab.

To select a different icon, click on the open icon folder button located on the right side of the windowi to open a selection dialog where you can navigate to the folder containing your preferred icons. Initially, you will be directed to the 128x128 folder, which includes a variety of icons provided with the opsi-setup-detector under a free license. Once you open this folder, all available icons will be displayed on the left side of the window, allowing you to choose one for your product.

Creating the Product

After you have finished configuring the product, you can proceed to create it using the options provided on the last tab.

Create the Product on the last Tab.
Figure 16. Create the Product on the last Tab.

The following options are available on this tab:

  • Path to opsi-work-bench: Displays the directory you configured during setup for the workbench share on your opsi server. This can be either a drive letter or a UNC path.

  • Check workbench path button: Use this to verify whether the workbench share is accessible.

  • Create mode: Choose how the package should be created:

    • create opsi product files: This option will create (if not already existing) the directory structure for the new opsi product on the workbench. It also generates or copies the necessary files for the package.

    • create opsi product files and build package: In addition to creating the directory structure, this option attempts to build the package on the opsi server. If the build and install checkbox is selected in the Build Mode area on the right, the product will be installed on the server after being built. If the connection to the opsi web service is configured, the service is contacted, and if necessary, it will prompt for the password.

The building and installation process via the web service only works if the opsiconfd is of version 4.2.0.287 or newer. If the service is either unavailable or outdated, the opsi PackageBuilder (non-GUI version) will step in to create the package.
  • create opsi product files and start the interactive PackageBuilder creates the directory tree for the new opsi product (if it doesn’t exist on the workbench) and starts the opsi PackageBuilder in an interactive mode. You need to exit this application explicitly to return to the opsi-setup-detector.

    • Build Mode: There are two options here, which define the actions performed when you select Create opsi Package:

  • build: This option solely creates the opsi package, similar to the opsi-makepackage command.

  • build and install: This option not only creates the opsi package (opsi-makepackage) but also installs it, equivalent to the command opsi-package-manager --install <package>.

    • Create opsi Package: Click on this button to start the build process. If there is an opsi product with the same name, you will see the following dialog:

Backup Dialog
  • Rebuild Package only: This button initiates the building of the opsi package without re-generating the opsi files first. Hence, it’s a convenient option for rebuilding a package after making modifications to the script in an external editor.

During the creation of the opsi product, the opsi-setup-detector records all the information you’ve entered into a file named opsi-project.osd, located in the root directory of the product.

At a later stage, you can reopen an opsi-project.osd file with the opsi-setup-detector if you need to make adjustments to an already existing package.

Opening an existing Project

To open an existing project structure as a project with the opsi-setup-detector, there are two approaches:

  • For products created with the opsi-setup-detector: Navigate to the File menu, then select Open, and select the opsi-project.osd file located in the root directory of the project.

  • For products not created with the opsi-setup-detector: Open the control file (either control or control.toml) via the menu entry File / Open Control File. It’s located in the OPSI directory of the product.

The second method provides less comprehensive information, particularly regarding the setup file used by the installer.

Testing and improving a Script

There are two distinct methods for testing and enhancing a product:

  • Test the script you’ve developed without installing it on the opsi server or deploying it to a client (Standalone Tests).

  • Evaluate the entire product by installing it on the server and deploying it to a client (Integrated tests).

The instructions that follow are based on the assumption that the product you are testing was created using the opsi-setup-detector.

Standalone Tests

Start the application opsi-script-gui:

  • Windows: Double-click to open opsi-script.exe. If the client agent is installed on your computer, locate the program at C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\opsi-script.exe. Otherwise, manually copy the contents of the opsi-script\windows\x86\ directory from the \\<opsiserver>\opsi_depot share to your Windows computer.

On Windows 10, you should right-click the opsi-script.exe file in Explorer and choose Run as administrator from the context menu.
  • Linux: Start /opt/opsi-script/opsi-script-gui.

  • macOS: Launch the application via the /Applications/opsi-script menu.

Upon starting the application, you will be presented with the following window:

Open *opsi-script-gui* in interactive Mode.
Figure 17. Open opsi-script-gui in interactive Mode.

Use Select Script to choose the script you’re looking to test. Next, click Start to execute the script on your computer. Alternatively, for a syntax check, select Test_Syntax. This action checks the script for syntax errors but does not run it on your computer (see the section Checking the Script Syntax).

To observe how opsi-script interprets the script, you can use the opsi-logviewer.

Adjust the log level using the slider in the bottom right corner of the opsi-logviewer to display more or fewer details.

If you need to modify the script, you have a couple of options for editing:

  • Open the project in the opsi PackageBuilder and use the editor provided there.

  • Alternatively, use a text editor like jEdit that supports opsi-script syntax highlighting. This feature is typically included in the basic setup of the opsi products.

The text editor jEdit supports syntax highlighting for *opsi-script* scripts.
Figure 18. The text editor jEdit supports syntax highlighting for opsi-script scripts.

Now, you can save the changes and keep the editor open. Simply switch back to the opsi-script window and click on the Start button again; there’s no need to reselect the script. To observe the modifications, refer to the opsi-logviewer. You can refresh the log by choosing Reload from the right-click context menu or by clicking the reload button on the toolbar.

To fine-tune your scripts to perfection, you can repeat these steps as needed:

  1. Edit and save the script in your text editor.

  2. Run the script (again) in opsi-script.

  3. Check the updated logs to confirm the impact of your changes.

Integrated tests

For the integrated tests, roll out the product on a test client:

  • Open the script setup.opsiscript in an editor and make changes if necessary; save the changes:

    • Open the project in opsi PackageBuilder and start the editor provided here.

    • Use a text editor such as jEdit with opsi-script syntax highlighting (included in the basic setup of the opsi products).

  • Build the product:

    • Variant 1: Open the project in opsi PackageBuilder and click on the Build button.

    • Option 2: Open a terminal on the opsi server or log in via SSH, e.g. with PuTTY. Switch to the workbench (/var/lib/opsi/workbench) and then to the project directory. Call the following command:
      opsi-makepackage

  • Install the product on the opsi server:

    • Variant 1: Click on the Install button in the opsi PackageBuilder.

    • Variant 2: Run the following command in the project directory in the terminal:
      opsi-package-manager -i <myproctid_version.opsi>
      Replace <myproctid_version.opsi> with the name of the opsi package (as it was output during the build process).

  • Deploy the product via the opsi-configed management interface:

    1. Select the test client on the Clients tab.

    2. Select the product on the Localboot products tab. If your opsi package does not appear there (which is normal after the first installation), press the button on the very left of the toolbar or select File / Reload all data from the menu.

    3. Set the product to setup and save the changes.

    4. Start the client or call up on_demand from the context menu for running clients.

    5. Wait until the product has been installed on the client.

    6. Switch to the Logfiles tab and then to instlog and view the log file.

Adjust the log level using the slider in the bottom right corner to display more or fewer details.

To further customize your scripts, you can repeat these steps:

  1. Edit the script in the editor and save your changes.

  2. Build the product.

  3. Install the product on the server.

  4. Deploy the product on the client.

  5. Check the log file.

opsi PackageBuilder: Modifying a Script

Launch the opsi PackageBuilder (oPB) from the start menu. If you encounter difficulties (particularly when using a KDE desktop environment), you might need to start the program from a terminal instead. Simply input any path, and if an error message appears indicating that the path was not found, acknowledge it to proceed:

opsipackagebuilder --path /home

When you start opsi PackageBuilder for the first time, it will be in offline mode because it hasn’t yet established a connection with the opsi server:

opsi PackageBuilder: First Start in Offline Mode
Figure 19. opsi PackageBuilder: First Start in Offline Mode

Initial Configuration

To set up the opsi PackageBuilder, click on the Settings button.

Configure the following on the General tab:

  • Config server: Input the fully qualified domain name (FQDN) of your opsi config server, such as opsi.mycompany.org.

  • opsiadmin User: Enter the username of an administrator with access to the opsi service. This account should be a part of the opsiadmin group (refer to the section Users and Groups).

  • opsiadmin Password: Provide the corresponding password for the opsiadmin user. This password will be encrypted and is not visible. It’s essential for the opsi PackageBuilder to communicate with the opsi server.

  • 4.0.4 or newer: Activate this checkbox.

  • SUDO without password: This is the default setting; accept it as it is.

  • Package maintainer: Enter your full name. This will be included in the changelogs.

  • Mail address: Provide your email address here; it will also be featured in the changelogs.

oPB Settings: *General* Tab
Figure 20. oPB Settings: General Tab

On the Program tab, configure the following settings:

  • Activate the checkbox Extended changelog editor.

  • Select a Development folder; enter the full path to the directory in which the opsi packages are to be created. Ideally, this is the path to the mounted share with the opsi workbench. Optionally, you can select Use existing network drive.

  • Script eEditor: Choose the text editor for script editing according to your operating system:

    • Windows: Accept the default setting (path to the oPB ScriptEditor).

    • Linux: Path to the editor, e.g. /usr/bin/jedit; leave the Editor command line options field empty.

    • macOS: Path to the editor, e.g. /Application/jedit; Editor command line options field remains empty.

oPB Settings: *Program* Tab
Figure 21. oPB Settings: Program Tab

On the opsi Commands tab, adjust the following setting, which deviates from the default configuration:

  • Build command: We recommend the following command:
    opsi-makepackage -v

  • Activate the checkbox Use depot functions.

oPB Settings: *opsi Commands* Tab
Figure 22. oPB Settings: opsi Commands Tab

Save the settings and restart the opsi PackageBuilder. After restarting, the program should switch to online mode.

opsi PackageBuilder: Start in Online Mode
Figure 23. opsi PackageBuilder: Start in Online Mode

Modifying, packing and installing packages

To edit a package, select the Open Package (F2) button and locate the directory created by the opsi-setup-detector, for instance, w:\develop\newprod2. This action will open the following dialog:

Open an existing opsi Package.
Figure 24. Open an existing opsi Package.

On the Package tab, the metadata of the opsi product is displayed in the left column (refer to section Product Configuration 1 for details). Script files are situated on the right. Next to each script file, you will find this button:

oPB: *Edit* Button
Figure 25. oPB: Edit Button

When you click on this button, the script editor specified in the settings will launch, allowing you to modify the script. On Windows, this typically defaults to the oPB-ScriptEditor. This editor comes equipped with features like colored syntax highlighting, optional source code folding (for a more compact view with comments), customizable lexer definition (accessible when launched from the start menu), auto-completion for syntax elements and variables, as well as customizable and reusable code blocks known as snippets.

The editor’s core component is the Scintilla module, which is also used by other renowned text editors like Notepad\++, CodeLite, etc. However, the lexical elements for opsi scripts, such as syntax highlighting and folding, are implemented using AutoIt. This is because Scintilla does not inherently provide specific highlighting for opsi scripts. Since AutoIt is an interpreter language, the ScriptEditor might not be as fast as other editors, particularly when editing very large scripts or with code folding activated.

The settings provide an option to enable or disable these functions when the editor is initiated via oPB. By default, syntax highlighting and folding are turned off when the editor is started from the start menu. However, you can activate them via the View menu if needed.

Launch the editor from the command line to access specific options directly. The --help option displays information about available parameters.

On the Dependencies tab, the dependencies established with other opsi products are displayed, as detailed in the section Priority and Dependencies.

oPB: *Dependencies* Tab
Figure 26. oPB: Dependencies Tab

The Properties tab shows the product properties, including type, value, etc:

oPB: *Properties* Tab
Figure 27. oPB: Properties Tab

At the bottom of the window, you can see the following buttons:

Button Description

image::common:opb_btnPacken.png[]

Starts an SSH connection to the opsi server and executes the command for packaging (see section opsi-makepackage: Packaging the Product).

image::common:opb_btnInstallieren.png[]

Starts an SSH connection to the opsi server and executes the install command (see section opsi-package-manager: Installing the Product).

image::common:opb_InstSetup.jpg[]

Similar to Install, but the package is also set to setup on all clients on which it is marked as installed.

Be very cautious when using the Inst.+Setup button. Only use it when you’re certain of its function and implications!

opsi-makepackage: Packaging the Product

To package the product, navigate to the product’s main directory and execute the command opsi-makepackage.

It’s a good practice to generate an accompanying MD5 checksum file. Tools like opsi-package-updater use this file to verify the package’s integrity post-transfer.

By default, opsi-makepackage automatically creates an MD5 checksum file. Should you wish to disable this feature, use the following parameter when executing the command:

opsi-makepackage --no-md5

When transferring packages to opsi depot servers, opsi-makepackage uses the zsync tool, which only transmits the differing parts of packages, thereby conserving bandwidth. This process needs a .zsync file, which opsi-makepackage automatically generates. To turn off this functionality, disable the feature using the following parameter:

opsi-makepackage --no-zsync

If you encounter storage issues in the /tmp temporary directory while creating large packages, you can define an alternative temporary directory using --temp-directory.

Additionally, before building a package, opsi-makepackage examines if a package with an identical name or version number already resides in the directory. Should this occur, the tool will prompt you for your preferred course of action:

Package file '/var/lib/opsi/workbench/mytest/mytest_3.14-1.opsi' already exists.
Press <O> to overwrite, <C> to abort or <N> to specify a new version:

Press [O] to overwrite the existing package, press [C] to halt the process, or opt for [N] to provide a fresh version number for the product or package.

More details about the opsi-makepackage tool and its various options are available in the section opsi-makepackage.

opsi-package-manager: Installing the Product

To install opsi products, use the opsi-package-manager command. First, navigate to the main directory of the product and execute the following command:

opsi-package-manager -i <myproductid_version.opsi>
For additional details about the opsi-package-manager tool and its parameters, refer to section opsi-package-manager.

Example: control File

Since opsi 4.3, you can create a control file in TOML format. If such a control.toml file exists, it is considered the definitive source and should be properly maintained.

control file in opsi ⇐ 4.2 style:
[Package]
version: 1
depends:

[Product]
type: localboot
id: mytest
name: My Test
description: A test product
advice:
version: 3.14
priority: 0
licenseRequired: False
productClasses:
setupScript: setup.opsiscript
uninstallScript:
updateScript:
alwaysScript:
onceScript:
customScript:
userLoginScript:

[ProductDependency]
action: setup
requiredProduct: javavm
requiredStatus: installed

[ProductProperty]
type: unicode
name: mytextprop
multivalue: False
editable: True
description: hint
values: ["off", "on"]
default: ["off"]

[ProductProperty]
type: bool
name: myboolprop
description: yes or no
default: False

[Changelog]
mytest (3.14-1) testing; urgency=low

  * Initial package

 -- jane doe <j.doe@opsi.org>  Mi, 14 Jul 2010 12:47:53 +0000
control file in opsi >= 4.3 .toml style:
[Package]
version = "1"
depends = []

[Product]
type = "localboot"
id = "mytest"
name = "My Test"
description = """A test product"""
advice = """"""
version = "3.14"
priority = 0
licenseRequired = false
productClasses = []
setupScript = "setup.opsiscript"
uninstallScript = "uninstall.opsiscript"
updateScript = ""
alwaysScript = ""
onceScript = ""
customScript = ""
userLoginScript = ""
windowsSoftwareIds = []

[[ProductDependency]]
action = "setup"
requiredProduct = "javavm"
requiredStatus = "installed"
requirementType = ""

[[ProductProperty]]
type = "bool"
name = "myboolprop"
description = "hint"
default = [false]
Stand-alone changelog entry: changelog.txt file
mytest (3.14-1)

  * Initial package

-- jane doe <j.doe@opsi.org> Di, 29 Aug 2023 10:36:09

opsi-newprod: Creating a Product

Apart from the graphical tools for creating opsi products introduced in this chapter, the opsi-newprod command line tool is available to create a basic structure for opsi products. Upon launching, it initially inquires whether you want to create a localboot or a netboot product.

For products installed via the client agent or opsi-script, opting for localboot is appropriate. Choose netboot for products that are executed via the opsi Linux boot image, like operating system installations.
First, select the Type of opsi Product you wish to create.
Figure 28. First, select the Type of opsi Product you wish to create.

Use the [Tab] key to navigate to the OK option, or press [F12] to confirm your selection. In the next dialog, enter the information for your new opsi product:

Enter the Information about the Product.
Figure 29. Enter the Information about the Product.

Fill in the fields with the appropriate information:

  • Product id: This is a unique identifier for the product and is generally independent of the version. Only use lower case letters, no spaces or special characters; the hyphen - is permitted as a separator.

  • Product name: This is the name of the product; we recommend avoiding special characters.

  • Description: Enter additional information about the product. Tools like opsi-configed will display this under Description.

  • Advice: If you want to include further information, for example, on how to use the product, this is the place. opsi-configed displays these under Note.

  • Product version: The version of the packaged software is shown here; a maximum of 32 characters are allowed.

  • Package version: This is the version of the package for the specified product version. It’s used to differentiate between packages that have the same product version but, for example, have updated or corrected opsi-script scripts.

  • License required: This setting does not impact localboot products. For netboot products, however, it specifies whether a license key should be obtained from the license management system.

  • Priority: The value affects the order in which installations are executed, with possible values ranging from 100 (indicating installation at the very beginning) to -100 (indicating installation at the very end). Additionally, dependencies on other products may also influence the sequence of installation.

Next, specify the scripts that you provide for the various actions:

Enter the Name of the Scripts.
Figure 30. Enter the Name of the Scripts.

Enter the following information:

  • Setup script: Usually, this is setup.ins.

  • Uninstall script: Usually, this is uninstall.ins.

  • Update script: The script is designed to apply small modifications to an existing, large installation. When the product’s action request is set to setup, this update script is automatically run following the completion of the setup script’s execution.

  • Always script: This script runs each time the client agent is activated, for instance, following every system startup.

  • Once script: The script has the resulting state not_installed. It’s a rarely used option that should be ignored unless you have a specific purpose for it.

  • Custom script: Such a script neither alters subsequent actions nor affects the resulting state. It’s a seldom-used option, best left alone unless you’re certain of its application.

  • User login script: This is used to make modifications to the profile of the currently logged-in user after they’ve logged in. This only works if you’re using the User Profile Management extension.

Typ Resulting State Subsequent Action

setup

installed

none

uninstall

not_installed

none

update

installed

none

always

installed

always

once

not_installed

none

custom

unchanged

unchanged

User login

unchanged

unchanged

Now that the product details are specified, you can define dependencies with other products if needed. Otherwise, select No to proceed.

Would you like to define a Dependency?
Figure 31. Would you like to define a Dependency?

If you’ve chosen Yes, the following dialog appears:

Define the Product Dependency accurately.
Figure 32. Define the Product Dependency accurately.

Enter the following information:

  • Dependency for action: This contains the action of the product (that you are currently creating) for which the dependency applies (since opsi 4.3: not only setup`).

  • Required product id: Enter the ID of the produc for which there is a dependency.

  • Required action: You can either request the setup action or the installed status (see below).

  • Required installation status: This setting indicates the expected status of the dependent product, typically installed. If the actual status differs, the system will automatically set the product to setup.

  • Requirement type: This option defines the installation sequence for the product dependencies. If the dependent product must be installed before the installation of the current product can commence, select before. Conversely, if it should be installed after the current product, choose after. If the installation order is irrelevant, you can leave this field empty.

The actual installation order is determined by a mix of product dependencies and their set priorities. For more details on how these factors interact, refer to the section Priority and Dependencies.

Next, opsi-newprod focuses on properties, prompting you with the following questions:

Do you want to create Properties?
Figure 33. Do you want to create Properties?

Product properties are stored on a client-specific basis and consist of a name (key) that can have different values. These are then queried by the opsi-script script. Initially, you determine whether it’s a text value (unicode) or a logical value (boolean):

Select the Property Type.
Figure 34. Select the Property Type.

For a unicode property, complete the following fields:

  • Property name (identifier): Input the name of the property.

  • Property description: This text appears as a tooltip in opsi-configed for assistance.

  • Possible values: Type a comma-separated list of all possible values the key can assume. Leaving this field empty allows any value to be entered later in opsi-configed.

  • Editable: Choose whether additional values can be entered beyond the specified list; you’ll see options True or False.

If a value includes a backslash \, it must be entered twice. For example, a path specification should look like this: C:\\temp.

In the next dialog, you can set a default value for the property.

For boolean type properties, as opposed to unicode, the dialog differs. Here, you simply provide a name and a description for the property.

Enter the Name and the Description.
Figure 35. Enter the Name and the Description.

You can define multiple product properties. Once you choose not to define any more properties by responding negatively to Do you want to create a product property?, the final dialog will appear. In this dialog, you’re required to enter your name and email address, which are essential for the changelog.

Finally, enter the Contact Details of the Maintainer.
Figure 36. Finally, enter the Contact Details of the Maintainer.

The basic structure of the product is now ready. In the new directory you will find the files and directories described above. Change to the OPSI folder and list the content (ls). The control file now contains the data you just defined, and you can load the file into an editor to view or change the entries.

Starting from opsi version 4.3 and onwards, the opsi-newprod tool will generate a control file in the TOML format (.toml), along with a separate changelog.txt file.

Advanced Configuration with opsi-setup-detector

In the upcoming sections, we’ll explore additional configuration features of the opsi-setup-detector. These include using a custom directory, installing from a local temporary directory, managing license keys, and personalizing user profiles and desktop icons.

Custom Directory

When you activate the Support custom directory checkbox on the Product Configuration 1 tab, the product gets supplemented with an extra directory named custom. This directory is ideal for storing client-specific customizations. Importantly, when you upgrade to a new version of the package, the custom directory remains untouched. The script includes templates for integrating files from this directory into the installation process.

Here’s what gets added to the setup.opsiscript file:

; copy custom files to install dir
Files_copy_from_custom_dir

This calls a Files section to copy files from a custom directory to the client. The corresponding section looks like this:

[Files_copy_from_custom_dir]
copy -s "%scriptPath%\custom\*" "$installdir$"

In this example, the contents of the custom directory are transferred to the installation directory, and the custom directory itself is created. It contains the two files OPSI\preinst and OPSI\postinst. These files ensure that the contents of the custom directory remain intact on the depot, even when updates occur.

Local, temporary Directory

When you activate the Install from local temp dir checkbox on the Product Configuration 1 tab in opsi-setup-detector, it adjusts the installation process such that the installation files are initially copied to a local, temporary directory, and the installation is carried out from there. This method is particularly beneficial in scenarios where the installation might disrupt the network connection, a common situation with driver installations.

As a result, opsi-setup-detector creates a new boolean property named install_from_local_tmpdir, which defaults to false and has this description: Determines whether the installation files are copied to a local directory.

To accommodate this feature, modifications are made to the setup.opsiscript file as follows:

set $Install_from_local_tmpdir$ = GetProductProperty("Install_from_local_tmpdir","False")

; before the installation:
if $Install_from_local_tmpdir$ = "true"
	; copy installer files to tempdirectory
	Files_copy_installer_to_temp
	; set $installerSourceDir$ to tmpdir
	set $installerSourceDir$ = forcePathDelims("%opsiTmpDir%\"+$ProductId$)
endif

; do the installation

; after the installation
if $Install_from_local_tmpdir$ = "true"
	; cleanup installer tempdirectory
	Files_del_installer_from_temp
endif

Now the installation files are temporarily moved to a temporary directory and deleted after the installation if the condition Install_from_local_tmpdir is set to true.

The corresponding sections look like this:

; copy installer files to tempdirectory
[Files_copy_installer_to_temp]
copy -s "$installerSourceDir$\*.*" "%opsiTmpDir%\$ProductId$"

; cleanup installer tempdirectory
[Files_del_installer_from_temp]
del -sf "%opsiTmpDir%\$ProductId$\"

License Key

Activating the Handle License Key checkbox on the Product Configuration 1 tab within the opsi-setup-detector adds the necessary property and code for managing license keys.

This action creates an additional property named secretlicense_or_pool. By default, this property is left blank and carries the description license key or opsi licensepool. The inclusion of secret in the property name signifies that the value of this property will be masked in opsi-configed, meaning it won’t be displayed in plain text.

This code is inserted into the setup.opsiscript file:

DefVar $LicenseHandledByScript$ = "true"

set $LicenseOrPool$ = GetConfidentialProductProperty("SecretLicense_or_Pool","")

; before the installation:
; ---------------------------------------------------------------
comment "handle license "
; ----------------------------------------------------------------
if $LicenseHandledByScript$ = "true"
	comment "we should handle license"
	;reserve license and get license key
	set $LicenseKey$ = get_licensekey_byPoolOrKey($LicenseOrPool$)
	; here the section or function calls should follow which
	; make use of the license key resp the license reservation
endif

get_licensekey_byPoolOrKey checks if the value entered in the secretlicense_or_pool property corresponds to the name of a license pool as defined in the opsi extension License Management. If it matches, a license key is retrieved from this specified pool. Otherwise, the content of the property is treated and used directly as the license key.

This code is inserted into the uninstall.opsiscript:

DefVar $LicenseHandledByScript$ = "true"

set $LicenseOrPool$ = GetConfidentialProductProperty("SecretLicense_or_Pool","")

; after the uninstallation

; ---------------------------------------------------------------
comment "handle license "
; ----------------------------------------------------------------
if $LicenseHandledByScript$ = "true"
	comment "we should free license used"
	Set $tmpstr$ = FreeLicense($LicenseOrPool$)
endif

Desktop Icon

Activate the checkbox DesktopIcon on the Product Configuration 1 tab to add a property and corresponding code for managing desktop icons.

A new boolean property named desktopicon is then created, set to false by default, and described as Should there be a desktop icon?

The corresponding code snippet is then integrated into the setup.opsiscript file:

set $desktopicon$ = GetProductProperty("desktopicon", "False")

; after the installation
; handle desktop icon
if $DesktopIcon$ = "true"
	comment "Create Desktop Icon"
	Linkfolder_create_desktop_icon
else
	comment "Remove Desktop Icon"
	Linkfolder_remove_desktop_icon
endif

If desktopicon is set to true, a section Linkfolder is called. The corresponding code (which is also inserted in the uninstall.opsiscript file) looks like this:

[Linkfolder_remove_desktop_icon]
; check delete_element
set_basefolder common_desktopdirectory
set_subfolder ""
delete_element $productId$

[Linkfolder_create_desktop_icon]
; check name, target and working_dir
set_basefolder common_desktopdirectory
set_subfolder ""
set_link
	name: $productId$
	target: $Installdir$\$targetprogram$
	parameters:
	working_dir: $Installdir$
	icon_file:
	icon_index:
end_link

Additionally, these two lines are added to the delinc.opsiinc file:

comment "Start Remove Desktop Icon Handling :"
Linkfolder_remove_desktop_icon

Customize local User Profiles

The Product Configuration 1 tab includes a checkbox named Customize Profile. When selected, a section Profileactions is added to the code which facilitates modifications to local user profiles. This feature also extends to Roaming Profiles through a login script.

In the OPSI/control file, the setup.opsiscript is designated not only as a setupScript but also as a userLoginScript.

The following segment is added to the setup.opsiscript file:

; Run the customization for user profiles
ProfileActions

The code triggers the execution of a section named ProfileActions. Depending on the context in which it’s invoked, this section is executed for all local profiles or specifically for the profile of the currently logged-in user (see the chapter User Profile Management).

The sections relevant to this process, which serve as templates for modifying user profiles, are structured as follows:

[ProfileActions]
; all section that called from [ProfileActions]
; will be executed for all user profiles
;
; if this script runs as loginscript
; only the [ProfileActions] will be executed

; copy some files to every user profile
Files_copy_to_user_profiles

; make entries in every currentuser hive
Registry_current_user

; modify or create ini files in all user profiles
;Patches_in_user_profiles  "%UserProfileDir%\Appdata\Roaming\<path_to_ini_file>"
Patches_in_user_profiles  "%UserProfileDir%\Appdata\Roaming\osd_profile_example\osd_profile_example.ini"

[Files_copy_to_user_profiles]
; example structure:
;copy "%Scriptpath%\profile_files\*.*" "%UserProfileDir%\Appdata\Roaming\<path_to_application_dir>"
; example:
;copy "%Scriptpath%\profile_files\*.*" "%UserProfileDir%\Appdata\Roaming\osd_profile_example"

[Registry_current_user]
; example structure:
;openkey [HKCU\Software\<application key>]
;set "<var name>" = "<var value>"
; example:
;openkey [HKCU\Software\osd_profile_example]
;set "osd_profile_example_entry" = "example_value"

[Patches_in_user_profiles]
; example structure:
; set [<section name>] <key name>=<value>
; example:
;set [example_section] example_key=example_value

Uninstall_before_install

Activate the checkbox Uninstall_before_install on the Product Configuration 1 tab to add a property and corresponding code to control if we should uninstall before we try to install.

A new boolean property named Uninstall_before_install is then created, set to true by default, and described as Should we add code to check if we uninstall before the installation ?

The corresponding code snippet is then integrated into the setup.opsiscript file:

set $uninstall_before_install$ = GetProductProperty("uninstall_before_install", "True")

(...)

if FileExists("%ScriptPath%\delinc.opsiinc")  and ($uninstall_before_install$ = "true")
	comment "Start uninstall part"
	include_insert "%ScriptPath%\delinc.opsiinc"
endif

Installation with Logged-in User

There are times when software installations require a logged-in user. An indication of this is when a manual execution of an opsi-script script with commands for unattended or silent installation works, but the same installation fails when executed automatically through opsi.

This could be because the installation program requires a logged-in user or needs access to a user profile. In such scenarios, you can integrate your installation into an opsi package that establishes these necessary conditions. You can create such a package using the opsi-setup-detector by selecting the Windows task Analyze File and Create Package 'with user'.

Customizing the Unattended/Silent Setup

Following a successful silent installation, there’s often a need for additional customizations. Using opsi-script makes these adjustments manageable, but first, it’s essential to understand which changes in the graphical user interface correspond to specific alterations in files and the Windows registry.

For this task, consider using tools such as:

Setup with Automated Responses

An alternative and swift method for integration into automatic software distribution is the setup with automated responses. This approach uses a control program to automate user interactions with dialog windows that appear during setup.

For this, we recommend this tool:

AutoIt: Managing the Setup Process

AutoIt provides various functionalities for managing the setup process, including the capability to address potential error conditions with [ADLIB] script sections.

One critical issue, however, remains unaddressed: unexpected windows, not previously incorporated into the script, can halt the script’s execution. Additionally, user interventions through mouse and keyboard (unless disabled) can unpredictably alter the scripted sequence of events.

For these reasons, an unattended or silent setup is typically the better solution! A hybrid method can also be effective: use a silent setup for the main installation, with an AutoIt script intercepting and managing known exceptions or special conditions.

AutoIt: Known Issues

When installations are transferred to a different desktop in the client agent configuration, or if the desktop is locked, certain AutoIt functions have problems.

It is advisable to steer clear of these functions in opsi-script scripts, if possible:
  • winwait()

  • winactivate()

  • Send()

Unfortunately, these are the three most frequently used functions. We recommend replacing the commands with those included in the opsi-script library C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\lib\opsi-autoit-lib.au3. This library not only includes the extended functions outlined here but also encompasses a logging function. Simply copy the opsi-autoit-lib.au3 file into the product directory and then include it in the AutoIt code like this:

#include "%scriptpath%\opsi-autoit-lib.au3

After that, you can replace the following items:

  • You can replace winwait() with the function opsiwinwait($title, $text, $maxseconds, $logname).

  • Send() can be replaced by the function opsiControlClick($title, $text, $id, $maxseconds, $logname) or by opsiControlSetText($title, $text, $id,$sendtext, $maxseconds, $logname).

It is recommended to determine the ControlID with Au3info.exe. Be sure to use the numeric ControlID, as other variants seem to cause problems.
  • You can find examples in the directory C:\Program Files (x86)\opsi.org\opsi-client-agent\opsi-script\lib\ in the files:

    • autoit_example_1.txt

    • autoit_example_2.txt

    • autoit_example_3.txt

Analyzing and Repackaging

When developers build an application package, they are aware of the essential components needed for its functionality. In cases where an installation package already exists, running the setup program can reveal which parts must be installed on a workstation to achieve the desired functionality.

There are a number of tools for analyzing setup programs, e.g. Regshot

Uninstalling Products

Removing software from a computer typically involves creating an uninstall script. However, the challenge lies in determining the specifics of the installation process and ensuring that only the necessary components are removed to avoid system damage. Ideally, the software manufacturer is best equipped to know the exact uninstallation process.

Products often come with automated uninstall routines. When these can operate without user intervention, they are the preferred choice. In scenarios where an automated routine isn’t available or needs augmentation, opsi-script can be used. This section provides an overview of the available options.

Using the Uninstallation Routine

If the product’s manufacturer supplies a program (or an MSI package) for uninstallation, first check whether it operates silently, without user interaction. If this is not the case, an AutoIt script can be used in combination with the uninstallation routine.

The call to the executable file can be placed in a [WinBatch] section within the opsi-script script:

[WinBatch_start_ThunderbirdUninstall]
"%SystemRoot%\UninstallThunderbird.exe" /ma
Even when a manufacturer provides a dedicated program for uninstalling their product, don’t assume it completely removes all components. Always verify on a test system to ensure the computer remains stable post-uninstallation and to check if any files or registry entries persist.

Uninstalling MSI Products

When a product is distributed as an MSI package and installed via msiexec, it can typically be uninstalled using the same tool. Use msiexec.exe with the /x parameter, followed by the name of the MSI package or its GUID.

Each MSI package has a unique, product-specific GUID that remains consistent across all installations. This ID can be found in the registry at HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall.

For silent uninstallation without user interaction, include the /qb-! parameter in your command:

msiexec.exe /x some.msi /qb-! REBOOT=ReallySuppress

This is what the uninstallation looks like with a GUID:

msiexec.exe /x {003C5074-EB37-4A75-AC4B-F5394E08B4DD} /qb-!

Each version of a product might have a unique GUID. To remove older versions, it’s important to pinpoint their respective GUIDs.

To do this, there are different methods. The preferred method since opsi-setup-detector Version 4.3.3 is using the MsiUpgradeCode.

MsiUpgradeCode

Here we use the MsiUpgradeCode, extracted by opsi-setup-detector from the MSI file.
The MsiUpgradeCode is product specific and version independent. The osd-lib.opsiscript library contains the function getGuidListByMsiUpgradecode which list all the MsiProduct codes that identfy installed software that matches the given MsiUpgradeCode. This list ($UninstallList$) can be used to control the uninstall of installed versions.

; Variant 3:
;-----------------------------------------------------
; Finding the MsiId by the Upgrade Code from the MSI file:
; The MsiUpgradecode should be product specific and version independent.
; It should be - it is not always.
Set $MsiUpgradecode$ = '{C73ED533-953E-47E5-9A42-A48292BB7C6C}'
; get Installed MsiIds by the UpgradeCode
Set $UninstallList$ = getGuidListByMsiUpgradecode($MsiUpgradecode$)
;-----------------------------------------------------

MsiDisplayName

This method involves using the `MsiName`, extracted by `opsi-setup-detector` from the MSI file.

This MsiName is listed as DisplayName in the registry’s Uninstall section. Use the MsiName to search for the right GUID. Start by removing any details about the architecture and version at the end of MsiName. Then, encapsulate it with regular expressions:

; Variant 2:
;-----------------------------------------------------
; Finding the MsiId by the Displayname from Registry:
; Be sure that the Displayname is set correctly:
Set $DisplayName$ = 'grepWin x64'
; escape all regex relevant chars with '\' : '\^$.|?*+()[{'
set $DisplayNameRegex$ = escapeRegexMetaChars($DisplayName$)
; '(?i)' = case insesitive ; '.*' = 0 or more of any thing
set $DisplayNameRegex$ = '(?i)'+$DisplayNameRegex$+'.*'
Set $UninstallList$ = getGuidListByDisplaynameRegex($DisplayNameRegex$)
;-----------------------------------------------------

In this script segment, the following actions are performed:

  • Set $DisplayName$ = 'short msi name': The variable $DisplayName$ is assigned the truncated MsiName, omitting any additional details like version or architecture.

  • set $DisplayNameRegex$ = escapeRegexMetaChars($DisplayName$): This line prepares $DisplayName$ for a regex search, effectively escaping any special characters in the string.

  • set $DisplayNameRegex$ = '(?i)'$DisplayNameRegex$'.*': This regex pattern is set to be case-insensitive (?i) and designed to match the beginning of a string, followed by any sequence of characters, essentially accommodating any additional details following the base name.

  • Set $UninstallList$ = getGuidListByDisplaynameRegex($DisplayNameRegex$): The script then uses the getGuidListByDisplaynameRegex function, part of the osd-lib.opsiscript library, to scour the registry. It compiles a list matching the criteria, formatted as <MsiVersion> = <msi GUID>.

Processing the $UninstallList$

The further uninstall process is controlled by the entries of the $UninstallList$:

comment "run the uninstallation "
; ----------------------------------------------------------------

if count($UninstallList$) int> "0"
	Comment "Uninstalling all found versions"
	for %uninstallEntry% in $UninstallList$ do Sub_Uninstallation_msi
endif

[Sub_Uninstallation_msi]
set $MsiVersion$ = TakeString(0, splitstring('%uninstallEntry%', "="))
set $MsiId$ = TakeString(1, splitstring('%uninstallEntry%', "="))

if stringtobool(checkForMsiProduct($MsiId$))
	Message "Uninstalling :"  + $ProductId$ + " " + $MsiVersion$+ "..."
	Winbatch_Uninstall_1
	Set $ExitCode$ = getlastexitcode
	if stringtobool(isMsiExitcodeFatal($ExitCode$, "true", $ErrorString$ ))
		LogError $ErrorString$
		isfatalerror $ErrorString$
	else
		Comment $ErrorString$
	endif
else
	Comment "No previously installed " + $ProductId$ + " version found"
endif

In this script segment, the following actions are performed:

  • If the $UninstallList$ contains one or more entries

  • Call for every entry of the $UninstallList$ the sub section [Sub_Uninstallation_msi]

  • [Sub_Uninstallation_msi]: Finally, this section utilizes the retrieved GUID for the uninstallation process.

If these techniques fall short or are partially successful, the next section discusses an alternative approach using an opsi-script script.

opsi-script Useful Commands for Uninstalling

When uninstalling a product that was installed using opsi-script functions or if a manufacturer’s uninstall routine isn’t available, creating a custom uninstall script is a viable solution.

opsi-script provides a variety of functions to aid in creating an effective uninstallation process. A comprehensive explanation of these functions and their parameters can be found in the opsi-script Reference.

For basic scenarios, you can use a Files section to remove specific files with the following command:

delete -f <file>

To delete a directory with subdirectories, use this command:

delete -sf <directory>\

The parameter f indicates a forced deletion of the file, even if it is write-protected. The s parameter includes subdirectories and operates recursively.

Use the /AllNTUserProfiles parameter if you need to delete a file or directory from all user profiles.

When you need to remove a directory tree containing files marked as "hidden" or as "system files", consider using the rmdir command. This can be executed via a ShellScript section:

[ShellScript_deleteDir]
rmdir /S /Q "<directory>"

Sometimes a running process must be terminated before deletion. In this case, find out the name (e.g. via the task manager) and pass it to the opsi-script command KillTask:

KillTask "thunderbird.exe"

If a product (or parts of it) operates as a service, you need to stop this service before uninstallation. You can deactivate the service in the registry and restart the computer, or use the system command net with the stop parameter. This stops the service instantly, deleting the associated files without a restart:

net stop <service>
Extra caution is necessary when removing .dll files that may still be in use by other programs. These files need to be dealt with on a case-by-case basis, and unfortunately, we can’t offer universal guidance for this situation.

To remove specific entries from the registry using opsi-script, use the DeleteVar command. This command is placed within a Registry section of an opsi-script and it removes entries from the currently open key:

DeleteVar <VarName>

To delete a registry key with all subkeys and registry variables, you can use the command DeleteKey:

DeleteKey [HKLM\Software\Macromedia]

64 Bit Support

opsi-script is a 32 bit application. Scripts designed for installing 32 bit software typically function properly on 64 bit systems as well. However, when it comes to installing 64 bit software using opsi-script or working with 64 bit systems in general, please consult the chapter 64 Bit Support.