VBScript (and Jscript) MSI CustomActions suck


Today was one of those days where you finally get around to looking at the time and wonder where the heck the hours went.  It wasn’t even like I really got a lot done.  I think my context switch costs have been really high lately.  It feels good to finally be home chilling out to the Perfecto Chills albums.  I thought I’d relate a short story to you why VBScript (and Jscript for that matter) should not be used for CustomActions in an MSI.

Today, I realized it was 15:39 when a fellow developer, we’ll call him Joe, called me at work.  My first thought was, "Jeez, it’s almost 4 o’clock and I haven’t got anything done!"  My second thought was, "I bet Joe is screwed."  Joe only calls me when the WiX toolset has completely failed or he has hit the wall with the Windows Installer.  Today, Joe had hit the wall.

"Rob, have you been tracking the email thread about the CustomAction of mine that is failing?"  I had seen this thread earlier in the day and remembered Joe mentioning something about a VBScript CustomAction.  "A little bit, you’re not really using VBScript for your CustomAction, are you?"

That was it.  Joe was attempting to debug some rather complex issues with a VBScript CustomAction interacting with some COM components during an install.  Everything seemed to work fine if he ran the VBScript (slightly modified) in the cscript.exe or wscript.exe hosts.  However, when the script executed in the Windows Installers ActiveScript engine it failed in rather mysterious ways.

Interestingly enough, a Windows Installer developer attached one of the many emails that I send to people when they are having problems using VBScript for CustomActions.  In those emails, I always suggest that script never be used for CustomActions in MSI.  So, Joe called me and asked, "So what can I do, Rob?"

My answer was simple, "Joe, there is a reason I recommend never using VBScript for CustomActions.  It’s because there isn’t really a whole lot you can do when you get into this kind of situation."  Then I provided him a few ideas that started with attempting to get the script debugger to somehow attach and try to then debug over to the COM component and ended up suggesting getting the command-line debugger attached to the COM component on load.  None of which is trivial.

What I don’t understand is why people completely disregard dire warnings that certain technologies should not be used in certain circumstances.  Yes, I understand it is extremely easy to write CustomActions in VBScript.  No, that doesn’t make it a good thing to use in your install.

So, I’m blogging here tonight at the end of a very long day to share with you three reasons, I recommend you not use VBScript or Jscript for CustomActions:

1.  Robust code is difficult write in script.  Setup code must operate on machines that are in an unknown state.  In such hostile environments, there are many different ways that code can fail.  Properly recovering from error conditions is very important (even if it just results in rollback).  "On Error Resume Next" is not conducive to proper error handling in code.  For this reason alone, Microsoft Office banned all script CustomActions from their MSI files.  I am admittedly biased but I believe Office has one of the most impressive, smooth, and stable setup programs for the Windows platform, especially considering its complexity.

2.  Debugging script in the Windows Installer is difficult.  Some might even argue it is impossible to debug script CustomActions.  As Joe is going to find out for the next few days, debugging the interactions between the Windows Installer, the scripting engine, and any other objects is a non-trivial task because the tools are so primitive.  There are many tools for C/C++ code that can have very low impact on the machine if you are tracking a particularly skittish bug.  Maybe I’m only called in when bugs are really hard, but there have been many times I was thankful for ntsd and pageheap.exe.

3.  Anti-virus products kill them.  This one just killed me.  A couple years after Office banned the use of scripting for CustomActions, Visual Studio shipped their first MSI setup.  They decided it would be okay if there were a few script CustomActions.  When customers got the product, PSS started getting reports of the Visual Studio setup mysteriously failing and rollingback.  After some very long calls, PSS discovered that if the users’ anti-virus programs were disabled the installations would succeed.  Turns out many of the top name anti-virus programs considered the scripts hosted by the Windows Installer to be virus and would kill the scripts off failing the Visual Studio install.

Anyway, hope you enjoyed the stories and remember, "VBScript and Jscript suck for CustomActions."

