Unable to setup with WiX Installer - c#

I created a Setup with WiX Installer for my C# application.
I use a Class CustomAction to install a SQL data base and setting rights to a folder.
There is my Class :
public class CustomActions
{
[CustomAction]
public static ActionResult AllowAppData(Session session){...}
[CustomAction]
public static ActionResult Install_SetupDataBase(Session session){...}
}
And the product.wxs :
<Binary Id="CASetup.dll" SourceFile="$(var.SetupCustomAction.TargetDir)$(var.SetupCustomAction.TargetName).CA.dll" />
<CustomAction Id="CustomActionSetupAllow" BinaryKey="CASetup.dll" DllEntry="AllowAppData" Execute="immediate" />
<CustomAction Id="CustomActionSetupBase" BinaryKey="CASetup.dll" DllEntry="Install_SetupDataBase" Execute="immediate" />
<InstallExecuteSequence>
<Custom Action='CustomActionSetupAllow' After='InstallFinalize' />
<Custom Action='CustomActionSetupBase' After='InstallFinalize' />
</InstallExecuteSequence>
The build is ok but when the Install perform I have the message :
I've try with only CustomActionSetupAllow and it's works fine. But with CustomActionSetupBase I got the message.
How can I know what DLL are missing ? And where should I add a reference ?

The error "could not be run" doesn't mean it's missing. It's in the Binary table of the MSI file and will be streamed out onto disk to run. The error means that it doesn't load and run, or is crashing. It's possible that there are missing dependent Dlls.
One potentially serious problem is that you've marked the custom action (CA) to be immediate. That means it runs before anything has been installed, such as perhaps the empty database you might be populating, as well as any dependent Dlls it might need. Apart from that, if you create the SQL DB with an immediate CA and the install subsequently fails so you'll have a DB but no installed product. It should be a deferred custom action, ideally with a rollback CA to remove the DB so the user can run the install again and you don't populate the same DB again, if that's an issue.
There are other areas you may want to look at. An immediate CA runs with the installing user's credential and not elevated, so if the code requires elevation it will fail. A deferred CA will run elevated with the system account, so access to a SQL DB with the system account might be an issue. Code in a CA needs to be very defensive because it's not the same environment as an interactive test. For these reasons it's often better to do this with a startup program that runs in a true interactive environment when the app first runs.

Related

Wix installer defaults to original Property value when another user logs in for the first time with app installed

