Suppress Custom Action EXE
Hi all,
finally starting to somewhat get a hang of Windows Installer.I have a custom action that runs an executable in the system32 directory (ServerManagercmd.exe) to install IIS. My conditions are fine as it is running however I'd this executable brings up a cmd-prompt progress window. I'm wondering if there's a way to suppress it?
finally starting to somewhat get a hang of Windows Installer.I have a custom action that runs an executable in the system32 directory (ServerManagercmd.exe) to install IIS. My conditions are fine as it is running however I'd this executable brings up a cmd-prompt progress window. I'm wondering if there's a way to suppress it?
1 Comment
[ + ] Show comment
-
what is the answer for it? - naveenkumarm 11 years ago
Answers (20)
Please log in to answer
Posted by:
spartacus
15 years ago
Seems like a good time to post and article I wrote on this subject some time ago. It is geared towards InstallShield users, but can easily be adapted for WISE &c.
Background
From time to time it is convenient to create a custom action that calls (say) an executable that is already part of the Operating System but which runs in the COMMAND subsystem. One example might be to call the NET.EXE executable to stop a service (OK, I know it's not a great example as you should be using the ServiceControl table here [;)])
The custom action might, for example, call NET.EXE as follows :
C:\Windows\System32\NET.EXE STOP SPOOLER
The problem with commands like these is that when the Custom Action executes, a command window usually appears on the screen and, besides generally looking untidy, may cause confusion to the end user during installation.
This article outlines a method that can be used to invoke the executable to run under the Windows subsystem and not the Command subsystem and thereby avoids the appearance of the command window.
Method
The method devised makes use of wixca.dll, a DLL supplied in the WiX toolset. If you don't already have it you can download the full WiX tookit from this link
http://sourceforge.net/project/downloading.php?group_id=105970&use_mirror=garr&filename=wix-2.0.5805.0-binaries.zip&85039060
We only need the one DLL from the toolkit, so use WinZip or similar to extract the wixca.dll file from the download.
1) Now establish what the exact command is you wish to run. The command must contain a quoted path to the executable, followed (optionally) by any parameters.
For example, if we wish to stop the Print Spooler service, the command would be :
"C:\Windows\System32\NET.EXE" STOP SPOOLER
2) In your package, create a property named QtExecCmdLine and set the value of this property to the command line in exactly the format shown above.
3) In InstallShield editor, launch the custom action wizard, Click Next then assign the custom action a name plus (optionally) any comments. In my example I will name the custom action StopSpooler and leave the comments blank
4) Click Next, then in the Type field select "Call a function in a Windows Installer dynamic-link library" and click Next
5) In the source field browse to the wixca.dll file you extracted earlier. In the target field enter CAQuietExec then click Next
6) Leave the Return Processing field as Synchronous(Check Exit Code) and click Next
7) Leave the In-Script Execution as Immediate Execution and Execution Scheduling as "Always Execute" and click Next
8) Leave the Install UI Sequence as <Absent from Sequence> and set the Install Execute Sequence field to the desired position in the sequence (e.g. just before InstallFinalize). Apply any Install Execute conditions you need to (e.g. NOT REMOVE~="ALL") then click Next.
9) Click Finish.
Thats all there is to it. When the CA runs, you will no longer see a command box, but with verbose logging enabled you will be able to see any output the command created in the MSI log file - very useful for troubleshooting !
Deferred Mode
If you wish to run your command in deferred mode, then at step 2, enter a property name of your own choice to hold the command string and make sure (at Step 3) that your custom action is named the same as the property name you chose. This will then instruct the DLL to use the CustomActionData method to determine the command line it needs to execute.
(Dont forget to place the custom action between InstallInitialize and InstallFinalize)
Further information can be found at the following link :
http://wix.sourceforge.net/manual-wix2/qtexec.htm
Regards,
Spartacus
Background
From time to time it is convenient to create a custom action that calls (say) an executable that is already part of the Operating System but which runs in the COMMAND subsystem. One example might be to call the NET.EXE executable to stop a service (OK, I know it's not a great example as you should be using the ServiceControl table here [;)])
The custom action might, for example, call NET.EXE as follows :
C:\Windows\System32\NET.EXE STOP SPOOLER
The problem with commands like these is that when the Custom Action executes, a command window usually appears on the screen and, besides generally looking untidy, may cause confusion to the end user during installation.
This article outlines a method that can be used to invoke the executable to run under the Windows subsystem and not the Command subsystem and thereby avoids the appearance of the command window.
Method
The method devised makes use of wixca.dll, a DLL supplied in the WiX toolset. If you don't already have it you can download the full WiX tookit from this link
http://sourceforge.net/project/downloading.php?group_id=105970&use_mirror=garr&filename=wix-2.0.5805.0-binaries.zip&85039060
We only need the one DLL from the toolkit, so use WinZip or similar to extract the wixca.dll file from the download.
1) Now establish what the exact command is you wish to run. The command must contain a quoted path to the executable, followed (optionally) by any parameters.
For example, if we wish to stop the Print Spooler service, the command would be :
"C:\Windows\System32\NET.EXE" STOP SPOOLER
2) In your package, create a property named QtExecCmdLine and set the value of this property to the command line in exactly the format shown above.
3) In InstallShield editor, launch the custom action wizard, Click Next then assign the custom action a name plus (optionally) any comments. In my example I will name the custom action StopSpooler and leave the comments blank
4) Click Next, then in the Type field select "Call a function in a Windows Installer dynamic-link library" and click Next
5) In the source field browse to the wixca.dll file you extracted earlier. In the target field enter CAQuietExec then click Next
6) Leave the Return Processing field as Synchronous(Check Exit Code) and click Next
7) Leave the In-Script Execution as Immediate Execution and Execution Scheduling as "Always Execute" and click Next
8) Leave the Install UI Sequence as <Absent from Sequence> and set the Install Execute Sequence field to the desired position in the sequence (e.g. just before InstallFinalize). Apply any Install Execute conditions you need to (e.g. NOT REMOVE~="ALL") then click Next.
9) Click Finish.
Thats all there is to it. When the CA runs, you will no longer see a command box, but with verbose logging enabled you will be able to see any output the command created in the MSI log file - very useful for troubleshooting !
Deferred Mode
If you wish to run your command in deferred mode, then at step 2, enter a property name of your own choice to hold the command string and make sure (at Step 3) that your custom action is named the same as the property name you chose. This will then instruct the DLL to use the CustomActionData method to determine the command line it needs to execute.
(Dont forget to place the custom action between InstallInitialize and InstallFinalize)
Further information can be found at the following link :
http://wix.sourceforge.net/manual-wix2/qtexec.htm
Regards,
Spartacus
Posted by:
shweta_kar
15 years ago
Posted by:
anonymous_9363
15 years ago
Posted by:
jayteeo
15 years ago
Thanks for responding guys.. VBScab was correct in saying that the custom action is running an EXE from its destination. I did as suggested write a VBScript to run the install, however the install fails. Strangely even when I tell it to ignore the exit code and to run asynchronously.
Here is my script:
'Create Shell Object
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
'Set Style Property
Dim WindowStyle
WindowStyle = 4 '0 for hidden, 4 to show it
Dim intExitCode
Dim Executable, Parameters
Executable = "ServerManagerCmd.exe"
Parameters = "-install Web-Server"
intExitCode = WshShell.Run(Executable & " " & Parameters, _
WindowStyle, True)
When I run it from cscript, it actually runs fine. The verbose logging doesn't tell me anything besides that the script did not run successfully. Do you guys see something in my script that WISE would complain about? I will read the article linked above. TIA.
Here is my script:
'Create Shell Object
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
'Set Style Property
Dim WindowStyle
WindowStyle = 4 '0 for hidden, 4 to show it
Dim intExitCode
Dim Executable, Parameters
Executable = "ServerManagerCmd.exe"
Parameters = "-install Web-Server"
intExitCode = WshShell.Run(Executable & " " & Parameters, _
WindowStyle, True)
When I run it from cscript, it actually runs fine. The verbose logging doesn't tell me anything besides that the script did not run successfully. Do you guys see something in my script that WISE would complain about? I will read the article linked above. TIA.
Posted by:
jayteeo
15 years ago
Posted by:
anonymous_9363
15 years ago
Why on earth you are making this more complicated escapes me but anyway...
Change this:
Change this:
Set WshShell = WScript.CreateObject("WScript.Shell")
to this:Set WshShell = CreateObject("WScript.Shell")
You cannot use the WScript directive, as it is unique to Window Scripting Host, whereas the Windows Installer engine has its own host for VBScript.
Posted by:
jayteeo
15 years ago
Posted by:
spartacus
15 years ago
ORIGINAL: jayteeo
Sparticus - Appreciate your response. Would rather avoid having to include additional files (i.e. the WiX DLL you mentioned).
Just to clarify, the WiX DLL will not be deployed to the target system *permanently* if used in the method I described. It is just a resource that sits in the Binary table of the package. During installation, it will be extracted to a temporary folder when needed by the custom action and then discarded.
Also, last time I looked, it was about 110 KBytes, so the impact on the overall size of the MSI would also be minimal should you decide to use it.
Regards,
Spartacus
Posted by:
jayteeo
15 years ago
Posted by:
anonymous_9363
15 years ago
What should I do to make it less complicated?You could always prefix your command with opening a CMD window but with the '/C' switch. Thus, the command window would open, kick off the EXE, then exit immediately. You'd see a DOS window briefly but not for the duration of the EXE's execution.
Also, you can install IIS using the same command string that 'Control Panel\Add/Remove Programs\Add/Remove Windows Components' does (using sysocmgr.exe) but silently. http://technet.microsoft.com/en-us/library/cc758047.aspx
Posted by:
jayteeo
15 years ago
Hi VBScab,
One of the first things I tried was calling cmd.exe with the /c switch. This would only work if the executable being called does not open its own cmd-style window (which ServerManagerCmd.exe does).
Additionally, sysocmgr is not a good option for our intentions. This MSI package not only will install IIS but also install the FTP component, which is dependent on IIS being installed. Sysocmgr exits immediately after execution while IIS installs in the background thus the FTP install will not be blocked and execute immediately which results in an error.
One of the first things I tried was calling cmd.exe with the /c switch. This would only work if the executable being called does not open its own cmd-style window (which ServerManagerCmd.exe does).
Additionally, sysocmgr is not a good option for our intentions. This MSI package not only will install IIS but also install the FTP component, which is dependent on IIS being installed. Sysocmgr exits immediately after execution while IIS installs in the background thus the FTP install will not be blocked and execute immediately which results in an error.
Posted by:
jayteeo
15 years ago
K.. I made the assumption that my vbscript would work but am getting an unexpected error.
Error 1720. There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. Custom action Instasll_IIS_7 script error -2147024894, : Line 14, Column 1,
I've been pulling my hair out on this one..what does it not like about the script?
'Create Shell Object
'Set Style Property
Dim WindowStyle
WindowStyle = 4 '0 for hidden, 4 to show it
Dim intExitCode
Dim Executable, Parameters
Executable = "ServerManagerCmd.exe"
Parameters = "-install Web-Server"
Set WshShell = CreateObject("WScript.Shell")
intExitCode = WshShell.Run("C:\Windows\System32\ServerManagerCmd.exe -install Web-Server", 4, True)
Also, I was getting a different error before. Something to the effect of WshShell was not an object instance ("object needed for WshShell"). I got around this error by removing my variable declartion in the beginning of the script. Why does Wise complain when I explicitly declare WshShell?
PS - I do realized there are some unused variables there, this was due to me trying to fix the problem I'm encountering
Error 1720. There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. Custom action Instasll_IIS_7 script error -2147024894, : Line 14, Column 1,
I've been pulling my hair out on this one..what does it not like about the script?
'Create Shell Object
'Set Style Property
Dim WindowStyle
WindowStyle = 4 '0 for hidden, 4 to show it
Dim intExitCode
Dim Executable, Parameters
Executable = "ServerManagerCmd.exe"
Parameters = "-install Web-Server"
Set WshShell = CreateObject("WScript.Shell")
intExitCode = WshShell.Run("C:\Windows\System32\ServerManagerCmd.exe -install Web-Server", 4, True)
Also, I was getting a different error before. Something to the effect of WshShell was not an object instance ("object needed for WshShell"). I got around this error by removing my variable declartion in the beginning of the script. Why does Wise complain when I explicitly declare WshShell?
PS - I do realized there are some unused variables there, this was due to me trying to fix the problem I'm encountering
Posted by:
anonymous_9363
15 years ago
-2147024894 converts to 'FFFFFFFF80070002' in hex. Throw away the junk and we get down to '2'. DOS error 2 equates to 'File not found', probably because it's looking for a file called "C:\Windows\System32\ServerManagerCmd.exe -install Web-Server". You need to alter the command line you're running.
Once again, my assertion that QAD scripts will always catch out the unsuspecting is vindicated. If you had built in proper error-trapping from the beginning, your script would check for the existence of 'C:\Windows\System32' then for 'ServerManagerCmd.exe' before attempting to run the EXE. In that process you would end up with variables which you could re-use in your command line.
Once again, my assertion that QAD scripts will always catch out the unsuspecting is vindicated. If you had built in proper error-trapping from the beginning, your script would check for the existence of 'C:\Windows\System32' then for 'ServerManagerCmd.exe' before attempting to run the EXE. In that process you would end up with variables which you could re-use in your command line.
Posted by:
jayteeo
15 years ago
You are correct- I was able to figure out the error and the root cause of the problem. Once I had gotten the script working, I had intended on catching the exit code and the standard/error output of running the script. If the script fails, display the oerror output in a dialog box.
ServerManagerCmd actually does reside in System32. However, I am running this on a 2k8 box. The problem is MSIExec runs under the 32-bit subsystem whose System32 folder does not contain the executable. I need to some how direct MSIExec to access the Sysnative folder. Have you heard of people running into this problem?
ServerManagerCmd actually does reside in System32. However, I am running this on a 2k8 box. The problem is MSIExec runs under the 32-bit subsystem whose System32 folder does not contain the executable. I need to some how direct MSIExec to access the Sysnative folder. Have you heard of people running into this problem?
Posted by:
AngelD
15 years ago
Posted by:
spartacus
15 years ago
Posted by:
AngelD
15 years ago
Posted by:
turbokitty
15 years ago
Rating comments in this legacy AppDeploy message board thread won't reorder them,
so that the conversation will remain readable.
so that the conversation will remain readable.