WIX SQL Server Express SP1 execution in MSI - wix

I am creating a WIX installer, and in my Product.wxs file I am including SQLEXPR_x64_ENU.exe in the products install directory. I am calling the install command via a custom action like this:
<Property Id="SQLEXPRINSTANCENAME" Value="SQLEXPR" />
<CustomAction Id="SqlInstall"
FileKey="SqlInstaller"
ExeCommand="/Q /HIDECONSOLE /ACTION=Install /INSTANCENAME="[SQLEXPRINSTANCENAME]" /IACCEPTSQLSERVERLICENSETERMS /FEATURES=SQLEngine /TCPENABLED=1 /SQLSVCACCOUNT="NT AUTHORITY\Network Service" /SQLSYSADMINACCOUNTS="Builtin\Administrators" /BROWSERSVCSTARTUPTYPE="Automatic" /AGTSVCACCOUNT="NT AUTHORITY\Network Service" /SQLSVCSTARTUPTYPE="Automatic""
Execute="immediate"
Return="check"
Impersonate="yes" />
and later in the execute sequence declaration I have:
<InstallExecuteSequence>
<Custom Action="SchedXmlFile" After="InstallFiles">1=1</Custom>
<Custom Action="SqlInstall" After="InstallFinalize">INSTALLSQLYN = "Yes"</Custom>
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
It runs the installer fine, but SQL Server Express will start to hang, and therefore hang the entire MSI.
If I take this command line and copy it to the command prompt the installation finishes.
The MSI verbose logging option does not indicate anything and there is no summary file for the SQL Server install Log.
So I am basically stuck not knowing why the installer gets stuck, and I have no idea what to do!
If somebody knows a simpler way of including the installer to an MSI let me know? Or if you can help me figure out why it fails? I did not bootstrap it (that works but doesn't allow me UI to question the user to install SQL or not, know how to conditionally run exepackage from a confirmation dialog in the bootstrapper?). I intend on chaining this MSI I am making into a bootstrapper for my products installer.

You cannot run another installer from within an msi as it will already have an open transaction. You will need to use a bootstrapper to check for and install SqlExpress before your msi is run.
Check out the bundle/burn docs here.

What worked for me was running SQL Server Express 2008 R2 SP1 installer from C# immediate custom action within my own installer. The custom action started new process - that sql express installer executable with command line parameters. See example below. This worked on Windows Server 2008 and Win7.
The problem here is that for Windows 8 \ Server 2012 you will need SQL Server Express 2008 R2 SP2 because SP1 throws "known compatibility issues" warnings. And in SP2 they changed the installer so that it hangs on ExecuteStandardTimingsWorkflow step. This is the major blocker for me at the moment.
using (var myProcess = new Process
{
StartInfo =
{
FileName = prcssFilePath /*path to the SQLEXPR_x64_ENU.exe or SQLEXPR32_x86_ENU.exe*/,
Arguments = cmdLineArgs ?? string.Empty,
WindowStyle = (hideWnd) ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal
}
})
{
if (runAsAdministrator)
{
myProcess.StartInfo.Verb = "runas";
}
myProcess.Start();
myProcess.WaitForExit();
return myProcess.ExitCode;

Related

Executing wix msi custom actions as system

I am using WIX to build a an MSI that will be executed as a regular user but with system privileges (AlwaysInstallElevated=1). I have defined two Custom Actions that execute net.exe.
The net.exe commands are not getting executed as a regular user. I have also tested executing this msi as an Administrator and the net.exe commands are getting executed.
I have logged the msi output and I see error codes that lead me to believe that the net.exe commands are not being executed elevated. I'm reaching out to the community to see if
What I'm trying to do is possible
Do I need to instead use an exe as a custom action in order for the exe to install elevated.
Thanks in advance for the feedback.
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe user TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command1">Command1</CustomAction>
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe localgroup Administrators TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command2">Command2</CustomAction>
<InstallExecuteSequence>
<Custom Action="Command1" After="PublishProduct">NOT Installed</Custom>
<Custom Action="Command2" After="Command1">NOT Installed</Custom>
</InstallExecuteSequence>
Machine Policy and User policy allows for msis to be executed as system.
MSI (c) (DC:F8) [09:17:39:438]: Machine policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: User policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: Running product '{34ED8E61-40EA-47CE-95E7-8EE3CDBCB1E8}' with elevated privileges: All apps run elevated.
Errors
MSI (s) (8C:8C) [20:39:18:989]: Executing op: ActionStart(Name=Command1,,)
MSI (s) (8C:8C) [20:39:18:989]: Executing op: CustomActionSchedule(Action=Command1,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe user TestUser /add,)
CustomAction Command1 returned actual error code 2 but will be translated to success due to continue marking
MSI (s) (8C:8C) [20:39:19:535]: Executing op: ActionStart(Name=Command2,,)
MSI (s) (8C:8C) [20:39:19:535]: Executing op: CustomActionSchedule(Action=Command2,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe localgroup Administrators TestUser /add,)
CustomAction Command2 returned actual error code 1 but will be translated to success due to continue marking
Even in an install started by an administrator the impersonated custom actions run without elevation. So the answer is your number 2. start the install from an elevated process with a CreateProcess-type of initiation. Having said that, it's not clear to me why you can't run the CA deferred with no impersonation because there seems to be nothing that requires the user to be an actual user as opposed to the system account. So the failure might not be elevation, and that's the issue with passing the task off to a program that isn't going to give you good error messages. So....
I've seen boilerplate code to do this kind of thing, and I believe WiX has it anyway, the Util User element, that may be the way to go.
Like Phil says, don't use net.exe to create users. Use WiX's built in features to do so (I should have found a better sample but don't have time right now):
http://wixtoolset.org/documentation/manual/v3/xsd/util/user.html
https://www.firegiant.com/wix/tutorial/com-expression-syntax-miscellanea/new-user-on-the-block/
My first instinct would be that the AlwaysInstallElevated policy would be misconfigured, but judging from the log file it is set correctly. I am rusty, but the impersonation looks like it is correctly set to "no" Phil? And the scheduling is deferred and seemingly placed right before InstallFinalize - seems OK off the top of my head.
Could it be that net.exe cannot be run properly as LocalSystem? Why then would it work when the installation is kicked off as Administrator? One would think LocalSystem had all required privileges. Isn't the current user's access token attached to the msiexec.exe process somehow? (for logging purposes or something). Or could it be a privilege that the Administrator account has that LocalSystem does not? How would that privilege apply if there is no impersonation? Did you try to manually launch net.exe as a regular user? What errors do you get when attempting to create a user when running as a regular user?
In either case I wouldn't waste my time running EXE custom actions if there is an alternative. I don't remember the last time I did. I normally use VBScript, C++ and earlier I used Installscript - with all its archaic syntax. Just switch to the built-in WiX constructs and you should be fine.

Run ExeCommand in customAction as Administrator mode in Wix Installer

I am new to wix installer. I have developed a set-up using wix installer for my application and I need to execute a Custom Action to run a command in cmd.exe. In XP it works fine. But in Windows 8 & 7 the cmd prompt needs to be run as administrator.
I have googled and found the keywords Elevated Privileges and impersonate might help me.
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"></Package>
As you can see above, I used the InstallScope attribute set to perMachine, and I have used Impersonate="No" in the CustomAction element:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Impersonate='no'
ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]myProduct.dll" /codebase' Return='check' />
But I didn't get any changes while installating. I need the command prompt to open and run the above command in Administrator Mode.
And can anyone please tell me about these keywords "Elevated Privileges & impersonate"
<InstallExecuteSequence>
<Custom Action='comReg' After='InstallFinalize'>NOT REMOVE</Custom>
<Custom Action='comUnreg' Before='RemoveFiles'>REMOVE</Custom>
</InstallExecuteSequence>
How to do it?
The wix documentation here explains the Impersonate attribute:
This attribute specifies whether the Windows Installer, which executes as LocalSystem, should impersonate the user context of the installing user when executing this custom action. Typically the value should be 'yes', except when the custom action needs elevated privileges to apply changes to the machine.
You also need to understand the difference between deferred and immediate custom actions. See the Execute attribute on the same help page:
This attribute indicates the scheduling of the custom action. This attribute's value must be one of the following:
deferred
Indicates that the custom action runs in-script (possibly with elevated privileges).
immediate
Indicates that the custom action will run during normal processing time with user privileges. This is the default.
At present your custom action is immediate, which means it is running with user privileges. See this blog post for lots of details, but particularly:
Any immediate custom actions impersonate the invoking user. Before Windows Vista this wasn't a problem since at this point the installing administrative user had a privileged token. With the introduction of UAC in Windows Vista the default administrative token with UAC enabled is a filtered token and does not hold all privileges. Since immediate custom actions are not supposed to modify machine state - only to gather state data and schedule custom actions to run deferred - this still shouldn't be a problem. After all, at this point the generation of the installation and rollback scripts is all that should be going on.
You should never modify machine state with an immediate custom action. Use a deferred one, and keep impersonate to no, and it should work:
<CustomAction Id='comReg' Directory='INSTALLLOCATION' Execute='deferred' Impersonate='no' ExeCommand='"[NETFRAMEWORK40CLIENTINSTALLROOTDIR]regasm.exe" "[INSTALLLOCATION]EAWordImporter.dll" /codebase' Return='check' />
EDIT: Schedule the custom action using the InstallExecuteSequence element:
<InstallExecuteSequence>
<Custom Action='comReg' Before='InstallFinalize'/>
</InstallExecuteSequence>

PerUser install with Custom Action - UAC disabled

I'm using WiX to generate an MSI that installs a browser plugin on a perUser basis. I have a custom action to install a driver using DPInst (which needs elevated privileges).
The install works fine when UAC is enabled; Windows shows the prompt to elevate. However, if I have UAC disabled and try to install on a regular user account, dpinst.exe will get spawned until the computer freezes. (About a thousand times at last count).
In the <InstallExecuteSequence> I have:
<Custom Action="Install_Drivers" After="InstallFiles">NOT Installed</Custom>
My custom action is:
<CustomAction Id='Install_Drivers' Execute='deferred' Directory='DRIVERS' ExeCommand='"[DRIVERS]DPinst.exe" /SW /SA' Return='ignore' Impersonate='no'/>
I have Return='ignore' because, from what I understand so far, dpinst.exe always returns a non-0 code.
How can I ensure that the custom action fails correctly when UAC is disabled? On a related note, can I show a custom message to the user when the driver installation fails?
Further Information: I'm developing on Windows 7 currently, but targeting WinXP and up.
Edit Taking a look at the log for the installation these seem to be the relevant lines:
Executing op: CacheSizeFlush(,)
Executing op: ActionStart(Name=Install_Drivers,,)
Executing op: CustomActionSchedule(Action=Install_Drivers,ActionType=3170,Source=C:\long_redacted\Drivers\,Target="C:\long_redacted_path\Drivers\DPinst.exe" /SW /SA,)
Disallowing shutdown. Shutdown counter: 0
CustomAction Install_Drivers returned actual error code 1073807364 but will be translated to success due to continue marking
The bit about the shutdown is, I believe, when I logged off stop the installation. (Canceling doesn't seem to have any effect).
Try setting the 'Impersonate=no' attribute on the 'CustomAction' element, like this:
<CustomAction Id='Install_Drivers' Execute='deferred' Directory='DRIVERS' ExeCommand='[DRIVERS]DPinst.exe" /SW /SA' Return='ignore' Impersonate="no" />
Also note: you have a stray double-quote in your ExeCommand
Installing a driver is an inherently per-machine operation. A limited user can't do it. So with UAC disabled, it's not going to work. DPInst apparently doesn't get the hint that it doesn't have permissions and can't get them. Sounds like a bug in DPInst. You should change your installer to be per-machine and add a launch condition on the Privileged property to prevent the installer from starting for limited users without UAC.

Why doesn't this silent launch work in WIX?

I have the following command running at the end of my package install for an application.
<Property Id="WixShellExecTarget" Value="[INSTALLDIR]RCR.VDS.exe" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA"
DllEntry="WixShellExec" Impersonate="no" />
I can't use [#myApplication] because I run heat on my output folder on my build server so I don't know the auto generated id of my application. Any ideas on how to silently run my application after the install?
The log file shows this for the command line section
******* CommandLine: **********
MSI (c) (30:74) [09:47:14:156]: Note: 1: 2203 2: VDSInstall.msi 3: -2147287038
MSI (c) (30:74) [09:47:14:156]: MainEngineThread is returning 2
Please see: How To: Run the Installed Application After Setup
If you want the custom action called during a silent install add:
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">SOMECONDITION</Custom>
</InstallExecuteSequence>
Note SOMECONDITION should be an expression that checks the EXE is installed and the user wants the program to be launched.
The are a copy things you can consider:
The identifier from heat.exe will be stable. So you can use the ugly identifer in your [#UglyFileId1234abcef45612345asdf] custom action.
a. You could also apply a XSLT to transform the heat output for the executable file's Id to something nicer than the ugly identifier. Depends how readable you want the launch custom action to be.
If you want the executable launched silently then you'll probably want the Quite Execution custom action instead of the Shell execute custom action that "LaunchApplication" uses.

Set environment variable before running a custom action in WiX

I have to build an MSI-based installer using WiX and I need to set environment MY_HOME before running a command action.
I have a component:
<Component Id="SEMYHOME"
Guid="*my guid*">
<CreateFolder />
<Environment Id="MY_HOME"
Action="set"
Part="all"
Name="MY_HOME"
Permanent="no"
System="yes"
Value="[APPLICATIONPATH]myapp"/>
</Component>
Then I have a custom action:
<CustomAction Id="InstallMyService"
Directory="INSTALLDIR"
ExeCommand='"[INSTALLDIR]myapp\install_service.bat" install'
Execute="immediate"
Return="ignore"/>
<InstallExecuteSequence>
<Custom Action="InstallMyService"
After="InstallFinalize"/>
</InstallExecuteSequence>
NOTE: This action need the MY_HOME variable to be set before running.
When install this MSI, I got a log showing that the MY_HOME variable is set before running the custom action "InstallMyService", but the command to install my service still fails. I found that the cause is when command called, MY_HOME still not set.
After an install is finished, MY_HOME was set as expected, but the custom action fails :(
How can I fix this problem?
Windows Installer and Custom Actions are hosted via the Service Control Manager which has a long history of not respecting broadcast messages that are sent announcing Environment changes. So even if you fix the immeadiate / deferred problem that Yan mentions you'll find that your custom action still doesn't have the environment variable.
Why don't just just pass "[APPLICATIONPATH]myapp" to your .bat file and fetch it in as %2?
BTW I also don't reccomend calling batch files from an installer. It's fragile and embarrassing to see installs that run popping up little black windows.
You CA is immediate. This means that it runs immediately when Windows Installer is processing your MSI package. And this obviously happens before the component containing <Environment/> is installed. Modify it to be deferred (Execute="deferred") and schedule before InstallFinalize.