Stopping A Service In WIX And Starting When Install Is Complete - installation

I'm using WiX 3.5 to create an installer that installs a Windows Service and copies DLL's to the bin directory of a third party app. The third party app has a series of Windows Services also that will need stopped before the DLL's get copied and started after the install is complete. What would I need to do to accomplish this. I have looked for examples, but can only find how to start the service that I'm installing.
***On a side note, the service that I am installing needs to run under a specific user account. I see how to define the Service Account/Password in WIX, but I'm hesitant to use that because it stores the password unencrypted in XML, and I have security concerns with that.

First off, to stop a service you need to use the ServiceControl element.
<ServiceControl Id="serviceName" Name="actualServiceName" Stop="both" Start="both" Wait ="yes" />
To answer your side not, you can have the username and password be properties that the user sends to the MSI, or that the user enters from the GUI.
<ServiceInstall Id="serviceName" Name="shortName" DisplayName="longName" Type="ownProcess" Start="auto" ErrorControl="normal" Account="[USER]" Password="[USERPWD]" Description="description" />
<Property Id="USER" Value="defaultValue" />
<Property Id="USERPWD" Value="defaultValue" Hidden="yes" />
Of course, the default value is not needed, and not really recommended, but I still put it in there.

Use <ServiceControl/>
<ServiceControl Id="thirdPartyService" Name="thirdPartyService" Stop="install" Start="install" Wait="yes" />

Related

Don't override the service account when upgrading a service using WiX toolset

