Msi registry

From wikinotes

NOTE:

Do not use this table to modify environment variables (you will receive an error about insufficient privileges).

Instead, use the Environment table.

Documentation

Add/Change Registry
Registry table https://docs.microsoft.com/en-us/windows/win32/msi/registry-table
WriteRegistryValues table https://docs.microsoft.com/en-us/windows/win32/msi/writeregistryvalues-action
Remove from Registry
RemoveRegistry table https://docs.microsoft.com/en-us/windows/win32/msi/removeregistry-table
RemoveRegistryValues table https://docs.microsoft.com/en-us/windows/win32/msi/removeregistryvalues-action
Sequence Tables
Sequence tables

Overview

Table Columns
Registry Foo primary-key used to uniquely identify the registry entry. (examples show a name like 'Foo')
Root -1 magic number indicating root (HKCU, HKLM, ...)
Key Software\GNU key being operated on
Name Foo, * Name of subkey, or magic-string indicating key-operation (create, delete, ...).
Value Bar, #%Bar Value of subkey, with optional prefix indicating type.
Component_ ? The component-id this key belongs to.
Directory -> Component -> Registry

# before creating registry table entries, you will
# need to create a directory and a component.
# Directory
msidir = msilib.Directory(db,          # database
                          cab,         # cab
                          None,        # basedir
                          '.',         # physical
                          'TARGETDIR', # logical
                          'SourceDir') # default

# Component
comp_entry = collections.namedtuple('comp_entry', ('Component', 'ComponentId', 'Directory_', 'Attributes', 'Condition', 'KeyPath'))
component_data = [comp_entry(Component='Foo',
                             ComponentId=msilib.gen_uuid(),
                             Directory_='TARGETDIR',
                             Attributes=2,  # msidbComponentAttributesOptional
                             Condition=None,
                             KeyPath='Foo_reg')]
msilib.add_data(db, 'Component', component_data)

# Registry Modification
reg_entry = collections.namedtuple('reg_entry', ('Registry', 'Root', 'Key', 'Name', 'Value', 'Component_'))
reg_data = [reg_entry(Registry='Foo_reg',
                      Root=2,  # HKCU
                      Key='Environment',  # HKCU\Environment
                      Name='Foo',
                      Value='Bar',
                      Component_='Foo')]
msilib.add_data(db, 'Registry', reg_data)

# Add Modification to Sequence


# Commit Database Changes
db.Commit()

Key Root

This magic number indicates where the registry key is to be written.

-1 HKCU or HKLM depending on if user decides to install to system or user-account
2 HKCU (current user)
3 HKLM (local machine)

Add/Remove Keys

If value is not assigned, then name value is interpreted as a magic-string.

This is used to create/delete keys, or perform other special behaviour.

# delete a key (and all of it's subkeys)
delete_key = {'root': -1,
              'key': 'Software\Garbage',
              'name': '-'}

# key is created if does not exist, and deleted (with all subkeys)
# when the installer is uninstalled
installer_owned_key = {'root': -1,
                       'key': 'Software\InstallerOwned',
                       'name': '*'}

SubKey Types

values are assigned prefixes to indicate their type.

Keys are reg_sz by default.

Value Prefixes
REG_SZ
#% REG_EXPAND_SZ
# REG_DWORD
#x REG_BINARY
reg_sz = {'root': -1,
          'key': 'Environment',
          'name': 'Foo',
          'value': 'Bar'}

reg_expand_sz = {'root': -1,
                 'key': 'Environment',
                 'name': 'Foo',
                 'value': '#%%USERPROFILE%Bar'}  # '#%' prefix indicates reg_expand_sz (environment variables are expanded)

StringLists Append/Prepend

values can also be assigned prefixes that indicate their placement within an existing value.

# list of 3x strings 'a', 'b', and 'c'
value: 'a[~]b[~]c'

# append, removing duplicate existing entries
value: '[~]a[~]b'      # [~] before stringlist

# prepend, removing duplicate existing entries
value: 'a[~]b[~]'      # [~] after stringlist

# replace-all
value: 'a[~]b'         # no prefix/suffix of [~]
value: '[~]a[~]b[~]'   # prefix and suffix of [~]