PSMSI includes cmdlets for creating MSI packages that can contain any file and directory structure you wish. It also includes functionality to customize the installer interface by including custom EULAs and images.
To get started creating installers with PSMSI, you will need to download the latest version of the PSMSI module. This can be installed with Install-Module
.
Install-Module PSMSI
This module is based on v3 of the Wix Toolset. There is so much more we could accomplish with this module. It mainly creates WiX XML and runs the WiX tools to generate MSIs. We're very open to PRs and issues. Feel free to check out the WiX documentation for features that could be added.
The New-Installer
cmdlet is used to generate an installer. It can contain directories and files for installation. The first step is to define the basic parameters of your installer.
The Product and UpgradeCode parameters are required. The UpgradeCode is a GUID that needs to remain the same for each version of your product and should be unique from other products.
New-Installer -ProductName "My First Product" -UpgradeCode '1a73a1be-50e6-4e92-af03-586f4a9d9e82'
Within the Content parameter of the New-Installer cmdlet, you need to include a root directory for installation on the end user's machine. The root directory needs to be a predefined directory. One of the parameter sets on New-InstallerDirectory defines a PredefinedDirectory parameter that you can use to select the target root directory.
New-InstallerDirectory -PredefinedDirectory "LocalAppDataFolder"
You can now optionally specify a nested directory within your root directory. This will be created if it does not exist and removed on uninstall.
New-InstallerDirectory -DirectoryName "My First Product"
Finally, you can include files within your directory. The New-InstallerFile cmdlet accepts a Source parameter with the path to the file you would like to install.
New-InstallerFile -Source .\MyTextFile.txt
The full script for this installer looks like this.
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 .\license.txt
}
}
} -OutputDirectory (Join-Path $PSScriptRoot "output")
Running the above script will produce a WXS, WXSOBJ and MSI file in the output directory. The MSI is the only file that you need to provide to your end users. The WXS and WXSOBJ files are artifacts of the Windows Installer XML Toolkit used to generate these installers.
You can use the -RequiresElevation
parameter of New-Installer
to change from the default PerUser
installation to a PerMachine
installation.
The following creates an installer that will install to the program files folder.
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 .\license.txt
}
}
} -OutputDirectory (Join-Path $PSScriptRoot "output") -RequiresElevation
The Application Icon that will be displayed within Add\Remove Programs can be defined using the AddRemoveProgramsIcon
of New-Installer
.
New-Installer -Product "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 .\license.txt
}
}
} -OutputDirectory (Join-Path $PSScriptRoot "output") -AddRemoveProgramsIcon "icon.ico"
The UpgradeCode
value should be static to ensure that upgrades work successfully. Define the upgrade code by 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 .\license.txt
}
}
} -OutputDirectory (Join-Path $PSScriptRoot "output")
The installer version is set using the Version
parameter of New-Installer
. You can provide upgrades by increasing the version and keeping the Upgrade Code the same.
The version defaults to 1.0.
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 .\license.txt
}
}
} -OutputDirectory (Join-Path $PSScriptRoot "output") -Version 2.0
Custom actions allow you to run PowerShell scripts during install and uninstall. You will need to include the script as a file in your installer. Use the FileId
parameter of New-InstallerCustomAction
to reference the PS1 file you wish to execute.
For example, you may have a script named MyCustomAction.ps1
with an ID of CustomAction
.
New-InstallerFile -Source .\myCustomAction.ps1 -Id 'CustomAction'
You can then use that script as a custom action during an installation.
New-InstallerCustomAction -FileId 'CustomAction' -RunOnInstall
You can pass arguments to both PowerShell.exe and your script. The Arguments
parameter passes custom arguments to PowerShell.exe (like -NoProfile). The ScriptArguments
parameter defines arguments to pass to the script itself.
This checks the exit code of PowerShell.exe. If the exit code is non-zero, then it will cause the install to fail.
Runs the custom action during install.
Runs the custom action during uninstall.
You can create directories and files using New-InstallerDirectory
and New-InstallerFile
. Directories should start with one of the pre-defined directories provided by MSI.
Use the PredefinedDirectory
parameter of New-InstallerDirectory
to define the root folder for the installation. You can use directories such as Program Files
, AppData
and CommonAppData
.
Custom folders appear within pre-defined directories. You can nest folders to create a folder tree. Folders can then contain files. Use the DirectoryName
parameter of New-InstallerDirectory
to create a directory. Use Content
to specify either folders or files to include.
Including the Configurable
property on New-InstallerDirectory
will allow the end user to select a directory during installation.
New-InstallerDirectory -DirectoryName "My First Product" -Content {
New-InstallerFile -Source .\license.txt
} -Configurable
Files are defined by their current location and an ID. The Source
parameter should identify the file you wish to include. It's location in the New-InstallerDirectory
tree will define where it is installed on disk.
New-InstallerDirectory -DirectoryName "My First Product" -Content {
New-InstallerFile -Source .\license.txt
}
Shortcuts can be defined for installers using New-InstallerShortcut
. You will define where the shortcut is located using New-InstallerDirectory
and reference a file by Id.
For example, to define a file by ID, you would include the Id
parameter of New-InstallerFile
.
New-InstallerFile -Source .\MyTextFile.txt -Id "myTestFile"
Next, you would define the shortcut in a directory and reference the file by ID.
New-InstallerDirectory -PredefinedDirectory "DesktopFolder" -Content {
New-InstallerShortcut -Name "My Test File" -FileId "myTestFile"
}
You can set the working directory of a shortcut by specifying the ID of the folder. The below example sets the working directory to the installation directory's ID.
New-Installer -ProductName "MyImage" -UpgradeCode (New-Guid) -Version 1.0.0 -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 .\installer -RequiresElevation
You can customize the user interface of the installer by using the UserInterface
parameter of New-Installer
along with New-InstallerUserInterface
.
User interfaces can include custom graphics and EULAs for your installer.
$UserInterface = New-InstallerUserInterface -Eula (Join-Path $PSScriptRoot 'eula.rtf') -TopBanner (Join-Path $PSScriptRoot "banner.png") -Welcome (Join-Path $PSScriptRoot "welcome.png")
For more free tools, visit the Ironman Software free tools index.