Is there anyway to check to see if a service is installed, and if so, stop it and uninstall it when my application is being uninstalled using WiX 3.7? I don't want WiX to install the service though - just uninstall it.
I have WiX setup to install several application components, but the application itself CAN spawn a Windows Service (depending on features selected during install). I'm not really sure what the best way to clean that up is - I guess just to have my setup check if that service exists and remove it upon uninstall.
I'm not sure if I would need a CustomAction for that. I'm fairly familiar with installing services with WiX, but not JUST removing them (if it exists).
Here is my setup project. Just to give a little additional background on this, this is an auto-updater/launcher application. It takes a series of XML files to tell it how to update/prepare an application. If you choose the "MyApp Printer" feature, for example, it would install an extra XML file that tells my application how to hash check the local files against a web service and then install and start the "MyApp Printer" Windows Service for that component. The Windows Service that is located inside my actual WiX Setup Project is something completely different, and that works fine when uninstalling so please disregard that one.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="MyApp ID" Language="1033" Version="1.0.0.0" Manufacturer="MyApp ID" UpgradeCode="932dbe1f-e112-4bd0-8f60-b81850fb465b">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<WixVariable Id="WixUILicenseRtf" Value="EULA.rtf" />
<Feature Id="ProductFeature" Title="MyApp ID Setup Core" Level="1" Absent="disallow" Display="expand">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id="MyAppStartMenuFolderRemove" />
<Feature Id="MyAppClientFeature" Title="MyApp ID Windows Client" Level="1" Absent="allow">
<ComponentGroupRef Id="MyAppClientComponents" />
<ComponentRef Id="MyAppStartMenuIcon" />
</Feature>
<Feature Id="MyAppPrinterFeature" Title="MyApp ID Printer App" Level="2" Absent="allow">
<ComponentGroupRef Id="MyAppPrinterComponents" />
<ComponentRef Id="PrinterStartMenuIcon" />
</Feature>
</Feature>
<UIRef Id="WixUI_FeatureTree" />
<UIRef Id="WixUI_ErrorProgressText" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="MyAppBaseFolder" Name="MyAppID">
<Directory Id="INSTALLFOLDER" Name="MyAppLauncher">
<Directory Id="UPDATESCRIPTSFOLDER" Name="Scripts" />
</Directory>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="MyApp ID"/>
</Directory>
</Directory>
</Fragment>
<Fragment>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="PrinterStartMenuIcon">
<Shortcut Id="PrinterStartMenuShortcut"
Name="MyApp ID Printer UI"
Description="Manage the MyApp ID Printer Service"
Icon="MyAppPrinterIcon"
Target="[INSTALLFOLDER]AutoUpdater.exe"
Arguments="MyAppPrinter"
WorkingDirectory="INSTALLFOLDER">
<Icon Id="MyAppPrinterIcon" SourceFile="$(var.AutoUpdater.Launcher.TargetDir)\Resources\MyApp_printer_white.ico" />
</Shortcut>
<RegistryValue Root="HKCU" Key="Software\Microsoft\MyApp.CardPrinter.Service" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
<Component Id="MyAppStartMenuIcon">
<Shortcut Id="MyAppStartMenuShortcut"
Name="MyApp ID"
Description="Run the MyApp ID Windows Client software"
Target="[INSTALLFOLDER]AutoUpdater.exe"
Arguments="MyAppClient"
WorkingDirectory="INSTALLFOLDER"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\MyApp.WindowsClient" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
</Component>
<Component Id="MyAppStartMenuFolderRemove">
<RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\Microsoft\MyApp.WindowsClient" Name="installedFolder" Type="integer" Value="1" KeyPath="yes"/>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="LibrariesComponent" Guid="7ED3B3B3-A984-44ED-9BA3-841F53CEA114">
<File Source="$(var.AutoUpdater.Foundation.TargetPath)" Vital="yes" KeyPath="yes" />
<File Source="$(var.AutoUpdater.Module.TargetPath)" Vital="yes" />
<File Source="$(var.AutoUpdater.Module.WebService.TargetPath)" Vital="yes" />
</Component>
<Component Id="ServiceComponent" Guid="CAB8D997-5798-4B9D-8CA0-78AACE58932E">
<File Source="$(var.AutoUpdater.Service.TargetPath)" Vital="yes" KeyPath="yes" />
<File Source="$(var.AutoUpdater.Service.TargetDir)\AutoUpdater.Service.exe.config" Name="AutoUpdater.Service.exe.config" Vital="yes" />
<ServiceInstall Name="ServiceComponentInstall" Id="ServiceComponentInstall" DisplayName="MyApp ID Launcher" Account="LocalSystem" ErrorControl="normal" Type="ownProcess" Start="auto" Vital="yes" />
<ServiceControl Name="ServiceComponentInstall" Id="ServiceComponentControl" Start="install" Stop="both" Remove="uninstall" Wait="yes" />
</Component>
<Component Id="LauncherComponent">
<File Source="$(var.AutoUpdater.Launcher.TargetPath)" Vital="yes" />
<File Source="$(var.AutoUpdater.Launcher.TargetDir)\Resources\MyApp_printer_white.ico" Name="MyApp_printer_white.ico" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="MyAppClientComponents" Directory="UPDATESCRIPTSFOLDER">
<Component Id="MyAppClientXml">
<File Source="$(var.AutoUpdater.Service.TargetDir)\Scripts\MyAppClient.xml" Name="MyAppClient.xml" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="MyAppPrinterComponents" Directory="UPDATESCRIPTSFOLDER">
<Component Id="MyAppPrinterXml">
<File Source="$(var.AutoUpdater.Service.TargetDir)\Scripts\MyAppPrinter.xml" Name="MyAppPrinter.xml" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
I hope that wasn't too confusing :). Thanks in advance!
EDIT:
Thank you Rob, the solution was to add the <ServiceControl> element to the last Fragment:
<Fragment>
<ComponentGroup Id="MyAppPrinterComponents" Directory="UPDATESCRIPTSFOLDER">
<Component Id="MyAppPrinterXml">
<File Source="$(var.AutoUpdater.Service.TargetDir)\Scripts\MyAppPrinter.xml" Name="MyAppPrinter.xml" />
<ServiceControl Id="NukeMyAppPrinterService" Name="MyApp ID Printer Service" Remove="uninstall" Stop="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
It will work whether or not that "MyApp ID Printer Service" is installed or not. I love the easy solutions!
Can't say I've done this myself (this is a pretty unique scenario) but the ServiceControl element should do the work just fine:
<ServiceControl Id='NukeService' Name='YourServiceName'
Remove='uninstall' Stop='uninstall' />
Related
I've got the following entries in my Web.config file in an asp.net mvc application:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
...
</configSections>
<log4net>
<appender name="PublicAccessAppender" type="log4net.Appender.RollingFileAppender">
<datePattern value="'C:\Users\my_user_name\Documents\Temp\logs\public-access.'yyyy-MM-dd'.log'" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<maxSizeRollBackups value="5" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="PublicAccessAppender" />
</root>
</log4net>
...
</configuration>
I hope it's pretty self-explanatory what I'm trying to achieve, but when I run the application (hosted in IIS), I get no log file. FWIW, the directory hierarchy exists up to Temp folder, and I'd like log4net to generate the rest of the directories/files in the path.
I've added the log4net nuget package to my application, and I'm logging with the INFO level.
What am I missing here?
I think you can't put full path into datePattern, there must be just YYYYmmdd and things like that. Put the file path into file element:
<file value="C:\Users\my_user_name\Documents\Temp\logs\public-access.log" />
<datePattern value="yyyyMMdd" />
<preserveLogFileNameExtension value="true" />
The last element forces to put datePattern before the .log extension which was probably your original goal..
Here's the working appender configuration:
<appender name="PublicAccessAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\temp\my_user_name\Documents\Temp\logs\app.log" />
<datePattern value=".yyyy-MM-dd" /><!-- can be omitted as it's the default datePattern value -->
<rollingStyle value="Date" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
Note to readers struggling with log4net configuration: asp.net hosted in IIS pretty much has 0 write permssions, so the issue you're most likely struggling with is that your web app simply doesn't have permission to write to the log file.
That's what was happening for me, and I noticed it by inspecting the contents of log4net.LogManager.GetRepository().ConfigurationMessages in the debugger after calling .Configure().
I followed this post to give my web app the necessary persmissions to write to the log file (namely Read/Write/Modify).
My .wxs file has a piece like this
<Directory Id="UDPMonitorFiles" Name="UDP Monitor">
<Component Id="UDPMonitorFiles" Guid="*">
<File Id="UDP_UDPMonitor.exe"
Source="$(var.UDP Monitor.TargetDir)\UDP Monitor.exe"/>
<File Id="UDP_UDPMonitor.exe.config"
Source="$(var.UDP Monitor.TargetDir)\UDP Monitor.exe.config"/>
<ServiceInstall
Id="UDPServiceInstaller"
Type="ownProcess"
Vital="yes"
Name="DiskManagement"
DisplayName="Epicentral UDP Monitor"
Description="Epicentral UPD Printer Monitoring Service"
Start="demand"
Account="LocalSystem"
ErrorControl="ignore"
Interactive="no">
</ServiceInstall>
</Component>
</Directory>
<Directory Id="S2SCallerServiceFiles" Name="S2S Caller Service">
<Component Id="S2SCallerServiceFiles" Guid="*">
<File Id="S2SCallerService.exe"
Source="$(var.S2SCallerService.TargetDir)\S2SCallerService.exe"/>
<File Id="S2SCallerService.exe.config"
Source="$(var.S2SCallerService.TargetDir)\S2SCallerService.exe.config"/>
<File Id="S2S.xml"
Source="$(var.S2SCallerService.TargetDir)\S2S.xml"/>
<File Id="S2S_log4net.dll"
Source="$(var.S2SCallerService.TargetDir)\log4net.dll"/>
<ServiceInstall
Id="S2SCallerServiceInstaller"
Type="ownProcess"
Vital="yes"
Name="DiskManagement"
DisplayName="Epicentral S2S Caller Service"
Description="Epicentral S2S Caller Service"
Start="demand"
Account="LocalSystem"
ErrorControl="ignore"
Interactive="no">
</ServiceInstall>
</Component>
</Directory>
<Directory Id="HealthWatcherServiceFiles" Name="Health Watcher Service">
<Component Id="HealthWatcherServiceFiles" Guid="*">
<File Id="HealthWatcherService.exe"
Source="$(var.HealthWatcherService.TargetDir)\HealthWatcherService.exe"/>
<File Id="HealthWatcherService.exe.config"
Source="$(var.HealthWatcherService.TargetDir)\HealthWatcherService.exe.config"/>
<ServiceInstall
Id="HealthWatcherServiceInstaller"
Type="ownProcess"
Vital="yes"
Name="DiskManagement"
DisplayName="Epicentral Health Watcher Service"
Description="Epicentral Health Watcher Service"
Start="demand"
Account="LocalSystem"
ErrorControl="ignore"
Interactive="no">
</ServiceInstall>
</Component>
</Directory>
That somehow only registers one service even though there are 3 projects with their own entry. If I comment out the one which installs (HealthWatcherServiceInstaller) then S2SCallerServiceInstaller is registered instead.
Any ideas how this could happen?
The ServiceInstall/#Name attribute is the name of the service. You have set all of the services to have the same name. You need to specify different names for each service.
We are using Wix script for installation through Jenkins. Ours is 64-bit OS. If executed through command prompt Windows\system32 desktop folder is dispalyed as C:\Users\XXXXX\Desktop\ which will do the installation properly. But if we run through Jenkins Desktop folder is C:\Windows\SysWOW64\config\systemprofile\Desktop\ . In later case installation and shortcut creation is improper. How to overcome this ?? What might be the reason?? Thank you in advance for any help. Here is the WIX SCRIPT
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="PUT-GUID-HERE" Version="1.0.0.0"
Language="1033" Name="Product" Manufacturer="ABC">
<Package InstallerVersion="200" Compressed="yes"
Comments="Windows Installer Package"/>
<Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="Product">
<Component Id="XYZ" Guid="*">
<File Id="XYZ.exe" Source="D:\Repo\Solution\XYZ\bin\Debug\XYZ.exe">
</File>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" Name="XYZ">
<Component Id="ApplicationShortcuts" Guid="*">
<Shortcut Id="ApplicationShortcut1" Name="XYZ"
Description="Product Shortcut"
Target="[APPLICATIONROOTDIRECTORY]XYZ.exe"
WorkingDirectory="APPLICATIONROOTDIRECTORY"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\XYZ"
Name="installed" Type="integer" Value="1" KeyPath="yes"/>
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
</Component>
</Directory>
</Directory>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="XYZ"/>
<ComponentRef Id="ApplicationShortcuts"/>
</Feature>
<UIRef Id="WixUI_Mondo" />
<UIRef Id="WixUI_ErrorProgressText" />
</Product>
</Wix>
It seems Jenkins is running as SYSTEM account. If you want to run Jenkins as user XXXXX so that the installation goes fine as it went while running as user XXXXX, then just try running Jenkins with the same user. To do that, go to Run > type services.msc > select Jenkins > (Right-click and select) Properties > Click on Log On tab > Select This account
Now enter the user name with which you want to run Jenkins and its password. Now restart Jenkins. You can now give a try to your WiX script.
I have created a Wix installer that is meant to replace an installer that was created in Visual Studio, and is supposed to update a previous version of the software it is installing. I kept the same upgrade code that was used in the previous installer for mine, so I thought that this code would work:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="Product"
Language="1033"
Version="1.0.6.0"
Manufacturer="Company"
UpgradeCode="PREVIOUSLY-USED-UPGRADE-CODE">
<Package InstallerVersion="301"
Compressed="yes"
InstallScope="perMachine"
Manufacturer="Company"
Description="Installs Product"
Keywords="Installer,MSI" />
<Media Id="1"
Cabinet = "Product.cab"
EmbedCab = "yes"/>
<MajorUpgrade Schedule="afterInstallInitialize" DowngradeErrorMessage="A newer version of Product is already installed." AllowDowngrades="no"/>
<Directory Id ="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="CompanyFolder" Name ="Company">
<Directory Id="INSTALLDIR" Name="Product" />
</Directory>
</Directory>
</Directory>
<Feature Id ="ProductFeature"
Title = "Product Feature"
Level = "1">
<ComponentGroupRef Id="ProductComponents"/>
</Feature>
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
<Component Id="cmpCOMAdminW2K" Guid="*">
<File Id="COMAdminW2K" Vital="yes" KeyPath="yes" Name="Interop.COMAdminW2K.dll" Source="Local\Path\To\Interop.COMAdminW2K.dll" />
<!-- Several registry entry updates -->
</Component>
<Component Id="cmpCustomSerializer" Guid="*">
<File Id="CustomSerializer" Vital="yes" KeyPath="yes" Name="AREANAME.Serialization.CustomSerializer.v2.0.dll" Source="Local\Path\To\AREANAME.Serialization.CustomSerializer.v2.0.dll" />
</Component>
<Component Id="cmpProductServer" Guid="*">
<File Id="ProductServer" Vital="yes" KeyPath="yes" Name="AREANAME.ProductServer.Shared.v2.0.dll" Source="Local\Path\To\AREANAME.ProductServer.Shared.v2.0.dll" />
</Component>
<Component Id="cmpRemotingHelper" Guid="*">
<File Id="RemotingHelper" Vital="yes" KeyPath="yes" Name="AREANAME.TechPC.RemotingHelper.v2.0.dll" Source="Local\Path\To\ND1.TechPC.RemotingHelper.v2.0.dll" />
</Component>
<Component Id="cmpProduct" Guid="*">
<File Id="Product" Vital="yes" KeyPath="yes" Name="AREANAME.TechPC.Service.Product.v2.0.exe" Source="Local\Path\To\AREANAME.TechPC.Service.Product.v2.0.exe" />
<ServiceInstall
Id="Product"
Name="ServiceName"
DisplayName="Full Service Name"
Start="auto"
ErrorControl="normal"
Type="ownProcess"/>
<ServiceControl
Id="startAndStopUsrPres"
Name="ServiceName"
Start="install"
Stop="both"
Remove="uninstall"
Wait="yes"/>
</Component>
<Component Id="cmpProductConfig" Guid="*">
<File Id="ProductConfig" Vital="yes" KeyPath="yes" Name="AREANAME.TechPC.Service.Product.v2.0.exe.config" Source="Local\Path\To\AREANAME.TechPC.Service.Product.v2.0.exe.config" />
<RemoveFile Id="RemoveProductConfig" Name="AREANAME.TechPC.Service.Product.v2.0.exe.config" On ="install"/>
</Component>
<Component Id="VersionRegistryEntry" Guid="*">
<RegistryKey Root="HKLM"
Key="Software">
<RegistryKey Key="Company"
ForceCreateOnInstall="yes">
<RegistryKey Key="Product"
ForceCreateOnInstall="yes">
<RegistryValue Id="ProductVersionEntry"
KeyPath ="yes"
Action ="write"
Name="Version"
Value="1.0.6.0"
Type="string"/>
</RegistryKey>
</RegistryKey>
</RegistryKey>
</Component>
</ComponentGroup>
</Product>
</Wix>
*Above code is obviously redacted.
The installer will be run on almost all of my company's machines through a software management system, so I have been testing my installer with the following command line:
msiexec.exe /i <ProductInstaller>.msi /quiet /l*v log.txt
That brings me to the problem. Some of you may have noticed that I have a "RemoveFile" tag inside the component containing my config file. I have it there because that file was not always getting updated when the installer ran. This, coupled with the MajorUpgrade schedule, allowed me to remove that file out of the target directory and ensure that the new config file was always getting put in that location. That fix seemed to work in my tests. The program files all appeared to be correct whenever I tried to run the installer on a machine that had a previous version of the program. However, even with all of the correct files in the correct location, the service would not start, either automatically or by manually attempting to start it within services.msc. Additionally, whenever I tried to run the following to uninstall:
msiexec.exe /x <ProductInstaller>.msi /quiet /l*v log.txt
I received the error message "This action is only available for products that are currently installed."
I'm not sure what to make of that since the new files are where they are supposed to be, and the old files are gone.
With all of that information, my question is somewhat vague: "What am I missing in order to have an installer that puts all files in the proper location and starts the service on install, and stops the service and removes the files on uninstall?"
Any assistance would be appreciated, and I would be happy to provide portions of the log files upon request to anybody who thinks that they would help in helping me to figure out what's going on.
Thank you!
-Seth
It was, in fact, that renamed .dll that was causing the problem.
I need write the response message to a "response.xml" file. And the response should be appended to this file, I set parameter "Append" true, but no use, is completely overwritten every time. Anyone can help me? Thanks and best regards.
<proxy xmlns="http://ws.apache.org/ns/synapse" name="EndpointTest" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<log level="full" />
</inSequence>
<outSequence>
<log level="full" />
<send>
<endpoint>
<address uri="vfs:file:///usr/local/wso2esb-4.0.3/Log" format="pox" />
<property name="OUT_ONLY" value="true" />
<property name="transport.vfs.Append" value="true" />
<property name="transport.vfs.ReplyFileName" value="response.xml" />
</endpoint>
</send>
<send />
</outSequence>
<endpoint>
<address uri="http://172.21.13.151:18989/aaadc/services/receiveMsg" format="pox" />
</endpoint>
</target>
</proxy>
Remove the append= true parameter from service level and use with endpoint url
eg:
vfs:file:///usr/local/wso2esb-4.0.3/Log?transport.vfs.Append=true