I am trying to create a WIX installer that will install a Windows Service. For the Windows service, I create a service exactly how it's outlined http://tech.pro/tutorial/895/creating-a-simple-windows-service-in-csharp.
In my wxs installer file, I have the following markup specified -
<Component Id="MyCompanyWindowsServiceComponent" Guid="*">
<File Id="MyCompanyWindowsServiceFile" Name="SimpleWindowsService.exe" DiskId="1"
Source="..\SimpleWindowsService\bin\debug\SimpleWindowsService.exe"/>
<ServiceInstall Id="MyCompanyServiceInstall" Type="ownProcess" Vital="yes"
Name="MyCompany:MyProduct"
DisplayName="MyCompany:MyProduct"
Description="MyCompany Windows Service"
Start="auto"
Account="LocalSystem"
ErrorControl="critical"
Interactive="yes"/>
<ServiceControl Id="StartService"
Start="install"
Stop="both"
Remove="uninstall"
Name="MyCompany:MyProduct"
Wait="no"/>
</Component>
and I have the component referenced like -
<Feature Id="Complete" Level="1">
::
<ComponentRef Id="MyCompanyWindowsServiceComponent"/>
</Feature>
When I finally run my installer, I see the file has been copied to the right location but the service itself hasn't been started.
What am I missing?
Regards
Related
I use wix toolset to install an ASP.NET Core application as a windows service. When doing a major upgrade, the installer can take very long (5 mins) while it usually is a couple of seconds. This is because the InstallValidate action gives errors because files are in use by the service, I noticed that if I stop the service before starting the installer, it always runs smoothly. I use the following code to install and start/stop the service: (this is generated using heat)
<Component Id="ApiEndpoint.exe" Guid="*">
<File Id="ApiEndpoint.exe" KeyPath="yes" Source="$(var.publishDir)\ApiEndpoint.exe" />
<wix:ServiceInstall Id="ApiEndpointInstall" DisplayName="ApiEndpoint" Name="ApiEndpoint" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<util:ServiceConfig RestartServiceDelayInSeconds="60" ResetPeriodInDay="1" FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="restart" />
</wix:ServiceInstall>
<wix:ServiceControl Id="ApiEndpointControl" Name="ApiEndpoint" Start="install" Stop="both" Remove="uninstall" xmlns:wix="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" />
</Component>
Shouldn't the files in use by the ApiEndpoint be excluded because the service will be stopped anyway? Is there a way I can stop the service before the InstallValidate, I tried this with a custom action, but this wasn't possible because no admin privileges are present at that point.
I also tried to ignore the exe file from heat and make a component for it myself, like below, this results in the same issue.
<Fragment xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<ComponentGroup Id="ExeComponents" Directory="INSTALLFOLDER">
<Component Win64="yes" Id="ExeComponent" Guid="*">
<File Id="ExecFile" Source="$(exeSource)" KeyPath="yes" />
<ServiceInstall Id="ApiEndpointInstall" DisplayName="ApiEndpoint" Name="ApiEndpoint" ErrorControl="normal" Start="auto" Type="ownProcess" Vital="yes">
<util:ServiceConfig RestartServiceDelayInSeconds='60' ResetPeriodInDays='1' FirstFailureActionType='restart' SecondFailureActionType='restart' ThirdFailureActionType='restart' />
<util:PermissionEx
User="Everyone"
GenericAll="yes"
ServiceChangeConfig="yes"
ServiceEnumerateDependents="yes"
ChangePermission="yes"
ServiceInterrogate="yes"
ServicePauseContinue="yes"
ServiceQueryConfig="yes"
ServiceQueryStatus="yes"
ServiceStart="yes"
ServiceStop="yes" />
</ServiceInstall>
<ServiceControl Id="ApiEndpointControl" Name="ApiEndpoint" Start="install" Stop="both" Remove="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
I'm very new at wix so I'm not sure if I'm missing something obvious or if this is just a limit of Wix.
I can see that the service stops eventually when the files are being copied, but it just seems like it is stopped either too late, or the installer should ignore the files in use by the service that will be stopped anyway.
I'm using WiX 3.1.1 to install an exe and a service. Sometimes, the MSI install fails with a fairly generic error:
Error 1923. Service 'MyService' (MyService) could not be installed.
Verify that you have sufficient privileges to install system services.
Experimentally, this appears to be because the service already exists, and my xml uses Vital="yes"
I would like to have the MSI ensure the service is installed, but accept (or repair) it if it's already present. It sounds like I should set Vital="no", will this cause it to ignore other errors? Is there a way to limit what kind of errors are ignored? Is there a best practice I'm missing?
For reference, a redacted snippet of my xml:
<Component Id="REDACTED" Guid="{REDACTED}" Win64="yes">
<File
Id="filB754EE270009E240193A8279D1529A43"
Name="myservice.exe"
KeyPath="yes"
DiskId="1"
Source="SourceDir\File\filB754EE270009E240193A8279D1529A43" />
<ServiceControl
Id="MyService"
Name="MyService"
Start="install"
Stop="both"
Remove="uninstall"
Wait="no" />
<ServiceInstall
Id="MyService"
Name="MyService"
Type="ownProcess"
Start="auto"
ErrorControl="normal"
Vital="yes"
Account="[SERVICEACCOUNT]"
Arguments="svc -config "C:\Program Files\MyService\conf\service.flags""
Description="My Service">
<ServiceConfig
ServiceName="MyService"
FirstFailureActionType="restart"
SecondFailureActionType="restart"
ThirdFailureActionType="restart"
ResetPeriodInDays="1"
RestartServiceDelayInSeconds="5"
xmlns="http://schemas.microsoft.com/wix/UtilExtension" />
</ServiceInstall>
</Component>
I am trying to install a windows service using wix but I can't seem to point the file for the service to the user selected install directory.
<Component Id="MyServiceInstaller_ServiceControl" Guid="B72CAA3F-F2DB-48D2-90DD-061209AB2CE5" Directory="INSTALLDIR">
<CreateFolder />
<File Id='MyServiceEXE' Name='MyService.exe' DiskId='1' Source='[INSTALLDIR]MyService.exe' KeyPath='yes'/>
<ServiceInstall Id="MyServiceInstaller_ServiceInstall"
Type="ownProcess"
Vital="yes"
Name="My Service"
DisplayName="My Service"
Description="This will make windows services great again!"
Start="auto"
Account="NT AUTHORITY\LocalService"
ErrorControl="ignore"
Interactive="no" />
<ServiceControl Id="MyServiceInstaller_ServiceInstall"
Name="My Service"
Stop="both"
Remove="uninstall"
Wait="yes" />
</Component>
The issue seems to be when I use any [PROPERTY] directory I get the following error.
error LGHT0103 : The system cannot find the file
'[INSTALLDIR]MyService.exe'.
How do I tell Wix to use the installation folder the user selected as the path for the service?
File/#Source points to the file in your build environment. Component/#Directory tells Windows Installer where the file should be installed. That controls the file used to install and control the service.
I am using WIX to create MSI installers for C# services. The MSI does 3 jobs :
a) Copy solution file from bin to a particular location.
b) Create a folder where the service writes it's logs.
c) install the service on the machine if it previously does not exist.
The want these to execute in the similar order. But, when the condition to check if the service is installed fails the previous step does not seem to be executing, i.e, copying and creating steps fail too.
Here is the snippet of the code.
<Directory Id="TARGETDIR" Name="SourceDir">
<!--Creating folder hierarchy for storing project solution files; reference defined in fragments-->
<Directory Id="ProgramFilesFolder" Name="PFiles"/>
<!--Creating folder hierarchy for storing logs; reference defined in fragments-->
<Directory Id="LOGS" Name="Logs"/>
</Directory>
<InstallExecuteSequence>
<LaunchConditions After='AppSearch' />
<Custom Action='CMDInstallService' Before='InstallFinalize'></Custom>
</InstallExecuteSequence>
<Property Id="MYSERVICE">
<RegistrySearch Id="SERVICE_CHECK" Root="HKLM" Name="Install" Type="raw"
Key="SYSTEM\CurrentControlSet\services\Service"/>
</Property>
<Condition Message="Service is already installed on your system">
<![CDATA[Installed OR MYSERVICE]]>
</Condition>
<CustomAction
Id='CMDInstallService' Directory='PROJECT_INSTALL' Execute='deferred' Impersonate='no'
ExeCommand='[SystemFolder]cmd.exe /K "C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe Service.exe"'
Return ='check'/>
This will not work because the files and folder are not committed before InstallFinalize. To install a service, you should use the following command:
<Component Id="Component_WinService" Directory="Directory_WindowsService" Guid="*">
<File Id="File_WindowsService" KeyPath="yes"
Source="WindowsService.exe" />
<ServiceInstall Id="ServiceInstall_WindowsService"
Type="ownProcess"
Vital="yes"
Name="My Windows service"
Description="Windows service."
Start="auto"
Account="LocalSystem"
ErrorControl="ignore"
Interactive="no"
/>
<ServiceControl Id="ServiceControl_WindowsService"
Start="install"
Stop="both"
Remove="uninstall"
Name="My Windows Service"
Wait="no"
/>
</Component>
I'm using Wix to create my application installer and using it to install an assembly in the GAC and it works fine.
My issue is when I'm setting the assembly property 'copy local=false' and I'm executing the installation, then my services is not being installed cause it can't find this dll in the local folder and it's not being installed to GAC yet.
If I'll install another component from the EXE installation and will verify that the DLL is in the GAC I will be able then to install the service.
I'm using Paraffin.exe to go all over my application directory and generate a wix file and also using Mold file to add component not from this directory.
<DirectoryRef Id="Manager">
<Component Id="NlogGACRegisterComponent" Guid="1B224CD1-6EE8-46D3-9335-A84B7D8FB87B">
<File Id="NlogDLL" Name="Nlog.DLL" Source="..\Logging\Nlog.DLL" KeyPath="yes" Vital="yes" Assembly=".net"/>
</Component>
<Component Id="ManagerServiceComponent" Guid="EA31E161-4331-4A82-8F2B-7E26F62C96D6">
<File Id="StateManagerServiceEXE" Name="ManagerHostService.exe" DiskId="1" Source="..\ManagerHostService.exe" KeyPath="yes" Vital="yes" />
<ServiceInstall Id="ServiceInstaller" Type="ownProcess" Name="ManagerHostService" DisplayName="Manager Service" Description="Manager Service" Start="auto" Account="[SERVICEACCOUNT]" Password="[SERVICEPASSWORD]" ErrorControl="normal">
<util:PermissionEx User="Everyone" GenericAll="yes" ServiceChangeConfig="yes" ServiceEnumerateDependents="yes" ChangePermission="yes" ServiceInterrogate="yes" ServicePauseContinue="yes" ServiceQueryConfig="yes" ServiceQueryStatus="yes" ServiceStart="yes" ServiceStop="yes" />
</ServiceInstall>
<ServiceControl Id="StartService" Start="install" Name="ManagerHostService" Stop="both" Remove="uninstall" Wait="yes" />
</Component>
</DirectoryRef>
This in the Mold file which responsible to install the DLL to GAC and then the service.
How can I make sure it first install the DLL's and then the service?
All files and Dlls ARE installed by the time that services are started. Look in your MSI file with Orca at the InstallExecuteSequence (or look in a verbose log) and you'll see that InstallServices and StartServices are after InstallFiles.
The issue is that assemblies aren't installed and available in the GAC until InstallFinalize, this is described here:
https://msdn.microsoft.com/en-us/library/aa370063(v=vs.85).aspx
where it says "This means you cannot use the ServiceControl Table to start the service, instead you must use a custom action that is sequenced after InstallFinalize." which is what you'll need to do.