I was asked to write a WiX Toolset MSI installer for a piece of software (let's call it Z from now on).
Z was developed atop of ASP.NET Web API Core 6.0 and it basically exchanges data between two machines (let's call them C and S).
My task is to install Z on C.
For testing purposes, the team and I tried installing Z on our local laptops running Windows 10. This worked like a charm.
One member, however, didn't have a Windows box (let's call it M), so he was using a remote machine running Windows Server 2012 (let's call it W) to install the MSI package.
After two or three weeks of distress between M's owner and the team, we decided to connect to a spare server running Windows Server 2016 from one Windows laptop, and tried installing Z there.
We've finally agreed upon M's complaints.
The MSI install fails when done via RDP (aka Terminal Service or mstsc /admin).
This is the ProductComponents.wxs, where we instruct Z how the Windows Service is deployed.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<!-- Customizable component group -->
<ComponentGroup Id="ProductComponents" Directory="APPLICATIONFOLDER">
<ComponentRef Id="WindowsServiceComponent" />
<ComponentRef Id="RemoveFolderComponent" />
</ComponentGroup>
<!-- Removal of the install folder when uninstalling the product -->
<!-- and (un)installation of Z as a Windows Service -->
<DirectoryRef Id="APPLICATIONFOLDER">
<!-- Removal of the folder -->
<Component Id="RemoveFolderComponent" Guid="{snipped}">
<RemoveFolder Id="RemoveInstallFolder" Directory="APPLICATIONFOLDER" On="uninstall" />
</Component>
<!-- (Un)installation of Z's Windows Service -->
<Component Id="WindowsServiceComponent" Guid="{snipped}">
<File Id="fil87B519F6CA084815922D1FED42E5B4AD" Source="$(var.PublishDir)\Z.exe" KeyPath="yes" Vital="yes" />
<ServiceInstall Id="WindowsServiceInstall" Name="Z" DisplayName="!(loc.ProductName_$(var.Platform))" Description="!(loc.WindowsServiceDescription)" Start="auto" Type="ownProcess"
ErrorControl="normal" />
<ServiceControl Id="StartService" Name="Z" Start="install" Stop="both" Remove="uninstall" Wait="yes" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>
And this is our Product.wxs, where we tell WiX about Z itself:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<!-- Fixed upgrade ID (do *NOT* change it) -->
<?define UpgradeCode = "{someguid}"?>
<!-- Declare Z -->
<Product Id="*" Name="!(loc.ProductName_$(var.Platform))" Language="!(loc.Language)" Version="$(var.BuildVersion)"
Manufacturer="!(loc.CompanyName)" UpgradeCode="$(var.UpgradeCode)">
<!-- Provide package details -->
<Package Compressed="yes" InstallScope="perMachine"
Platform="$(var.Platform)"
Manufacturer="!(loc.CompanyName)"
Description="!(loc.PackageDescription)"
Keywords="!(loc.PackageKeywords)"
Comments="!(loc.PackageComments)"
InstallPrivileges="elevated" />
<!-- Upgrade -->
<Property Id="PREVIOUSVERSIONSINSTALLED" Value="0" />
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="1.0.0.0" Maximum="$(var.BuildVersion)" Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
<MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeErrorMessage)" AllowDowngrades="no"
AllowSameVersionUpgrades="yes" IgnoreRemoveFailure="no" Schedule="afterInstallInitialize" />
<!-- Include .cab file into the .msi file -->
<MediaTemplate EmbedCab="yes" />
<!-- Use the icon.ico icon for this installer (shows up in Add/Remove Programs) -->
<Icon Id="MyBeautifulIcon" SourceFile="Assets\icon.ico" />
<Property Id="ARPPRODUCTICON" Value="MyBeautifulIcon" />
<!-- Help/Support website (shows in the Add/Remove Programs) -->
<Property Id="ARPURLINFOABOUT">http://www.z-enterprise.co.jp/</Property>
<!-- Disable Change/Repair buttons -->
<Property Id="ARPNOREPAIR" Value="yes" Secure="yes" />
<Property Id="ARPNOMODIFY" Value="yes" Secure="yes" />
<!-- Define components (files, shortcuts, Windows Services, etc.) -->
<Feature Id="RootFeature" Title="Z" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="AutoGeneratedComponents" />
</Feature>
<UIRef Id="InstallerUI"/>
<!-- Custom actions and their order of execution
See more at https://learn.microsoft.com/en-us/windows/win32/msi/standard-actions-reference -->
<InstallUISequence>
<Custom Action="ReadSettingsAction" After="CostFinalize" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="CheckSettingsAction" After="InstallInitialize" />
<Custom Action="SetPropertyAction" After="CheckSettingsAction" />
<!-- The condition NOT REMOVE below skips the custom action during uninstall -->
<Custom Action="SaveSettingsAction" Before="InstallServices"><![CDATA[NOT REMOVE]]></Custom>
</InstallExecuteSequence>
<!-- Enable verbose log mode for the installer. Logs are saved at %temp%\MSI{random chars}.LOG. -->
<Property Id="MsiLogging" Value="v" />
</Product>
</Wix>
The Windows user that is being employed to run the MSI installer is a local Administrator.
This user is able to install the Windows Service, but not to start it.
The MSI log file from an offending execution of Z is shown below,
MSI (s) (04:F8) [07:59:44:887]: Created Custom Action Server with PID 6620 (0x19DC).
MSI (s) (04:5C) [07:59:44:887]: Executing op: ActionStart(Name=StartServices,Description=Starting services,Template=Service: [1])
MSI (s) (04:5C) [07:59:44:887]: Executing op: ProgressTotal(Total=1,Type=1,ByteEquivalent=1300000)
MSI (s) (04:5C) [07:59:44:887]: Executing op: ServiceControl(,Name=Z,Action=1,Wait=1,)
MSI (s) (04:4C) [07:59:44:902]: Running as a service.
MSI (s) (04:4C) [07:59:44:902]: Hello, I'm your 64bit Elevated Non-remapped custom action server.
SFXCA: Extracting custom action to temporary directory: C:\Windows\Installer\MSIBE30.tmp-\
SFXCA: Binding to CLR version v4.0.30319
Calling custom action Z.CustomActions!Z.CustomActions.CustomActions.SaveSettings
Begin SaveSettings().
SaveSettings() has finished.
1: SaveSettingsAction 2: 0
MSI (s) (04:5C) [08:00:15:014]: Note: 1: 2205 2: 3: Error
MSI (s) (04:5C) [08:00:15:014]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1920
MSI (s) (04:94) [08:00:30:142]: I/O on thread 1524 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 6288 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 7668 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 1356 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 8044 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 8284 could not be cancelled. Error: 1168
MSI (s) (04:94) [08:00:30:142]: I/O on thread 4088 could not be cancelled. Error: 1168
MSI (s) (04:5C) [08:00:30:142]: Note: 1: 2205 2: 3: Error
MSI (s) (04:5C) [08:00:30:142]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709
MSI (s) (04:5C) [08:00:30:142]: Product: Z (64-bit) -- Error 1920. Service 'Z (64-bit)' (Z) failed to start. Verify that you have sufficient privileges to start system services.
For some reason, these 1168 errors were concerning me. I thought it might be the case that Z was trying to call the .NET Runtime. Then one of my attempts was to install the ASP.NET Core Runtime 6.0, like shown below.
Account
attribute for the <ServiceInstall>
tag?I tried the following:
mstsc /admin
or the equivalent for the platformto no avail.
Not exactly an answer but a good process to diagnose these failures is to:
net start <name>
) or services.msc to start the serviceNot clear why TS would introduce problems, but the above should help you isolate the service start issue. 99.999% of the time, there is a problem with the service code.