internal/functions/wix/Invoke-PSMDWixBuild.txt

Function Invoke-PSMDWixBuild
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]
    [Cmdletbinding()]
    Param (
        [Parameter(Mandatory = $false, Position = 0)]
        [string]
        $Path = (Get-Location).Path,
         
        [Parameter(Mandatory = $false)]
        [string[]]
        $Exclude = @('.git', '.gitignore', '*.msi'),
         
        [Parameter(Mandatory = $false)]
        [string]
        $OutputFolder = (Get-Location).Path,
         
        [Parameter(Mandatory = $false)]
        [string]
        $LicenseFile = "$Path\license.rtf",
         
        [Parameter(Mandatory = $false)]
        [string]
        $IconFile = "$Path\icon.ico",
         
        [Parameter(Mandatory = $false)]
        [string]
        $BannerFile = "$Path\banner.bmp",
         
        [Parameter(Mandatory = $false)]
        [string]
        $DialogFile = "$Path\dialog.bmp",
         
        [Parameter(Mandatory = $false)]
        [string]
        $ProductShortName = (Get-PSMDWixConfig -ProductShortName -Path $Path).ProductShortName,
         
        [Parameter(Mandatory = $false)]
        [string]
        $ProductName = (Get-PSMDWixConfig -ProductName -Path $Path).ProductName,
         
        [Parameter(Mandatory = $false)]
        [string]
        $ProductVersion = (Get-PSMDWixConfig -ProductVersion -Path $Path).ProductVersion,
         
        [Parameter(Mandatory = $false)]
        [string]
        $Manufacturer = (Get-PSMDWixConfig -Manufacturer -Path $Path).Manufacturer,
         
        [Parameter(Mandatory = $false)]
        [string]
        $HelpLink = (Get-PSMDWixConfig -HelpLink -Path $Path).HelpLink,
         
        [Parameter(Mandatory = $false)]
        [string]
        $AboutLink = (Get-PSMDWixConfig -AboutLink -Path $Path).AboutLink,
         
        [Parameter(Mandatory = $false)]
        [string]
        $UpgradeCodeX86 = (Get-PSMDWixConfig -UpgradeCodeX86 -Path $Path).UpgradeCodeX86,
         
        [Parameter(Mandatory = $false)]
        [string]
        $UpgradeCodeX64 = (Get-PSMDWixConfig -UpgradeCodeX64 -Path $Path).UpgradeCodeX64,
         
        [Parameter(Mandatory = $false)]
        [int]
        $Increment = 3,
         
        [Parameter(Mandatory = $false)]
        [switch]
        $NoX86,
         
        [Parameter(Mandatory = $false)]
        [switch]
        $NoX64
    )
     
    #region Helper functions
    Function ConvertTo-WixNeutralString
    {
        [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseLiteralInitializerForHashtable", "")]
        [CmdletBinding()]
        Param (
            [string]
            $Text
        )
        $changes = New-Object System.Collections.Hashtable
        $changes.'ß' = 'ss'
        $changes.'Ä' = 'Ae'
        $changes.'ä' = 'ae'
        $changes.'Ü' = 'Ue'
        $changes.'ü' = 'ue'
        $changes.'Ö' = 'Oe'
        $changes.'ö' = 'oe'
        $changes.' ' = '_'
        $changes.'-' = '_'
        Foreach ($key in $changes.Keys)
        {
            $text = $text.Replace($key, $changes.$key)
        }
        $text
    }
     
    Function Copy-WixSourceFile
    {
        [Cmdletbinding()]
        Param (
            [Parameter(Mandatory = $true, Position = 0)]
            [string]
            $Source,
             
            [Parameter(Mandatory = $true, Position = 1)]
            [string]
            $Destination,
             
            [Parameter(Mandatory = $false)]
            [string[]]
            $Exclude
        )
        New-Item $Destination -ItemType directory -Force | Out-Null
        $objects = Get-ChildItem $Source -Force -Exclude $exclude
        foreach ($object in $objects)
        {
            if ($object.Attributes -contains 'Directory')
            {
                Copy-WixSourceFile $object.Fullname (Join-path $Destination $object.Name) -Exclude $Exclude
            }
            else
            {
                Copy-Item $object.FullName $Destination
            }
        }
    }
    #endregion Helper functions
     
    # Increment version number if requested
    If ($Increment -gt 0)
    {
        $versionArray = $ProductVersion.split(".")
        If ($Increment -gt $versionArray.length)
        {
            $extraDigits = $Increment - $versionArray.length
            for ($i = 0; $i -lt $extraDigits - 1; $i++)
            {
                $versionArray += "0"
            }
            $versionArray += "1"
        }
        else
        {
            $versionArray[$Increment - 1] = [string]([int]($versionArray[$Increment - 1]) + 1)
        }
        $NewProductVersion = $versionArray -Join "."
        Set-PSMDWixConfig -ProductVersion $NewProductVersion -Path $Path | Out-Null
    }
     
    # MSI IDs
    $productId = ConvertTo-WixNeutralString -Text $ProductShortName
     
    # Date and time
    $timeStamp = (Get-Date -format yyyyMMddHHmmss)
     
    # WiX paths
    If ((Get-ChildItem -Path 'C:\Program Files*\WiX*\' -Filter heat.exe -Recurse))
    {
        $wixDir = Split-Path ((((Get-ChildItem -Path 'C:\Program Files (x86)\WiX*\' -Filter heat.exe -Recurse) | Select-Object FullName)[0]).FullName)
    }
    Else
    {
        Throw "Please install WiX Toolset"
    }
     
    #$wixDir = Join-Path $libdir "wix"
    $heatExe = Join-Path $wixDir "heat.exe"
    $candleExe = Join-Path $wixDir "candle.exe"
    $lightExe = Join-Path $wixDir "light.exe"
     
    # Other paths
    $thisModuleName = ConvertTo-WixNeutralString -Text $MyInvocation.MyCommand.ModuleName
    $tmpDirGlobalRoot = Join-Path $Env:TMP $thisModuleName
    $tmpDirThisRoot = Join-Path $tmpDirGlobalRoot $productId
    $tmpDir = Join-Path $tmpDirThisRoot $timeStamp
     
     
    $varName = "var." + $productId
    $oldMsi = Join-Path $OutputFolder ($productID + '*' + ".msi")
    $cabFileName = $productId + ".msi"
     
    $moduleIconFile = Join-Path $PSScriptRoot "icon.ico"
    $moduleBannerFile = Join-Path $PSScriptRoot "banner.bmp"
    $moduleDialogFile = Join-Path $PSScriptRoot "dialog.bmp"
     
    $tmpIconFile = Join-Path $tmpDir "icon.ico"
    $tmpBannerFile = Join-Path $tmpDir "banner.bmp"
    $tmpDialogFile = Join-Path $tmpDir "dialog.bmp"
     
    # MSI IDs
    $productId = ConvertTo-WixNeutralString -Text $ProductShortName
     
    # Create tmp folder
    if (test-path $tmpDir)
    {
        Remove-Item $tmpDir -Recurse
    }
    New-Item $tmpDir -ItemType directory | Out-Null
     
    # Copy Files to tmp dir
    $tmpSourceDir = Join-Path $tmpDir "files"
    Copy-WixSourceFile $Path $tmpSourceDir -Exclude $Exclude
     
    # Add license
    if (test-path $LicenseFile)
    {
        $licenseCmd = @"
<WixVariable Id="WixUILicenseRtf" Value="$LicenseFile"></WixVariable>
"@
    }
    # Add icon
    if (test-path $IconFile)
    {
        Copy-Item $IconFile $tmpIconFile
    }
    elseif (test-path $moduleIconFile)
    {
        Copy-Item $moduleIconFile $tmpIconFile
    }
    if (test-path $tmpIconFile)
    {
        $iconCmd = @"
<Icon Id="icon.ico" SourceFile="$tmpIconFile"/>
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
"@
    }
    # Add banner graphic
    if (test-path $BannerFile)
    {
        Copy-Item $BannerFile $tmpBannerFile
    }
    elseif (test-path $moduleBannerFile)
    {
        Copy-Item $moduleBannerFile $tmpBannerFile
    }
    if (test-path $tmpBannerFile)
    {
        $bannerCmd = @"
<WixVariable Id="WixUIBannerBmp" Value="$tmpBannerFile"></WixVariable>
"@
    }
    # Add dialog graphic
    if (test-path $DialogFile)
    {
        Copy-Item $DialogFile $tmpDialogFile
    }
    elseif (test-path $moduleDialogFile)
    {
        Copy-Item $moduleDialogFile $tmpDialogFile
    }
    if (test-path $tmpDialogFile)
    {
        $dialogCmd = @"
<WixVariable Id="WixUIDialogBmp" Value="$tmpDialogFile"></WixVariable>
"@
    }
     
    # Platform settings
    $platforms = @()
     
    $x86Settings = @{
        'arch' = 'x86';
        'sysFolder' = 'SystemFolder';
        'progfolder' = 'ProgramFilesFolder';
        'upgradeCode' = $UpgradeCodeX86;
        'productName' = "${ProductName} (x86)";
        'outputMsi' = (Join-Path $OutputFolder ($productID + "_" + $ProductVersion + "_x86.msi"))
    }
    $x64Settings = @{
        'arch' = 'x64';
        'sysFolder' = 'System64Folder';
        'progfolder' = 'ProgramFiles64Folder';
        'upgradeCode' = $UpgradeCodeX64;
        'productName' = "${ProductName} (x64)";
        'outputMsi' = (Join-Path $OutputFolder ($productID + "_" + $ProductVersion + "_x64.msi"))
    }
     
    If (!$Nox86)
    {
        $platforms += $x86Settings
    }
    If (!$Nox64)
    {
        $platforms += $x64Settings
    }
     
    # Remove existing MSIs
    # Remove-Item $oldMsi
     
    # Do the build
    foreach ($platform in $platforms)
    {
        $platformArch = $platform.arch
        $platformUpgradeCode = $platform.upgradeCode
        $platformSysFolder = $platform.sysFolder
        $platformProgFolder = $platform.progFolder
        $platformProductName = $platform.productName
         
         
        $modulesWxs = Join-Path $tmpDir "_modules${platformArch}.wxs"
        $productWxs = Join-Path $tmpDir ".wxs${platformArch}"
        $modulesWixobj = Join-Path $tmpDir "_modules${platformArch}.wixobj"
        $productWixobj = Join-Path $tmpDir ".wixobj${platformArch}"
        $productPdb = Join-Path $tmpDir ($productID + ".wizpdb${platformArch}")
         
        # Build XML
        $wixXml = [xml] @"
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
  <Product Id="*" Language="1033" Name="$platformProductName" Version="$ProductVersion"
           Manufacturer="$Manufacturer" UpgradeCode="$platformUpgradeCode" >
 
    <Package Id="*" Description="$platformProductName Installer"
             InstallPrivileges="elevated" Comments="$ProductShortName Installer"
             InstallerVersion="200" Compressed="yes" Platform="$platformArch">
    </Package>
    $iconCmd
    <Upgrade Id="$platformUpgradeCode">
      <!-- Detect any newer version of this product -->
      <UpgradeVersion Minimum="$ProductVersion" IncludeMinimum="no" OnlyDetect="yes"
                      Language="1033" Property="NEWPRODUCTFOUND" />
 
      <!-- Detect and remove any older version of this product -->
      <UpgradeVersion Maximum="$ProductVersion" IncludeMaximum="yes" OnlyDetect="no"
                      Language="1033" Property="OLDPRODUCTFOUND" />
    </Upgrade>
 
    <!-- Define a custom action -->
    <CustomAction Id="PreventDowngrading"
                  Error="Newer version already installed." />
 
    <InstallExecuteSequence>
      <!-- Prevent downgrading -->
      <Custom Action="PreventDowngrading" After="FindRelatedProducts">
        NEWPRODUCTFOUND
      </Custom>
      <RemoveExistingProducts After="InstallFinalize" />
    </InstallExecuteSequence>
 
    <InstallUISequence>
      <!-- Prevent downgrading -->
      <Custom Action="PreventDowngrading" After="FindRelatedProducts">
        NEWPRODUCTFOUND
      </Custom>
    </InstallUISequence>
 
    <Media Id="1" Cabinet="$cabFileName" EmbedCab="yes"></Media>
    $licenseCmd
    $bannerCmd
    $dialogCmd
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$platformProgFolder" Name="$platformProgFolder">
        <Directory Id="WindowsPowerShell" Name="WindowsPowerShell">
          <Directory Id="INSTALLDIR" Name="Modules">
            <Directory Id="$ProductId" Name="$ProductShortName">
              <Directory Id="VERSIONDIR" Name="$ProductVersion">
              </Directory>
            </Directory>
          </Directory>
        </Directory>
      </Directory>
    </Directory>
    <Property Id="ARPHELPLINK" Value="$HelpLink"></Property>
    <Property Id="ARPURLINFOABOUT" Value="$AboutLink"></Property>
    <Feature Id="$ProductId" Title="$ProductShortName" Level="1"
             ConfigurableDirectory="INSTALLDIR">
      <ComponentGroupRef Id="VERSIONDIR">
      </ComponentGroupRef>
    </Feature>
    <UI></UI>
    <UIRef Id="WixUI_InstallDir"></UIRef>
    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"></Property>
  </Product>
</Wix>
"@
         
        # Save XML and create productWxs
        $wixXml.Save($modulesWxs)
        & $heatExe dir $tmpSourceDir -nologo -sfrag -sw5151 -suid -ag -srd -dir $productId -out $productWxs -cg VERSIONDIR -dr VERSIONDIR | Out-Null
         
        # Produce wixobj files
        & $candleexe $modulesWxs -out $modulesWixobj | Out-Null
        & $candleexe $productWxs -out $productWixobj | Out-Null
    }
    foreach ($platform in $platforms)
    {
        $platformArch = $platform.arch
        $modulesWixobj = Join-Path $tmpDir "_modules${platformArch}.wixobj"
        $productWixobj = Join-Path $tmpDir ".wixobj${platformArch}"
        $platformOutputMsi = $platform.outputMsi
         
        # Produce the MSI file
        & $lightexe -sw1076 -spdb -ext WixUIExtension -out $platformOutputMsi $modulesWixobj $productWixobj -b $tmpSourceDir -sice:ICE91 -sice:ICE69 -sice:ICE38 -sice:ICE57 -sice:ICE64 -sice:ICE204 -sice:ICE80 | Out-Null
         
    }
    # Remove tmp dir
    Remove-Item $tmpDir -Recurse
}