Spinner Software Home About
KB Contact

How to create MSI Custom Actions

Published: 2004 - Last update: 2004 (c) Nicolai Kjaer / Spinner Software B.V.

For more information, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/using_custom_actions.asp.

Creating the VBScript

First, let's create a very basic script and make sure you can run it. Create the following two files:

test.cmd:
@ECHO OFF
@ECHO Test.cmd:
@ECHO Running test.vbs
CScript //nologo test.vbs
@ECHO Test.vbs returned %ERRORLEVEL%
PAUSE
test.vbs:
WScript.Echo "This is my first vbs script"
WScript.Quit 1

Doubleclick on the test.cmd script you just created. This will run your script, and if all goes ok, the output should look like this:

Test.cmd:
Running test.vbs
This is my first vbs script
Test.vbs returned 1
Press any key to continue . . .

Make sure you can run test.cmd succesfully as described above before you continue.

Writing a registry key in Vbs

Now, let's create a script that writes something to the HKEY_LOCAL_MACHINE registry hive:

Test.vbs:
' Get the Shell object
Dim oShell
Set oShell = CreateObject("WScript.Shell")
If Not oShell Is Nothing Then
	' Write a string value to the registry
	oShell.RegWrite "HKLM\SOFTWARE\MyMSI\MyRegistryKey\MyString", "Enter value here", "REG_SZ"
	' Free object again
	Set oShell = Nothing
End If

If you wanted to write an integer value instead, you can replace RegWrite like this:

' Write a dword (unsigned integer) value to the registry
oShell.RegWrite "HKLM\SOFTWARE\MyMSI\MyRegistryKey\MyInteger", 1, "REG_DWORD"

For more information on the RegWrite and WScript.Shell object, please see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/wsmthregwrite.asp

If you wanted to run a program, replace RegWrite with a command line this:

' Run parameters: path\filename, ShowState (1 = normal), Wait for program to finish (True/False)
' Open Notepad and wait for the user to close it
oShell.Run "%WINDIR%\Notepad.exe " & WScript.ScriptFullName, 1, True

For more information on the WScript.Shell.Run method, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/wsmthrun.asp

Including the script in the MSI

Including a script as binary

Open your MSI file with Orca, and go to the Binary table. Create a new record:

Name: TestVbs
Data: drive:\path\test.vbs

The script you point to is then loaded into the record.

You need a custom action to call the script. Go to the CustomActions table and create a new record:

Action=RunTestVbs
Type=6
Source=TestVbs
Target=NULL (leave blank)

Type 6 specifies that it's a VbScript that can be found in the Binary table. The Source then points to the Name primary key in the Binary table.

Create a new record in the InstallExecuteSequence table:

Action=RunTestVbs
Condition=NOT Installed
Sequence=6500

The Sequence should be just before the InstallFinalize action (6600 if using default sequencing).

The result: during installation, the RunTestVbs custom action is called as specified by the sequencing, and if the Condition is met (not evaluated to FALSE). The RunTestVbs custom action points to a VBScript in the Binary Table, the record that matches the Name field to "TestVbs". The content of the Data field is then executed.

Tip: If you get an error, enable logging (add a /L*v "path\logfile.txt" parameter to your MSIExec statement). You can then see the precise VbScript error.

Tip: You cannot use the WScript object in scripts that are called by MSIExec. Make sure you haven't left a WScript.Quit statement in your scripts. Use the Session object to interact with the MSI Installer, for example to return error messages or update properties or the progress bar. For more information on the Session object, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/session_object.asp.

Including the script as a CustomAction text

Another method of doing this (if it's a short script) is to include the VBScript text directly in the custom action:

Create a new script file to hold you script source:

OpenNotepad.vbs:
' Get the Shell object
Dim oShell
Set oShell = CreateObject("WScript.Shell")
If Not oShell Is Nothing Then
	' Run Notepad
	oShell.Run "%WINDIR%\Notepad.exe", 1, False
	' Free object again
	Set oShell = Nothing
End If

This will simply start Notepad when called (run "cscript //nologo opennotepad.vbs" to test).

Now, create a new CustomAction record:

Action=OpenNotepad
Type=38 (VBScript text found in sequence table)
Source=NULL (blank)
Target=NULL (blank). The script actually goes here, but we'll update it in a second.

Now add it to the sequencing table ((InstallExecuteSequence):

Action=OpenNotepad
Condition=NOT Installed
Sequence=6501

Now you're ready to read the Opennotepad.vbs script into the CustomAction table. Copy the WiTextIn.vbs script from the ProgramFilesFolder\MSIntel.sdk\Samples\Scripts\ folder. This script will import a text file (such as a .vbs script :-) into an MSI database.

Run this command to import OpenNotepad.vbs into the MSI:

CScript WiTextIn.vbs mymsi.msi CustomAction OpenNotepad Target OpenNotepad.vbs

This will update the CustomAction record with a primary key ("Action") value of OpenNotepad in the mymsi.msi file ; the Target field is updated to contain the content of OpenNotepad.vbs. Voila, you have your script.

Test the MSI. It should now write the registry value(s) and start notepad during installation.

(c) 2004 Nicolai Kjaer, Spinner Software B.V.