I have a Wix installer where I have a property defined (Product.wxs):
<Property Id="SITEBASE" Value="localhost"/>
<Component Id="ApplicationSettings">
<File Id="ApplicationConfig" Name="MyApplication.exe.config" Source="$(var.Application.TargetPath).config"/>
<util:XmlFile
Id="ApplicatonConfig1"
File="[INSTALLDIR]MyApplication.exe.config"
Action="setValue"
Value="[SITEBASE]"
ElementPath="//MyApp.Properties.Settings/setting[\[]#name='SiteBase'[\]]/value"
Permanent="yes"
Sequence="1" />
<Component Id="ApplicationSettings">
<File Id="ApplicationConfig" Name="MyApplication.exe.config" Source="$(var.Application.TargetPath).config"/>
<util:XmlFile
Id="ApplicatonConfig1"
File="[INSTALLDIR]MyApplication.exe.config"
Action="setValue"
Value="[SITEBASE]"
ElementPath="//MyApp.Properties.Settings/setting[\[]#name='SiteBase'[\]]/value"
Permanent="yes"
Sequence="1" />
My source MyApplication.exe.config has SiteBase = "http://localhost/AnotherValueForTesting"
I have a Dialog where I an set the value for SiteBase (starts off as the value from Property SITEBASE so will display: localhost
If I Install the application as TestUser1, changing localhost to 1.1.1.1 the config file has the entered value (1.1.1.1) and everything is fine. I can reboot and log in using TestUser1 and all is still good.
If I log in as TestUser2, the values for TestUser2 will now have "localhost" (the default for the property)
I can then uninstall, re-install (using the 1.1.1.1 value) and when I log in as TestUser1/2 both have 1.1.1.1.
If I then log in as TestUser3, TestUser3 again has localhost, not 1.1.1.1. I tested with a different value in the app.config to determine that the value is definitely defaulting to what is set for Property Id "SITEBASE" and not the original in app.config
PS: the Package InstallScope="perMachine"
The short answer is that you're probably correct about the installer running again. It's a feature that if you have a file in a user profile directory (that therefore is installed at first only for that user) and then another user uses the app Windows will notice that the file is missing for that user and install it. Sine the application defines the file as being in a user folder it makes sense for all users to want that file also.
If that's not precisely what's happening, it may also be possible that the installed product is getting broken in some way and Windows is repairing it.
Either way, if you look in the Event log there should be MsiInstaller entries that refer to a missing component, quoting the guid that you can look for in your setup. That may help.
Someone on our team found the problem.
App logs had:
Detection of product '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}', feature 'ProductFeature', component '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}' failed. The resource 'HKEY_CURRENT_USER\Software\XXX\YYY\' does not exist.
Detection of product '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}', feature 'ProductFeature' failed during request for component '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'
Beginning a Windows Installer transaction: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Client Process Id: 19300.
Windows Installer reconfigured the product. Product Name: YYY. Product Version: 1.0.0. Product Language: 1033. Manufacturer: XXX. Reconfiguration success or error status: 0.
Product: YYY -- Configuration completed successfully.
Ending a Windows Installer transaction: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Client Process Id: 19300.
installer creates a registry entry under HKCU. Because this is a per-user setting, it doesn't exist for the next user, so an MSI repair is begun.
Changing it to install to HKLM instead of HKCU looks to have fixed the problem

Elevated installer with elevated custom action does not elevate executable

I have an installer with InstallPrivileges="elevated". I include inside the file table an app.EXE
<Component Id="myapp" Guid="*">
<File Id="myapp" Source="myapp.exe"/>
</Component>
using these CA to run it in an elevcated state:
<CustomAction Id="SetProp" Property="Launch" Value =""[INSTALLDIR]myapp.exe""/>
<CustomAction Id="Launch" BinaryKey="WixCA" DllEntry="CAQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
scheduled like this:
<Custom Action="SetProp" Before="Launch">NOT Installed</Custom>
<Custom Action="Launch" Before="InstallFinalize">NOT Installed</Custom>
but according to Uachelper class (c#) and the missing result this process is not elevated BUT verbose log and myapp.exe log shows no error.
I also tried to use a type 2 custom action (binarykey etc.), a type 18 custom action (filekey etc.) and to include an app.manifest into myapp.exe with requiredadministrator.
nothing worked to elevate myapp.exe.. during installation.
Workaround I found is to start myapp.exe manually after installation completed (go to [INSTALLDIR] and doubleclick myapp.exe, will prompt uac etc.) but I want to avoid that.
I also thought about trying to use runas but am not sure if this would work or if this is feasible.
All of this is based on http://wixtoolset.org/documentation/manual/v3/customactions/qtexec.html , https://stackoverflow.com/a/10028939/4096653 and many more questions here on SO.
What am I missing or what else can I try?
By default a custom action will be elevated only if it is deferred, not impersonated, and sequenced between InstallInitialize and InstallFinalize, and if it's a per machine install, and then it will run elevated with the system account. Whether it will actually work or not depends on whether the code is prepared to deal with being aware that it's not running as the interactive user with access to HKCU, user profile items like PersonalFolder, and the code knows where its data is. When a custom action executable gets fired off it is via the CreateProcess() type of call (NOT a shell execute call) and so there is no UAC dialog/manifest checking stuff going on. So your WiX posted looks correct if you are deferred and before InstallFinalize. I have no idea what a UACHelper class thinks if are running as system and elevated. ProcessMonitor/Explorer might tell you what your rights/tokens are.
It should work if you create an impersonated launcher custom action that does an explicit Shell Execute of your exe, because that behaves like a run from Explorer by the interactive user. It will run the app which will then ask for elevation as long as the user doing the install is admin. In code that's something like ProcessStartInfo.UseShellExecute=true, ShellExecute() Win32.
If you need an impersonated CA to be elevated the MSI needs to be running as administrator or started from a program with an elevation manifest that then runs the MSI.
You'll see lots of advice (I hope) saying you should arrange to run this automatically the first time your app runs, just have it launched and remember whether that it has been run. Running as elevated user from an MSI is too complicated unless you have an elevated launching bootstrapper.
I assume you want this to run in Execute sequence and have scheduled your custom actions in InstallExecuteSequence
It might be so that your app is not able to run as Local system user so try to switch the Impersonate to yes Impersonate="Yes"

Run unelevated custom action from a WiX elevated installer

I'm trying to figure out how to run a custom action from an elevated WiX installation setup program. The msi file generated by WiX is executed by DotNetInstaller.
In WiX I have a Package section with InstallScope set to perMachine and this custom action:
<CustomAction Id='RegisterPlugin' FileKey='RegisterPluginExe' ExeCommand='' Return='asyncNoWait' Impersonate='yes' />
<InstallExecuteSequence>
<Custom Action='RegisterPlugin' After='InstallFinalize'>NOT Installed</Custom>
</InstallExecuteSequence>
Impersonate set to yes should run the action exe as the user who run the DNI bootstrapper.
The custom action should read a file in the user AppData directory, using the value obtained by System.Windows.Forms.Application.LocalUserAppDataPath, but the directory used is wrong because is the one of the Administrator user.
I tried to use a manifest to run DNI unelevated, but the problem remains. If I run the msi directly, it correctly does some registry operations which require administration rights, while the custom action runs as expected.
Edit:
Looking at the task manager I can see that, if the msi is executed from DNI, the user becomes Administrator when the msi is started. If I run the msi directly, the user is always the same, even during the files installation on the system directory. It seems that in this case what change is not the identity, but the privileges.
Any ideas?
Thanks,
Stenio

Why DataDriven tests no longer run on Jenkins when using MSTest?

I have a suite of Webdriver tests which are written with C# and I am using MSTest as a runner. At this point NUnit is not an option, so I need to figure this out how to make it work with the current configuration. For CI I am using Jenkins ver. 1.514. I am not in control of what plugins are being installed or when Jenkins is updated and if asking such a thing might lead to a long wait and approval processes in different teams (hate birocracy).
So.. I have a few DataDriven tests which are defined as follows(i'll paste in one of them)
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "UsersData.csv", "UsersData#csv", DataAccessMethod.Sequential)]
[TestMethod()]
public void Test_Login()
{
Logger.Info("");
Logger.Info("-----------------------------------------------------------------");
So, this should be clear enough that i am using UsersData.csv file, which is placed in TestData folder in my project. To run this test in Jenkins, I used to use this command line
mstest /testmetadata:"%WORKSPACE%\SeleniumJenkins.vsmdi" /testlist:Jenkins /resultsfile:"%WORKSPACE%\AllTests_Jenkins.trx" /runconfig:"%WORKSPACE%\Local.testsettings" /detail:stdout
Everything worked just fine, but one day, when i encountered this error in the TRX results file:
The unit test adapter failed to connect to the data source or to read the data. For more information on troubleshooting this error, see "Troubleshooting Data-Driven Unit Tests" (http://go.microsoft.com/fwlink/?LinkId=62412) in the MSDN Library.Error details: The .Net Framework Data Providers require Microsoft Data Access Components(MDAC). Please install Microsoft Data Access Components(MDAC) version 2.6 or later.Retrieving the COM class factory for component with CLSID {2206CDB2-19C1-11D1-89E0-00C04FD7A829} failed due to the following error: 8007007e The specified module could not be found. (Exception from HRESULT: 0x8007007E).
BUT if i log on the machine where the slave is running and run the same command it seems it finds the DataSource files and ir runs ok.
Moreover, i installed psexec and i placed the command into a *.bat file, then i called this file from ps exec like this:
psexec \\my_IP -u "machine-name\jenkins-local" -p "password" cmd /C call "%WORKSPACE%\Selenium\msteststart.bat"
This seems to be working, but i don't get any Logging into Jenkins and if i redirect it to a file, then whenever another build starts and wipes out the workspace the file is lost, so i only have the last version of the file and i cannot compare it to other builds.
The local.testsettings file looks like this:
<?xml version="1.0" encoding="UTF-8"? >
<TestSettings name="Local" id="06505635-693a-4f31-b962-ecf8422b5eca" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>These are default test settings for a local test run.</Description>
<Deployment>
<DeploymentItem filename="Selenium\TestData\UsersData.csv" />
</Deployment>
<NamingScheme baseName="Selenium_" useDefault="false" />
<Execution>
<Timeouts testTimeout="10800000" />
<TestTypeSpecific>
<UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
<AssemblyResolution>
<TestDirectory useLoadContext="true" />
</AssemblyResolution>
</UnitTestRunConfig>
</TestTypeSpecific>
<AgentRule name="Execution Agents">
</AgentRule>
</Execution>
</TestSettings>
I would appreciate if anyone could give me a hint on this one. Thanks
It could be
an MDAC installation error. E.g. here are some ideas on how to repair it. Consider asking your admin to try to check if MDAC was properly installed.
a permission issue ? are you 100% sure you are running the command on your slave as the same user both using jenkins slave and psexec ?
As you say you manage to get it to work using psexec, a workaround would be to generate the file on the same machine the job is ran and archive the generated log file as artifact. Jenkins will keep track of it.
If you prefer to try to have the output in the console, maybe to apply console parsing, you can also make it that your psexec command outputs the file after the build to the console (by type-ing it after it has run), or maybe use this tee-like batch command to manage to get psexec to output what it does into jenkins console: Using a custom Tee command for .bat file
And don't forget to capture the standard error as well!

WiX Custom Action to check firewall status causes installer to fail

I have implemented a WiX Custom Action in C# to check whether the Windows firewall is on or off.
I tested the code with a C# console application and it worked without problems.
However, when I use the code in a WiX Custom Action it causes the installer to fail at run-time, with the following error in the msiexec error log:
DEBUG: Error 2755: Server returned unexpected error 1622 attempting to
nstall package MyInstaller.msi.
The installer has encountered an unexpected error installing this package.
This may indicate a problem with this package. The error code is 2755.
The arguments are: 1622, MyInstaller.msi,
Action ended 11:26:30: ExecuteAction. Return value 3.
Action 11:26:30: FatalError.
Action start 11:26:30: FatalError.
Action 11:26:30: FatalError. Dialog created
Action ended 11:26:31: FatalError. Return value 2.
Action ended 11:26:31: INSTALL. Return value 3.
Type NetFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", true);
INetFwMgr fwMgr = Activator.CreateInstance(NetFwMgrType) as INetFwMgr;
bool Firewallenabled = fwMgr.LocalPolicy.CurrentProfile.FirewallEnabled;
MessageBox.Show("Firewall enabled: " + Firewallenabled.ToString());
In my WiX XML file the CA is like this:
<CustomAction Id="CheckWindowsFirewallId"
BinaryKey="CustomActions.dll"
DllEntry="CheckWindowsFirewall" Execute="deferred" Impersonate="no" Return="check"/>
<InstallExecuteSequence>
<Custom Action="CheckWindowsFirewallId" After="InstallInitialize">NOT Installed</Custom>
I am using Visual Studio 2005, Windows XP, WiX version 3.6.1321.0
I am logged in as admininstrator.
I know exactly which line causes in the problem.
If I comment out the line with "Activator.CreateInstance(NetFwMgrType)" the error does not occur.
I have tried several different combinations of 'deferred' and 'impersonate' with no success.
If I can't get it to work I will try the WiX Firewall Extension instead, but it would be great if someone has an idea why it doesn't work.
There isn't enough information to know for sure. However, my magic eight ball guesses that the assembly your trying to activate a class out of isn't available. The best thing would be to get a debugger on the code and look at the exception. If you're having trouble doing that, catching the exception and writing it to the log file might be useful as well.
I also agree with Yan's comment above. I'd recommend using the built in support for Firewalls in WiX instead of writing your own code if possible.

Categories

Resources