There are multiple questions on that topic, I tried all the solutions but nothing worked for me.
The problem is that it 'does' work on machines with visual studio installed, but does not work on other pc's.. making it very hard to debug.
The custom action code is:
[CustomAction]
public static ActionResult EnumerateSqlServers(Session session)
{
MessageBox.Show("start EnumerateSQLServers"); // the message is not showing.
ActionResult result;
DataTable dt = SmoApplication.EnumAvailableSqlServers(false);
DataRow[] rows = dt.Select(string.Empty);//, "IsLocal desc, Name asc");
result = EnumSqlServersIntoComboBox(session, rows);
return result;
}
The log file shows:
MSI (c) (2C:1C) [11:16:42:338]: Doing action: EnumerateSqlServersAction
Action 11:16:42: EnumerateSqlServersAction.
Action start 11:16:42: EnumerateSqlServersAction.
MSI (c) (2C:34) [11:16:42:385]: Invoking remote custom action. DLL: C:\Users\Test\AppData\Local\Temp\MSI9328.tmp, Entrypoint: EnumerateSqlServers
MSI (c) (2C:E8) [11:16:42:385]: Cloaking enabled.
MSI (c) (2C:E8) [11:16:42:385]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (2C:E8) [11:16:42:385]: Connected to service for CA interface.
Action ended 11:16:42: EnumerateSqlServersAction. Return value 3.
DEBUG: Error 2896: Executing action EnumerateSqlServersAction failed.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2896. The arguments are: EnumerateSqlServersAction, ,
Action ended 11:16:42: WelcomeDlg. Return value 3.
MSI (c) (2C:44) [11:16:42:635]: Doing action: FatalError
Action 11:16:42: FatalError.
Action start 11:16:42: FatalError.
Action 11:16:42: FatalError. Dialog created
Action ended 11:16:43: FatalError. Return value 2.
Action ended 11:16:43: INSTALL. Return value 3.
MSI (c) (2C:44) [11:16:43:370]: Destroying RemoteAPI object.
MSI (c) (2C:E8) [11:16:43:385]: Custom Action Manager thread ending.
I did try a empty action like this:
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
MessageBox.Show("");
return ActionResult.Success;
}
that action works! it shows an empty message box.
EDIT: After a lot of testing, I found that the problem is with enumSQLServer when I comment this line it works.
SmoApplication.EnumAvailableSqlServers(false);
Log the installer using verbose (/l*v) settings. I expect to see a lot more including a .NET error stack trace. You are likely missing a dependency that's on the visual studio machine but not your clean test machine.
The most likely missing dependency is Microsoft.SqlServer.Smo.dll. In your custom action project check to see if this reference is set to CopyLocal = true and set it if it is not.
Did you already try to run your setup with elevated rights (right click on the setup and select "Run as administrator")?
SmoApplication.EnumAvailableSqlServers(false) needs elevated rights as far as I know.
Also check your definition of your custom action in your Product node within your .wxs file.
Following definition should work:
<CustomAction
Id="EnumerateSqlServers"
BinaryKey="YOUR BINARY KEY"
DllEntry="EnumerateSqlServers"
Execute="immediate"
Return="check"/>
Also try the following for testing purposes:
<InstallUISequence>
<Custom Action="EnumerateSqlServers"
Before="ExecuteAction"
Overridable="yes">NOT Installed</Custom>
</InstallUISequence>
In my case, this was happening on the install AND uninstall.
What we're doing is encrypting the connection string that was being passed in as a parameter.
Install
This fails because I don't have access to the installed config file which we're still working out. I wish WiX was a little easier to use or had better documentation.
Uninstall
Because we didn't have any conditions for the Custom Action, it was also running during uninstall and failing when attempting to load the config file that doesn't exist anymore.
Solution: Use NOT Installed AND NOT REMOVE. How to execute custom action only in install (not uninstall)
Related
I'm trying to quietly install a .msi file using C# without the need for any user input. I'm having trouble trying to get past the license agreement so that the installation can continue. Is there a way to pass an argument so that the agreement is accepted without any user imput?
Caution: I would avoid triggering software installation from within an application binary - unless you are making an actual setup launcher application. It can work, but it may trigger serious problems with anti-virus and malware scanners. I have seen that before. I would assume you would also need to run elevated - with admin rights - to kick off your installs (per-machine installations).
Some digressions and suggestions first: MSI can be installed via msiexec.exe commands, Powershell, DTF C# (see below), WMI, MSI API (COM, Win32).
Batch: With that said, why don't you just install using a regular batch file? The /QN switch will bypass the entire setup GUI-sequence and then there should be no need to accept any license agreements. MSI logging information (short version: open log and search for "value 3" to find errors).
This command must be run from an elevated command prompt (admin rights):
msiexec.exe /I "Installer.msi" /QN /L* "C:\msilog.log" ALLUSERS=1
Setup.exe: You can also make a WiX Burn bundle (see link for code mockup) or use some sort of other tool to make a setup.exe that will install your original application and then other components in sequence - so there is nothing to trigger to install from the application.
Interactive Install: If you want to install with some user interaction you can locate the property controlling the accept status of the license agreement and set that to the appropriate value - usually 1 - to indicate accepted license.
DTF: Now the code answer. There is a component installed with the WiX toolkit called DTF - Desktop Tools Foundation It has a number of C# classes designed to deal with MSI files via managed code. This answer explains what file to add as a reference in Visual Studio and describes the different files / assemblies of DTF briefly. Another DTF sample.
The relevant file for your described purpose is: "Microsoft.Deployment.WindowsInstaller.dll".
NOTE!
You must launch Visual Studio with admin rights to install per machine.
Add project reference to "%ProgramFiles(x86)%\WiX Toolset v3.11\bin\Microsoft.Deployment.WindowsInstaller.dll".
The below code tested in VS2017 (a more elaborate version with admin check here - zipped):
using System;
using Microsoft.Deployment.WindowsInstaller;
// RUN WITH ADMIN RIGHTS
namespace DTFTest
{
class Program
{
static void Main(string[] args)
{
try
{
Installer.SetInternalUI(InstallUIOptions.Silent);
Installer.EnableLog(InstallLogModes.Verbose, #"E:\Install.log");
Installer.InstallProduct(#"E:\Install.msi", "");
}
catch (Exception ex)
{
Console.WriteLine("Exception:\n\n " + ex.Message);
}
}
}
}
Link:
On reboot initiated issues
Install via VBScript COM, DTF, Win32
Generally you just run the msi silently like
msiexec /i foo.msi /qn
If the MSI has implemented an additional consent you might have to pass a property like
msiexec /i foo.msi /qn ACCEPTEULA=1
The exact name of this property would depend on the MSI so you'd need to consult vendor documentation or examine the MSI using a tool such as ORCA.
We have a Windows 10 1607 image with our app installed via Advanced Installer.
We then updated the app to a new version and the update worked as excepted.
However if we do the same procedure but with a Windows 10 1703 image, the upgrade of our app fails with the following error:
MSI (s) (58:B8) [16:12:02:846]: Note: 1: 2769 2: ShopInstallClass_x64 3: 1
Error 1001. Error 1001. The specified service has been marked for deletion
Info 2769. Custom Action ShopInstallClass_x64 did not close 1 MSIHANDLEs.
CustomAction ShopInstallClass_x64 returned actual error code 1603 (note this
may not be 100% accurate if translation happened inside sandbox)
MSI (s) (58:EC) [16:12:02:858]: Note: 1: 2265 2: 3: -2147287035
MSI (s) (58:EC) [16:12:02:860]: User policy value 'DisableRollback' is 0
MSI (s) (58:EC) [16:12:02:860]: Machine policy value 'DisableRollback' is 0
Action ended 16:12:02: InstallExecute. Return value 3
The custom action above refers to a windows service which is being uninstalled and then reinstalled with the new update. I tried putting a stop service and even a stop process to see if that would work (possibly handles left open) and the installer still did not work.
Any ideas why this is happening?
The code in the custom action has crashed, I assume you know that. Without showing more of the log it's also not clear where in the upgrade it's happening, if in fact you're referring to a major upgrade when you say "update". In a major upgrade there's an install of the new product and an uninstall of the older one - where is this crash happening in that sequence? It's also possible that your ShopInstall class is an installer class to install a service, which isn't necessary because Windows Installer has ServiceInstall actions for that.
Having said that, the message "The specified service has been marked for deletion" implies that the code is trying to do something to a disabled service. So it looks like a previous uninstall of the service has been attempted, and the service did not shut down or stop correctly. In that situation Windows will mark the service disabled and then a reboot will finally delete it. In the meantime if something tries to do something with that service it will fail with the "pending deletion" error. So you'd have to go back to whatever uninstall was attempted and why it failed to first stop, and then uninstall the service.
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
I am using the script from this answer https://stackoverflow.com/a/1681410/22 to insert a launch application checkbox at the end of the MSI installer.
Everything builds ok and I get the launch checkbox just fine, however the application does not launch when the installer is complete.
Not sure if this is the cause but my app does require admin (app.manifest)
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Installer Build Output:
------ Starting pre-build validation for project 'MyAppInstaller' ------
------ Pre-build validation for project 'MyAppInstaller' completed ------
------ Build started: Project: MyAppInstaller, Configuration: Release ------
Building file 'C:\path\to\MyAppInstaller.msi'...
Packaging file 'MyApp.exe'...
Packaging file 'Icon.ico'...
Starting post-build events...
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
Updating the Control table...
Updating the ControlEvent table...
Updating the CustomAction table...
Updating the Property table...
Done Adding Additional Store
Successfully signed: MyAppInstaller.msi
Edit:
If I right click the setup project in Visual Studio and select "Install". The app runs when the installer closes.
However, if I just double click the generated MSI. The app will not open after the MSI closes.
I've also tried to change the custom action to this, but I still get the same results:
sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch', '226', 'TARGETDIR', '[TARGETDIR]\\MyApp.exe')";
Update:
I ended up using a slightly modified version of "DJ KRAZE" answer. In my Main method I check for a "frominstaller" argument and then just launch the app in a new process and exit. Which then allows the installer to continue normally. Then I add the exe in the "Install" custom action with the "/frominstaller" argument.
if (frominstaller)
{
Process p = new Process();
p.StartInfo.FileName = System.Reflection.Assembly.GetExecutingAssembly().Location;
p.Start();
Application.Exit();
}
Have you tried these steps as listed in the post from the link that you referenced..?
To run any application after the installation is complete, right-click on your setup project, click on Custom Actions. Then right-click on Commit, Add Custom Action, and choose the file you would like to run. Note that it has to be in your application folder already, which shouldn't be a problem in your case since you are running your program anyway. Simply choose the output of your project.
Then, click on this added .exe, and change InstallerClass to false. This is crucial because it will look for an installer program otherwise.
You could even pass parameters to your .exe by adding them to the Arguments property
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.