WiX: Installing Service as LocalService - installation

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.

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.

Powershell DSC Pull Server throws internal error - Microsoft.Isam.Esent.Interop not found

I've followed the instructions found in Powershell.org's DSC Book to set up an http Pull Server (Windows 2012 server) to use with DSC. I set up the http Pull Server, then crafted a configuration to be pulled, then set up my node's LCM to pull and run the configuration.
I can see a Scheduled task on the node under Task Scheduler/Microsoft/Windows/Desired State Configuration, so I know at least something worked. However, my configuration is not being run. When I look at the Event Logs under Apps&Svcs/Microsoft/Windows/Desired State Configuration/Operational Log, I see the following event:
Job {E0B6977A-E34F-4EDD-8455-E555063CD3DD} :
This event indicates that failure happens when LCM is trying to get the configuration from pull server using download manager WebDownloadManager. ErrorId is 0x1. ErrorDetail is The attempt to get the action from server http://pullserver.local:8080/PSDSCPullServer/Action(ConfigurationId='adaba4f6-b2b6-420d-a1dd-3714106451d6')/GetAction returned unexpected response code InternalServerError.
When I manually hit that URL, after enabling CustomErrors, here is the error:
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Isam.Esent.Interop, Version=6.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
I tried googling for this error (no luck) and I can't find helpful information on this DLL. It looks like it's supposed to come with some parts of Windows, but I don't see it on my system. I'm reluctant to download it from one of those "DLL Downloader" sites.
Any ideas why the DSC Pull Server seems to require this DLL and I don't have it?
It seems that the PSDSCPullServer resource out of xPSDesiredStateConfiguration defaults to using Esent as a database provider, which only works with Windows 8.1 (not Server 2012). I found some documentation here with some code I could copy. I just had to edit the web.config for my pull server and change this:
<add key="dbprovider" value="ESENT" />
<add key="dbconnectionstr" value="C:\Program Files\WindowsPowerShell\DscService\Devices.edb" />
with this:
<add key="dbprovider" value="System.Data.OleDb" />
<add key="dbconnectionstr" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\WindowsPowerShell\DscService\Devices.mdb;"/>
The fact that the original configuration tried to point to a Devices.edb (which did not exist on my system, .mdb did) is further evidence that something funky was going on.
What method have you used? The xPSDesiredConfiguration module from the resource kit or manual steps? I have not gone through the DSC book myself. So, I wouldn't know what they are recommending.
The Microsoft.Isam.Esent.Interop assembly is the ESE database provider. However, you need to use this provider only for Blue OS (Windows 8.1). Which OS are you using for the Pull Server? For all supported OS other than the Blue OS, you are supposed to use the Jet provider for the devices.mdb.

azure local storage emulator issue 400 bad request

I could not find this one on the site. It may be trivial, but the error message is pretty misleading.
When you try out things with the azure sdk and the local emulators (storage and compute emulators) while debugging, you may get the following error during initialization of those emulators:
The process cannot access the file because it is used by an another process.
Moreover, if you want to test things from the code and you want to access the blob storage emulator, you may get 400 Bad request as a result.
You can configure this. Open the "DSServiceLDB.exe.config" file under "C:\Program Files\Microsoft SDKs\Windows Azure\Emulator\devstore".
Inside the file, tweak the values in this section:
<services>
<service name="Blob" url="http://127.0.0.1:10000/"/>
<service name="Queue" url="http://127.0.0.1:10001/"/>
<service name="Table" url="http://127.0.0.1:10002/"/>
</services>

Stopping A Service In WIX And Starting When Install Is Complete

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" />

Resources