Comments (22)

  1. Michael Sanford says:

    Hi Rob,

    Congrats on Wix! It’s an awesome project and I look forward to talking to you about it a lot more in the future!

    Regarding your latest post — I’ve got to speak up here… While I certainly do understand your point, I think you are overstating it a bit. It would be more accurate to say that using script for custom actions has some challenges that the author needs to understand.

    A smart guy can easily build robust custom actions in script that support a "debug" mode that writes heavily to the Installer log, or use a local COM server on the dev machine to call DebugOutputString api’s. Additionally, with a proper Visual Studio install on your dev machine, if you raise an error, the debugger will kick in, allow you to see exactly where the custom action is failing and (hopefully) why. Well written scripts don’t just ignore all errors by way of a single "On Error Resume Next" — they check for errors, handle the expected ones, and log the unexpected ones, and finally, return failure so the installation can react accordingly.

    Your point about scripts getting pinged by Anti-Virus software is the best one you made. Does this happen even if the script and/or msi file are digitally signed? Also, it is quite nieve of the Anti-Virus vendors to believe that a script is somehow more dangerous that a compiled .DLL. Both can malicous, and it is just as easy to add either one to an msi file.

    One could also argue that since msi is an "open architecture", using scripts actually better supports enterprise customers as it allows them to see what your custom actions are doing and do not pose a "black box" the way compiled code does.

    My last point is that you never actually said what the problem is that "Joe" had. You simply made the global assertion that his problem was that he was using script. I’m sure that if you had posted the specific problem, someone would have had some helpful suggestions…

    In summary, you make a lot of good points, but the use of the word "suck" is a bit over the top. In each scenario, the author should understand all the facts and make a decision based on his/her particular requirements.

  2. I’ll chime in here a bit in ‘offense’ against using VBScript for custom actions.

    Don’t do it.

    If your installation is intended for a wide distribution, you’re just setting yourself up for pain.

    Anti-virus is a pretty good reason, but the best reason to avoid it (by leaps and bounds) is the fact that when you distribute software aimed for thousands and thousands of end-user desktops, you’re simply begging for a steady supply of problems and mysterious support calls.

    A clean machine with a known set of service packs and patches will work everytime for your installation. The QA teams will verify this.

    Yet, your customers are never in that state. Their computers are at least 10% of the time in a state where the scripting host is old, mismatched version-wise, corrupt, missing some ProgId registrations, or just plain in a bad mood.

    It doesn’t help that even though it’s almost always some problem on the end user’s machine, your product is the one that looks bad when it can’t install correctly. And if you wish to help the customer through a system misconfiguration, you’re stuck trudging through all the possible areas/corruptions that could cause the script to fail so mysteriously. With so many bad installers out there killing necessary registry keys, anything could be the culprit.

    This all boils down to my core belief that you absolutely must reduce the number of dependencies an installation has on the target system. Any dependency it does have should be clear, detected and 100% verifiable (so a user can correct it). Most scripting engines can make this aspect incredibly difficult to manage.

  3. Mike Kolitz says:

    Some of the third-party products like InstallShield and Wise have developed scripting languages for MSIs – I’m guessing – for just this reason.

    The problem is that an interpreter engine must be installed before those scripts can execute properly, which just adds one more level of complexity when deploying an application.

    I don’t suppose Microsoft would consider developing and integrating it’s own scripting language into Windows Installer that would address the problems you listed above, as well as remove the pain of having to deploy those other scripting engines?

  4. Michael,

    You are right. I was being mostly lazy about this blog entry. However, I still stand by my points even if they aren’t solid ones to debate from because they model what I have seen happen consistently in the "real world". If you are actually going through all of the steps you describe to get your scripting CustomActions as solid as possible then awesome. You should always have the same nagging fear that Mattie pointed out (which I tried to sorta’ comment on in the "robust point") about dependencies, but in a controlled environment maybe you’re okay.

    As for the black box issue, properly written CustomActions should be table driven and that usually removes most of the "black" from the box. I have at least two blog entries queued up about this topic. Keep watching here for more.

    Finally, Joe’s problem was tracked down today and found it was caused by some really interesting interactions between all the components I described in my blog on a 64-bit machine. Really, my point was less about Joe’s problem (I know Joe, he was going to figure it out) and more about why scripting CustomAction "suck". And, I use the word "suck" only when I’m trying to elicit a reaction. Thanks for the comments, Michael. <wink/>

  5. Mike,

    As I understand it those vendors simply ported their existing scripting engines to the Windows Installer. They had customers that insisted the vendors’ custom scripting language still be supported before moving to the Windows Installer. I’ve also had people tell me those scripting engines behave very poorly on the Windows Installer because the Windows Installer had such a different model than the vendors’ custom install engines. I obviously don’t use script (VBScript or any other) for my CustomActions so I can’t really confirm that. Ultimately though, I think scripting doesn’t really have a place in the world of setup.

    But I’ve been told a few times that I’m pretty hardcore about creating solid setup programs. I have a very high bar for any code that has the potential of completely hosing a user’s machine as setup can.

  6. Ron says:

    This begs the question, is there really anything "better"? Executables can be (and have been) just as bad. In fact, they can be worse, because they don’t suffer the limitations of the scripting environment.

    I can’t wait to see your future blogs on CustomActions. Should be a eye-opener. 🙂

    Keep up the good work.

  7. Jim says:

    Rob,

    Being hardcode about solid setup programs is good.

    As one who has had to create some pretty elaborate custom actions (even a few I wrote), I have come to the conlusion that custom actions should be avoided at all costs. (a third axiom of setup?)

    I have been gradually eliminating custom actions from our installers and find that they have generally been required:

    1. To make our install ‘just like it used to be’ (pre-MSI)

    2. To cover for poor application design.

    3. To cover for poor MSI package design.

    None of these are really compelling requirements….

    Thanks for WiX, I hope to be able to incorporate it in our build in the future. We have been in the ‘text only’ input camp since 1999, but with a homegrown tool set that is pretty well imbedded now.

  8. JPG says:

    On the whole, I agree wholeheartedly with you and applaud your stance on the quality of setups and think that there is more grass roots support for your point of view than you realise.

    The scripting in InstallShield and Wise are direct ports of InstallScript and the Wise Installation System. So yes they are complete dogs to work with, but they should be considered as stop gaps whilst most setup authors learn Windows installer and then C++, as most of the people who (re)author application packages are not developers.

    They are paradigm shifts of understanding to switch between them and Windows Installler in general (unfortunately I learnt the hard way with the MSI.Chm and then Mike Gunderloys book), but there is another audience that I think has been largely unnoticed in this discussion – application repackagers.

    There are a lot of applications that are out there (both externally and internally developed) that are still in use, that clients demand be repackaged for automated distribution in MSI format. Unfortunately sometimes you have to use custom actions, especially when you’re under time constraints, to get the job done.

    That said hopefully the ratio of companies releasing MSI’s instead of EXE’s will tip more favourably in the future and then we can have the discussions about raising the bar on the quality of the setups and possibly expansions to the current logo validation suites.

    All that said, I would like to thank you for at least trying to improve things by leading by example and doing something about it, rather than whinging about the situation that so many others seem prone to do.

    Best regards

    James G

  9. RevFry says:

    I’m more than happy to stop using JScript. Where’s my C# CA support?

  10. Peter Torr says:

    Getting the script debugger to work is a black art; don’t rely on it.

    And just to nit-pick, the Windows Installer is a script _host_, not a script _engine_

    With me telling people not to run script in IE, and you telling people not to run script in MSIs, soon there will be nobody running my ex-product 🙂

  11. Tim Mayert says:

    That’s all fine and good, but what about the people that have come from a script based langauge, like InstallShield, and do not have the developer’s know how in other languages like C++, C# …?

    You are stating to not use VBScript or JScript then what is the recommended way to create customs actions when you have no choice?

    I know only a little C++ and have been doing the script thing for quite awhile now. I would like to get out of the Install Script and more into the MSI installs, but if you do have to have custom actions, because the MSI does not support something then what do you recommend the CA’s are made in?

    We have had problems with the InstallShield engines, but the script that we create is fairly solid and rarely causes problems.

    As is I am trying to create a Basic MSI project that I would like to avoid any scripts in, but I need to display the disk size requirements and the disk available size on a custom dialog box and have not been able to find anything that gives me this information. I only see this being done is a custom action. Is there a solution to this that will NOT require a custom action to get this information?

    Any ways my point of view on this topic.

    Tim M.

  12. Darwin Sanoy says:

    Just wanted to add my two cents to the fray (even if I am a little late).

    Wise Script custom actions compile into EXE’s just like their lanuages did previous – so interpretter pre-installation is limited to InstallScript.

    When administrators build packages, vbscript is the most accessible of all custom action language options. In addition their packages operate in "managed" environments. Although these environments can be quite complex and have a lot of variance in them – they are still a much more known target than the complexity that exists in having your package potentially run on any computer in the world. As such, they can generally ensure that scripting runtimes, virus software settings and non-standard machines can be handled. At the very least they have an out that machines that do not meet corporate standards are self-selected out of the SLAs they operate under – in otherwords they don’t take the fall for these.

    I am not trying to claim a manifesto that all administrator generated packages fall into this description – but in general administrators can rely on a certain base level of configuration management that tends to ease the difficulties in the use of scripted custom actions. Any concessions that may have to be made by the environment (such as ensuring script engines are healthy and operational for custom actions) are usually vastly outweighed by the difficulty it would take to secure the services of a C++ programmer whenever a custom action was required.

  13. Rob, I know you’ll pull your hair out for suggesting this, but I need to ask you a question.

    How come there are MSI Custom Action types only support VBScript and JScript? Would it have been possible in MSI to define a generic CA Type # that meant a script and then place a script language tag in either an additional column or embedded within the script itself?

  14. Project2501a says:

    > That’s all fine and good, but what

    > about the people that have come

    > from a script based langauge, like

    > InstallShield, and do not have the

    > developer’s know how in other

    > languages like C++, C# …?

    Seriously, learn how to program.

    Learn C#. Or something.

    Anyhow, I seriously think MS dropped the ball with the installer designer in VS.NET 2003/5 . And yeah, while WiX is ULTRA cool, I am *STILL* waiting for C# Custom Action & Greek Language support in the Installer desinger/packager.

  15. John Miller says:

    I know this is a rather late entry to this thread, but there is an absolute need for something like VBS being used in an MSI; why ? because MSI, suck at uninstalation time.

    I’ve got a typical example here, where the customer (I’m a software re-packager btw) has specified that any application must do a completely clean uninstal.

    The problem is that the program adds to both the registry  and the file structure, beyond what is in the msi tables. At remove time, the msi leaves the entire structure (both cases, registry and file) alone since it cant unuinstal what isn’t defined. Worse these structures are built up by using user identifiers at run time.

    Now if there was a way to absolutely, posatively, and definetly blast an entire directory structure irrespective of what is below it, and the same for registry key structures, then I would not be in the position of having to do customer actions in the 1st place, and scripting allows quick modification of standard routines to fit specific cases in each msi (msis being created through Wise).

  16. VBScab says:

    I’m late to this too, but to answer John, the major install authoring tools (certainly Wise and AFAIK InstallShield) both allow you to specify file & reg entries to be removed at uninstall time.

    As for script in CAs, it is sometimes necessary to work around limitations/bugs in the authoring tools. I had INCREDIBLE problems with Wise’s creation of virtual directories, where an MSI would create the VD but stopped creating the accompanying application. No amount of re-editing would fix it. In the end, with deadlines approaching, the quickest route was to shoehorn CreateVDirs.VBS from the Platform SDK into use. It would have taken F O R E V E R to get the same functionality authored in a DLL or EXE, what with code review, testing, QA, etc, etc.

  17. Imagine a blog entry where Bob Arnson steps in and tells the tale of the Office PIAs for the Creative Commons Add-in for Microsoft Office.