I am trying to setup a WiX installer that install a windows service and handles upgrades and updates.
The installer works like a charm, the user installs the service under the LocalSystem account then a service engineer has to assign a domain account to that service.
Here is my service installer component:
<Component Id="my_exe_Component">
<File Id="Myexe" Source="$(var.Myproject.TargetPath)" KeyPath="yes" />
<ServiceInstall Id="my_exe" Type="ownProcess" Vital="no" Name="NME" DisplayName="My intaller" Description="My installer description" Start="auto" Account="LocalSystem" ErrorControl="ignore" Interactive="no">
<util:ServiceConfig
FirstFailureActionType="restart"
SecondFailureActionType="restart"
ThirdFailureActionType="restart"
RestartServiceDelayInSeconds="0"
ResetPeriodInDays="1"/>
</ServiceInstall>
<ServiceControl Id="my_exe" Stop="both" Remove="uninstall" Name="NME" Wait="yes" />
</Component>
When I perform an upgrade to the installer, the account set to the service get overwritten back to the LocalSystem account, how do I persist the account set to my service when performing an upgrade?
My upgrade clause is set like so:
<MajorUpgrade AllowSameVersionUpgrades="yes" AllowDowngrades="no" DowngradeErrorMessage="A newer version of [ProductName] is already installed." Schedule="afterInstallExecute" />
Any help would be appreciated.
This is a classic source of truth problem. MSI wants to be the source of truth and doesn't have anything in it's code to account for this scenario. It thinks the service should be LocalSystem and so it wants to fix it. ( This isn't just upgrades ... a repair will do the same thing. )
So, what to do?
Option A:
Bring username /password configuration into the MSI. UI work, credential validation and encryption of the creds persisting it on the machine somewhere so that subsequent transactions can decrypt and reuse the credentials.
Note: Risk. The creds can be reverse engineered.. I got news though... so can windows LSA secrets and Application Pool Identities and such.
Option B:
Use custom actions to create the service. This way you can do logic to not touch the service during subsequent transactions.
Option C:
Put conditional expressions on CreateServices standard action to only apply during first time installation and not major upgrades.
Risk: If you ever change anything else about the service it won't get deployed by an upgrade because it's been bypassed. Also this is for all services in your MSI not just this one.
Option D:
Embrace running as a built in service account and use active directory permissions to grant that computer object rights to whatever it connects to.
Option E:
If the user applies creds after install, then they can simply do it again after upgrade. They can deal with it.

util:CloseApplication from Windows service

I am trying to close "Tray Application" during updating my application. Functionality to close tray from "Windows Service" looks like this:
<util:CloseApplication
Id="CloseTrayAgent"
Target="$(var.TrayAgentBinName).exe"
RebootPrompt="no"
CloseMessage="yes"
Description="Tray application is still running"/>
<InstallExecuteSequence>
<Custom Action="WixCloseApplications" Before="RemoveFiles" />
</InstallExecuteSequence>
That scenario works if update is invoked from "User" (just from user console) but it does not work if it is invoked from "Windows Service".
I checked msi log but it seems to me there is no errors.
Where is my mistake? Thanks.
Services run in session zero, which is isolated from the interactive desktop session. This article explicitly points out the issue with services that use APIs like SendMessage to send a message to a an app running in the interactive session:
https://blogs.technet.microsoft.com/askperf/2007/04/27/application-compatibility-session-0-isolation/
A search for -services session isolation- or -session 0- will give more information.

Why does a FTP send depend on its directory size?

We have a Proxy that is taking messages from a JMS queue and sends them to an FTP folder. We discovered now, that the sending to the FTP is very slow when the target directory on the FTP already contains a lot of files. (i.e. when I have around 2000 files in a directory, it already takes several seconds)
Here the code of our Proxy (get messages (plain-text) from a JMS and writes them to FTP):
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="myProxy" statistics="disable" trace="disable" transports="jms">
<parameter name="transport.jms.Destination">myQueue</parameter>
<parameter name="transport.jms.ConnectionFactory">myQueueConnectionFactory</parameter>
<parameter name="transport.jms.DestinationType">queue</parameter>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>text/plain</default>
</rules>
</parameter>
<target faultSequence="rollbackSequence">
<inSequence>
<log level="custom">
<property name="STATUS" value="myProxy called"/>
</log>
<property name="ClientApiNonBlocking" scope="axis2" action="remove"/>
<property name="OUT_ONLY" value="true"/>
<property name="transport.vfs.ReplyFileName" expression="fn:concat(get-property('SYSTEM_DATE','yyyyMMddHHmmss_SSS'), '_result.txt')" scope="transport"/>
<send>
<endpoint key="myFTPendpoint"/>
</send>
</inSequence>
</target>
And the FTPEndpoint lookes like this:
<?xml version="1.0" encoding="UTF-8"?>
<endpoint xmlns="http://ws.apache.org/ns/synapse" name="myFTPendpoint">
<address uri="vfs:ftp://USER:PASSWORD#SERVER.com/path/toSomewhere?vfs.passive=true"/>
</endpoint>
My analysis for now:
It is only slow when using FTP with VFS. When using the local file system - it is fast.
The files are tiny - so it's not the upload time
The network is fast
!Speed depends on the number of files already in the directory on the FTP!
Possible solutions?
Fix the problem of the speed. Disable the directory listing?
Workaraound: Create new folders at the output (that not one folder gets filled too much)
Does someone also discovered the same issue? And how can the FTP speed to big directories be improved?
Thanks for any help
I believe regardless of whether you do an explicit Directory listing there will be always an inferred Directory listing to determine whether the file write operation will be an overwrite or a create.
This leaves you with the other workaround.
You should create new folders at the output. Implement a hashing scheme to aid in the folder naming so that you know that the folders will not get filled too much. For example, instead of file1234.ext consider file/1/2/3/4.ext.
Generally, if you have performance issues you should benchmark.
Try performing the same action from a command line FTP client and see where the slow point is. Running each of the commands one by one will allow you to see which exact step(s) perform differently when putting to a folder with many files vs an empty folder.
You should also consider that the performance issue may not be with FTP. Just because that's the channel you're seeing the issue on, doesn't mean (purely as an example) that the OS isn't just slow when handling large folders (like NT used to be). FTP is the way you're seeing this error, that doesn't mean it's related to the cause.
To test this, I would access the server directly and access the folder that contains the files.
Finally, if none of those give you any clues, I'd probably try doing the same thing on a different end-point to see if there's a persistent problem.
You will always have issues on FTP with that amount of files, this is a common problem, and is not related with JMS, to confirm that, use a ftp client like filezilla and try to list the directory where the 2000 files exists...

Is there a way to simulate medium trust in VS2010

I am looking for "easy button", where I can say run this app under medium trust.
Yes,
As per: http://blog.mahingupta.com/mahingupta/blog/post/2010/08/01/AspNet-Set-Medium-trust-in-local.aspx
<system.web>
<trust level="Medium" />
</system.web>
Just note that most hosts do modifications to their medium trust offerings. Usually give few more permissions for LINQ and cross-server calls, but it differs from one host to another.
You can configure medium trust - just add a configuration option.
To configure an application to run with medium trust, add the following element to either the application's specific Web.config file in the application's virtual root directory or to the machine-level Web.config file.
<trust level="Medium" originUrl="" />

WiX: Installing Service as LocalService

I am trying to get my application an installer via WiX 3.0. The exact code is:
<File Id="ServiceComponentMain" Name="$(var.myProgramService.TargetFileName)" Source="$(var.myProgramService.TargetPath)" DiskId="1" Vital="yes"/>
<!-- service will need to be installed under Local Service -->
<ServiceInstall
Id="MyProgramServiceInstaller"
Type="ownProcess"
Vital="yes"
Name="MyProgramAddon"
DisplayName="[removed]"
Description="[removed]"
Start="auto"
Account="LocalService"
ErrorControl="ignore"
Interactive="no"/>
<ServiceControl Id="StartDDService" Name="MyProgramServiceInstaller" Start="install" Wait="no" />
<ServiceControl Id="StopDDService" Name="MyProgramServiceInstaller" Stop="both" Wait="yes" Remove="uninstall" />
Thing is, for some reason LocalService fails on the "Installing services" step, and if I change it to "LocalSystem" then the installer times out while trying to start the service.
The service starts fine manually and at system startup, and for all intents and purposes works great. I've heard there are issues getting services to work right under LocalService, but Google isnt really helping as everyone's responses have been "got it to work kthx".
Just looking to get this service set up and started during installation, that's all. Any help? Thanks!
Make sure the services.msc window is closed when you install
Have you tried ...
NT AUTHORITY\LocalService
Per this doc ...
... but the name of the account must be NT
AUTHORITY\LocalService when you call
CreateService, regardless of the
locale, or unexpected results can
occur.
reference: ServiceControl Table
The MSI documentation for ServiceControl Table states that the 'Name' is the string name of the service. In your code snipet, your ServiceControl 'Name' is set to the 'ID' for the ServiceInstall and not its 'Name'. So, your ServiceControl elements should read:
<ServiceControl Id="StartDDService" Name="MyProgramAddon" Start="install" Wait="no" />
<ServiceControl Id="StopDDService" Name="MyProgramAddon" Stop="both" Wait="yes" Remove="uninstall" />
Here is another case where a localsystem service can fail to install with error 1923: if you have another service already installed with the same DisplayName (but different internal service name, path, etc). I just had this happen to me.
I spent a while looking into this and discovered it was because I had the keypath attribute set on the the component not on the file. My wix file now looks like:
<Component Id="comp_WF_HOST_18" DiskId="1" KeyPath="no" Guid="3343967A-7DF8-4464-90CA-7126C555A254">
<File Id="file_WF_HOST_18" Checksum="yes" Source="C:\Projects\GouldTechnology\Infrastructure\WorkflowHost\WorkflowHost\bin\Release\WorkflowHost.exe" KeyPath="yes"/>
<ServiceInstall
Id="workflowHostInstaller"
Type="ownProcess"
Vital="yes"
Name="WorkflowHost"
DisplayName="Workflow Host"
Start="demand"
Account="[WORKFLOW_HOST_USER_ACCOUNT]"
Password="[WORKFLOW_HOST_USER_PASSWORD]"
ErrorControl="critical"
Interactive="no"/>
<ServiceControl Id="StartWFService" Name="workflowHostInstaller" Start="install" Stop="both" Remove="both" Wait="no" />
</Component>
Now I just need to work out how to give it the correct permissions...
I had the same problem. It turns out that I had a typo in the <ServiceControl Id="StartService" Name="MyServiceName" where my Name did not match the service name I specified in the service project when I created it.
This was also the problem with my service not uninstalling.
Had the same problem but with specified accounts, got bored of it and created a CA to start the service after the install was completed instead. Just don't bother trying to start it with MSI, just leave it to a CA, unless you get some quality info from somewhere.
BTW using LocalSystem and a manually started service works fine. Never got any other variations to work.
I'll just echo aristippus303's advice: Don't try to start a service with Windows Installer, and don't set any account, just accept the default of LocalSystem during installation. Trying to do anything else is too problematic. Windows Installer waits for the service to indicate it has started, and there are too many things that can go wrong, what with permissions and rights and firewall settings and missing files and so on, so then Windows Installer ends up frozen or terminating with an error and your install has failed.
What you want to do is to specify in your documentation that the user should manually change the service's account (if necessary) and manually start the service after the install is done, and to trouble-shoot any problems that turn up at that point. Or just tell the user to reboot so the auto-start option will start the service if you're fairly sure that there won't be problems.
Please pay attention that in the documentation for ServiceInstall element it is written about the Account attribute that "The account under which to start the service. Valid only when ServiceType is ownProcess.". In your example you did not specify the ownProcess service type which may be the problem.
We had the same problem occuring only on Windows XP machines were the service could not be installed. In the end we found that on XP the name setting from the WiX file is ignored and it instead used the service name set in the C# code. We happened to have a name in the code that contained white-space, i. e. "Blah Blah Service", when this was set to the same name as the WiX file used on Windows 7 it worked well.

Resources