Bootstrapping The .NET Framework Without An MSI Installer

I recently needed to test the idea of whether or not I could bootstrap .NET v4.0 onto a WinXP machine, from a USB thumb drive, without an application installer for the target app. The goal was to insert a thumb drive, run the app directly from the root of the thumb drive and have .NET 4 installed onto the system if it wasn’t already there, prior to the application starting up.


The High Level Process

At a very high level, this is fairly simple:

  1. Check for .NET 4
  2. If not found, install
  3. If found, or after install, launch the real app

When I got down into the weeds of doing this, I found a few very helpful items on the interwebs. To check for a specific version of .NET, I found this StackOverflow question, which has an answer that outlines the various registry entries you can look for.

Framework Version  Registry Key
1.0 HKLMSoftwareMicrosoft.NETFrameworkPolicyv1.03705
1.1 HKLMSoftwareMicrosoftNET Framework SetupNDPv1.1.4322Install
2.0 HKLMSoftwareMicrosoftNET Framework SetupNDPv2.0.50727Install
3.0 HKLMSoftwareMicrosoftNET Framework SetupNDPv3.0SetupInstallSuccess
3.5 HKLMSoftwareMicrosoftNET Framework SetupNDPv3.5Install
4.0 Client Profile HKLMSoftwareMicrosoftNET Framework SetupNDPv4ClientInstall
4.0 Full Profile HKLMSoftwareMicrosoftNET Framework SetupNDPv4FullInstall

The answer goes on to detail other aspects, such as service packs, but this information was sufficient for my needs.

I also grabbed a copy of the stand-alone .NET 4 Redistributable package. To be honest, the less-than 50 meg package size is rather surprising – especially when you see the greater-than 230 meg package size for .NET 3.5!

One other requirement was to prevent the user from having to click a bunch of “Next” and “License Agreement” buttons during the .NET 4 installation. I had a hard time finding documentation for the command line options online, but running the /? option against the redistributable gave me the information I needed. I ended up using “/passive /showfinalerror /promptrestart” as the options. This puts the installer into passive mode, which still displays progress but skips all the user interaction, will display an error message window if any problems occur, and will prompt the user to restart if a restart is required.


Implementing The Bootstrapper

Remember that this is a proof of concept, only, at this point. Given that and my general lack of C++ or Delphi skills (though I was a Pascal programmer back in high school, 15 years ago), I wanted to skip past the hard part of putting together a real bootstrapper executable. So… I chose to go with Windows Script Host and VBScript.

Fortunately, the WSH / VBScript documentation on MSDN is good enough to get me rolling – I haven’t done VBScript since the classic ASP days, and haven’t done VB in any form since 2005! But it all came back to me and with the help of the docs, I was able to produce this script:

Dim WshShell, value
Set WshShell = WScript.CreateObject("WScript.Shell")


Sub Run(ByVal sFile)  
Dim shell  
Set shell = CreateObject("WScript.Shell")
  shell.Run sFile, 1, true
  Set shell = Nothing
End Sub

value = wshShell.RegRead("HKLMSoftwareMicrosoftNET Framework SetupNDPv4Install")
if (Err.Number <> 0) Or (value is nothing) then
  Run("dotnetdotNetFx40_Full_x86_x64.exe /passive /showfinalerror /promptrestart")
end if


Yes, that’s an “ON ERROR RESUME NEXT” in the 2nd line! ACK! I know… but we’re limited in VBScript / WSH. The reason this is needed, is the RegRead call. If the key does not exist (and it won’t, on a machine that doesn’t have .NET 4 installed), an exception is thrown. We have to prevent the exception from failing the script and this is the only way I know of to do that. We then check for the presence of an error and run the .net installer if one was encountered.

… I know… using exceptions as logic and flow control is taboo. It is just an prototype / proof of concept, though.

For a long-term solution, I would suggest C++ or Delphi. It tends to look bad when you deliver a product to a customer with a “runme.vbs” file sitting on the thumb drive. Anyone with an ounce of tech knowledge would question the legitimacy of that. This should get you started, though. And hopefully someone else will find this useful, and possibly re-write the core logic of what I’ve provided in a C++ or Delphi app that can run natively.

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs - the amazingly awesome podcast audio hosting service that everyone should be using, and where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Bootstrap, Command Line. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Rod

    A batch file would be even simpler if you have the “reg” command on your system. If the key exists then “reg query” will return 0, otherwise it’ll return 1.

    REM Check the registry to see if the framework is installed.
    reg query “HKLM\Software\Microsoft\NET Framework Setup\NDP\v4\Full” /v Install
    if not %ERRORLEVEL% 1 goto :installed

    REM Install the framework as we can’t find it.
    dotnet\dotNetFx40_Full_x86_x64.exe /passive /showfinalerror /promptrestart

    REM Now run what you need to run.

  • derick.bailey

    I thought about a batch file, but didn’t know you could do registry reads from one. thanks, Rod!

  • Magnus

    Take a look at dotNetInstaller:

    It does the tings you want to do.


  • Christopher Bennage

    I did Pascal in high school too!

  • Michael Snead

    I realize this is old – but this would have been easy as pie to translate into JScript which works fine on WSH and give you try / catch support.