Catalin
Posts: 6739
Joined: Wed Jun 13, 2018 7:49 am

Read values from INI file using Custom Actions

Hello guys,

Today I am going to show you how to read values from an INI file using a Custom Action (in our case, a PowerShell script).

Scenario: read the values from an INI file installed by your setup and display those values in a custom dialog.

License required: Enterprise or above.

Quite related article: How to use .INI files parameters to start a service (Second scenario)

First of all, let's consider the following INI file:

Code: Select all

; Sample INI file created by Catalin

[About]

Name=Catalin
Age=25

[SecondSection]

SomeKey=SomeValue
You can download the INI file from below:
sampleINI.ini
(111 Bytes) Downloaded 3164 times

Now, here is how we are going to approach this.

First of all, we will need to add the .INI file as a Temporary File. The reason for this is that we need it to be available during the Dialogs Stage (in order to display the values we retrieve). Otherwise, if we add it as a normal file, it will be installed during the "Add resources" action group (under "Install Execution Stage"), which is long after the dialogs are displayed.

Now, let's move on to developing the Custom Action. At first, I thought this is going to be an easy task but it turned out it wasn't that easy, as PowerShell does not have any predefined cmdlets to work with INI files (although it has to work with CSV/XML files, for instance).

With that being said, we need to create our own function that will read the INI file.

The custom action should look something as it follows:

Code: Select all

#Requires -version 3
Param()

# adding the assembly so we can use the MessageBox class - debug purposes
Add-Type -AssemblyName PresentationFramework

function Get-IniFile 
{  
    param(  
        [parameter(Mandatory = $true)] [string] $filePath  
    )  
    
    $anonymous = "NoSection"
  
    $ini = @{}  
    switch -regex -file $filePath  
    {  
        "^\[(.+)\]$" # Section  
        {  
            $section = $matches[1]  
            $ini[$section] = @{}  
            $CommentCount = 0  
        }   

        "(.+?)\s*=\s*(.*)" # Key  
        {  
            if (!($section))  
            {  
                $section = $anonymous  
                $ini[$section] = @{}  
            }  
            $name,$value = $matches[1..2]  
            $ini[$section][$name] = $value  
        }  
    }  

    return $ini  
}  

# get the path to the TempFolder, where our INI file was added
$tempFolder = AI_GetMsiProperty TempFolder

# as the path to the .INI file is %temp%\NameOfTheIniFile.ini, we join the paths to create the full path to our INI file
$pathToIni = Join-Path -Path $tempFolder -ChildPath "sampleINI.ini"

[System.Windows.MessageBox]::Show("Path to the INI file is: $pathToIni")

# get the content of the INI file in a variable

$sampleINI = Get-IniFile -filePath $pathToIni

# get the value of each element we need and store it in an installer property so we can further
# display it on our custom dialog

AI_SetMsiProperty NAME $sampleINI.About.Name

AI_SetMsiProperty AGE $sampleINI.About.Age

AI_SetMsiProperty SOME_KEY $sampleINI.SomeSection.SomeKey
I have tried to comment as much as possible, so everything is as clear as possible.

As we can see, in order to identify the elements of the INI file, I have used a RegEx.

First of all, the main elements of an INI file are:

- a comment (the line starts with a ";" character) --> as it can be seen in the script, I have totally ignored this so the script does not get larger

- a section, e.g.: [About]

- key=value pairs, e.g.: Name=Catalin

Now, right after each RegEx I have commented what it is used for. I will do my best to explain how that works:

"^\[(.+)\]$" # Section

  • quote character (") ==> Matches a "" character
  • ^ ==> Matches the beginning of the string
  • \[ ==> Matches the "[" character which is how a section starts
  • . ==> Matches any character except line break
  • + ==> Matches 1 or more of the preceding tokens
  • \] ==> Matches the "]" character
  • $ ==> Matches the end of the string

Hope this explanation helps a bit to get a grip of what is happening.

Now, as previously mentioned, we can add this Custom Action as a "Run Inline PowerShell script".

This Custom Action should be added as a "custom action without sequence" (so we can schedule it on a dialog control).
RunScript.png
RunScript.png (27.77 KiB) Viewed 353413 times

We will schedule this right before we spawn our custom dialog (i.e. on the "Next" button of the previous dialog).

And this should pretty much be it.

For your reference, please find below a sample project that implements all of the above:

Hope this helps! :)

Best regards,
Catalin
Catalin Gheorghe - Advanced Installer Team
Follow us: Twitter - Facebook - YouTube

Return to “Sample Projects”