PSMSI PowerShell Module

repository·main·Indexed 42 days ago

https://github.com/ironmansoftware/psmsi

A PowerShell module that simplifies the creation of MSI installers by wrapping the WiX Toolset v3. It provides a native PowerShell DSL to define directory structures, files, features, and custom actions, generating WiX XML files and compiling them into final .msi packages.

Tokens
2.9K
Snippets
10
Records
11
Agent score
5%

What's inside PSMSI

  1. Manage installer versions and UpgradeCodes

    main

    To support seamless upgrades, you must keep the -UpgradeCode constant across different versions of the same product. You can then increment the -Version parameter (which defaults to 1.0) to signal a new version to the installer.

    New-Installer -ProductName "My First Product" -UpgradeCode '1a73a1be-50e6-4e92-af03-586f4a9d9e82' -Content { ... } -OutputDirectory (Join-Path $PSScriptRoot "output") -Version 2.0
  2. How PSMSI works with WiX Toolset

    main
    PSMSI is a wrapper around the WiX Toolset v3. It functions by generating WiX XML files and then executing the WiX tools to compile those files into final .msi packages. Because it relies on WiX, many advanced features can be implemented by leveraging WiX capabilities.
  3. Define Directories and Files

    main

    The installer structure is built using a nested hierarchy within the -Content block of New-Installer.

    Pre-defined Directories

    Use New-InstallerDirectory -PredefinedDirectory <Name> to select standard MSI root folders. Common values include:

    • LocalAppDataFolder
    • ProgramFilesFolder
    • DesktopFolder
    • AppData (and others provided by MSI)

    Custom Folders

    Create nested folders using New-InstallerDirectory -DirectoryName <Name>.

    • To allow users to choose a custom installation path, add the -Configurable switch.

    Files

    Include files using New-InstallerFile -Source <Path>. The file's position in the New-InstallerDirectory tree determines its installation path.

    New-InstallerDirectory -PredefinedDirectory "LocalAppDataFolder" -Content {
        New-InstallerDirectory -DirectoryName "My App" -Configurable -Content {
            New-InstallerFile -Source .	extbackslash{}app.exe
        }
    }
  4. Create your first installer with New-Installer

    main

    The New-Installer cmdlet is the primary entry point for generating an installer. It requires a -ProductName and a unique -UpgradeCode (a GUID). You define the file and directory structure within the -Content script block. The resulting output includes a .wxs file, a .wxsobj file, and the final .msi file.

    New-Installer -ProductName "My First Product" -UpgradeCode '1a73a1be-50e6-4e92-af03-586f4a9d9e82' -Content {
        New-InstallerDirectory -PredefinedDirectory "LocalAppDataFolder"  -Content {
           New-InstallerDirectory -DirectoryName "My First Product" -Content {
              New-InstallerFile -Source .	extbackslash{}license.txt
           }
        }
     } -OutputDirectory (Join-Path $PSScriptRoot "output")
  5. Set the Add/Remove Programs icon

    main

    You can specify the icon displayed in the Windows Add/Remove Programs list using the -AddRemoveProgramsIcon parameter on New-Installer.

    New-Installer -ProductName "My First Product" -UpgradeCode '1a73a1be-50e6-4e92-af03-586f4a9d9e82' -Content {
        New-InstallerDirectory -PredefinedDirectory "ProgramFilesFolder"  -Content {
           New-InstallerDirectory -DirectoryName "My First Product" -Content {
              New-InstallerFile -Source .	extbackslash{}license.txt
           }
        }
     } -OutputDirectory (Join-Path $PSScriptRoot "output") -AddRemoveProgramsIcon "icon.ico"
  6. Create Shortcuts and set Working Directories

    main

    Shortcuts are created using New-InstallerShortcut. You must reference a file's ID using the -FileId parameter.

    To set the Working Directory for a shortcut, use the -WorkingDirectoryId parameter and provide the -Id of the folder where the application resides.

    New-Installer -ProductName "MyImage" -UpgradeCode (New-Guid) -Content {
        New-InstallerDirectory -PredefinedDirectoryName ProgramFilesFolder -Content {
            New-InstallerDirectory -DirectoryName 'MyDir' -Id 'MyDir' -Content {
                New-InstallerFile -Id 'Image' -Source 'services.png'
            }
        }
        New-InstallerDirectory -PredefinedDirectoryName DesktopFolder -Content {
            New-InstallerShortcut -Name 'Test' -FileId 'Image' -WorkingDirectoryId 'MyDir'
        }    
    } -OutputDirectory .	extbackslash{}installer -RequiresElevation
  7. Configure All Users (Per-Machine) installation

    main

    By default, installers are PerUser. To create a PerMachine installation that requires administrative privileges (e.g., installing to ProgramFilesFolder), use the -RequiresElevation parameter on the New-Installer cmdlet.

    New-Installer -ProductName "My First Product" -UpgradeCode '1a73a1be-50e6-4e92-af03-586f4a9d9e82' -Content {
        New-InstallerDirectory -PredefinedDirectory "ProgramFilesFolder"  -Content {
           New-InstallerDirectory -DirectoryName "My First Product" -Content {
              New-InstallerFile -Source .	extbackslash{}license.txt
           }
        }
     } -OutputDirectory (Join-Path $PSScriptRoot "output") -RequiresElevation
  8. Customize the installer user interface

    main

    You can customize the visual appearance of your installer by creating a user interface object with New-InstallerUserInterface and passing it to the UserInterface parameter of the New-Installer command. This allows you to include custom graphics and an End User License Agreement (EULA).

    $UserInterface = New-InstallerUserInterface -Eula (Join-Path $PSScriptRoot 'eula.rtf') -TopBanner (Join-Path $PSScriptRoot "banner.png") -Welcome (Join-Path $PSScriptRoot "welcome.png")
  9. Use Features to group installation options

    main

    Features allow you to group files, folders, or shortcuts into selectable components. When features are used, PSMSI defaults to the WiX feature tree UI, allowing users to choose what to install.

    Feature States (-DefaultState):

    • Install: Installed by default.
    • Absent: Not selected by default, but available for user selection.
    • CompleteOnly: Installed only during a 'Complete' installation.
    • Disabled: Prevents the feature from being installed.

    Assigning Content to Features: You can wrap content in New-InstallerFeature or assign an existing item to a feature using the -Feature parameter on the item (e.g., on a shortcut).

    New-Installer -ProductName "My Product" -UpgradeCode 'GUID' -Content {
        New-InstallerDirectory -PredefinedDirectory "ProgramFilesFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Id "INSTALLFOLDER" -Content {
                # A required feature
                New-InstallerFeature -Id "Core" -Title "Core application" -Required -Content {
                    New-InstallerFile -Source .	extbackslash{}app.exe -Id "AppExe"
                }
    
                # An optional feature
                New-InstallerFeature -Id "Samples" -Title "Sample files" -DefaultState Absent -Content {
                    New-InstallerDirectory -DirectoryName "Samples" -Content {
                        New-InstallerFile -Source .	extbackslash{}sample.ps1
                    }
                }
            }
        }
    }
  10. Use Custom Actions to run PowerShell scripts

    main

    Custom actions allow you to execute PowerShell scripts during the installation or uninstallation process.

    Workflow:

    1. Include the .ps1 file in your installer using New-InstallerFile and assign it a unique -Id (e.g., -Id 'CustomAction').
    2. Define the action using New-InstallerCustomAction by referencing the -FileId.
    3. Important: Custom actions must be passed to New-Installer via the -CustomAction parameter as an array, not inside the -Content block.

    Parameters:

    • -RunOnInstall: Executes the script during installation.
    • -RunOnUninstall: Executes the script during uninstallation.
    • -Arguments: Arguments passed to PowerShell.exe (e.g., -NoProfile).
    • -ScriptArguments: Arguments passed directly to your script.
    • -CheckReturnValue: If set, a non-zero exit code from PowerShell will cause the installation to fail.
    # 1. Include the file with an ID
    New-InstallerFile -Source .	extbackslash{}myCustomAction.ps1 -Id 'CustomAction'
    
    # 2. Define the action (Note: This is passed to New-Installer -CustomAction, not in -Content)
    New-InstallerCustomAction -FileId 'CustomAction' -RunOnInstall