Use Nuget with WiX Project to create Windows Installer package (.msi)

WiX is one of the widely used tool to create a new Windows Installer package (.msi) file. The WiX Visual Studio package provides Visual Studio project templates for you to create a fully functional Windows Installer package easily. However, it expect you to have the WiX Toolset build tools installed to build the project. It may be strait forward to install it in your local development environment. However, it maybe hard when you need to do it with CI/CD pipelines. Though the Microsoft hosted agents comes with Wix Toolset installed it requires you to find the correct path etc.. and if you use the self-hosted build agents you need to install the Wix Toolset on those agents.

Another way to achieve this is by using the Wix nuget package. The out of the box WiX template has "EnsureWixToolsetInstalled" as InitialTargets. What we need to do is add a packages.config with WiX Nuget and update the template to ensure Nuget imports succeeded.

packages.config file is simple as below.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="GitVersion.MsBuild" version="5.10.1" developmentDependency="true" />
  <package id="WiX" version="3.11.2" />
</packages>

And below are the updates in project file.

<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project=".\packages\WiX.3.11.2\build\wix.props" Condition="Exists('.\packages\WiX.3.11.2\build\wix.props')" />
  <Import Project=".\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.props" Condition="Exists('.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.props')" />
  <PropertyGroup>
	<!-- We use the toolset from NuGet, instead of requiring it to be installed. This silences an "error" that isn't really an error. -->
	<WixTargetsImported>true</WixTargetsImported>
	<NuGetPackageImportStamp>
	</NuGetPackageImportStamp>
  </PropertyGroup>


---------------------

  <ItemGroup>
	<Content Include="packages.config" />
  </ItemGroup>
  
  -------------------
  
  <Import Project=".\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.targets" Condition="Exists('.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.targets')" />
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
	<PropertyGroup>
		<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
	</PropertyGroup>
	<Error Condition="!Exists('.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.props')" Text="$([System.String]::Format('$(ErrorText)', '.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.props'))" />
	<Error Condition="!Exists('.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '.\packages\GitVersion.MsBuild.5.10.1\build\GitVersion.MsBuild.targets'))" />
	<Error Condition="!Exists('.\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '.\packages\WiX.3.11.2\build\wix.props'))" />
  </Target>

You can find the complete file in below github repo.

Now if you need to build this in the Azure devops build pipeline, all you need to do is add below two task for Nuget restore and build WiX project.

- task: NuGetCommand@2
      inputs:
        command: 'restore'
        restoreSolution: '**/packages.config'
        packagesDirectory: '../packages'
        feedsToUse: 'select'

    - task: MSBuild@1
      displayName: 'Wix Msi MSBuild'
      inputs:
        solution: '**/*.wixproj'
        configuration: $(BuildConfiguration)
        msbuildArguments: '/p:OutDir=$(Build.SourcesDirectory)/'

That's all! Now we can build this project anywhere without installing the WiX Toolset.