I was helping a customer last week who wanted to push the .NET Framework 1.1 to a series of computers in a corporate network, but wanted to show some kind of progress UI on the client computers. I realized that we added an unattended switch to the setup wrapper for .NET Framework 1.1 based on some customer feedback from 1.0.
You can run .NET Framework 1.1 setup with the following command line switches to install using MSI basic UI:
dotnetfx.exe /q:a /c:"install.exe /qb /l"
This command line will cause the .NET Framework 1.1 to install with no user interaction required, but a small MSI progress bar will appear during installation so the user knows that something is happening on their machine. Note that as stated above, this /qb switch was added in .NET Framework 1.1, so this switch will not work in 1.0 setup.
Those of you with some knowledge of MSI command line parameters might ask why not just have customers extract the contents of dotnetfx.exe and then install netfx.msi directly. Or better yet, why not have them run dotnetfx.exe /q:a /c:"msiexec /i netfx.msi /qb /l*v" or something like that to achieve the same effect without needing to write new code to support the /qb switch for install.exe.
The answer to this is that we want customers who install the .NET Framework 1.0 and 1.1 to use install.exe to do so. There are several reason for this:
- We shipped .NET Framework 1.0 with some bugs that caused problems if you install using netfx.msi directly instead of going through install.exe. Fortunately, these bugs are fixed in .NET 1.1 and beyond, but they can potentially cause servicing and uninstall problems if .NET 1.0 is installed using the MSI directly.
- Install.exe will bootstrap and install Windows Installer 2.0 if it is not already installed on the computer. If the .NET Framework is installed by running the MSI directly, it becomes the responsibility of the 3rd party application or administrator who is deploying the .NET Framework to ensure that Windows Installer 2.0 or higher is already installed on the machine.
- (most importantly and most complicated to explain) Install.exe stops the Windows Installer service (named msiserver) before starting installation of the .NET Framework and after completing installation. This helps eliminate 1935 errors that might otherwise happen while installing the .NET Framework. Windows Installer added support for installing assemblies via native tables (MsiAssembly and MsiAssemblyName) beginning in Windows Installer version 2.0, but it requires the .NET Framework to be present becauses it uses a .NET Framework feature (called fusion) to install assemblies. That logic works fine for "normal" applications but becomes tricky for the .NET Framework itself (which is also an MSI package and needs to install assemblies as part of its own setup). This is what we call a "chicken and egg" problem - one has to come first but which one? The solution we use for .NET 1.0 and 1.1 setup is to copy the the minimal pieces of the .NET Framework needed to install assemblies, and then if Windows Installer detects that the .NET Framework is not present it will use these minimal pieces to install assemblies instead of the normal mechanism. At a really high level, the Windows Installer service will check to see if mscoree.dll exists in %windir%\system32, and if it does not, it will use the minimal pieces (located in the %windir%\system32\urttemp folder) to install assemblies. The complicating factor here is that the Windows Installer service continues to run in the background for 10 minutes after completing any installation activity. If Windows Installer has loaded the minimal pieces of the .NET Framework from %windir%\system32\urttemp, it will still have this version loaded in memory and if another setup needs to install assemblies within the next 10 minutes before the Windows Installer service shuts down, it will skip searching for mscoree.dll and instead use the minimal .NET Framework already loaded into memory. If that version of the .NET Framework in memory is not compatible with the assemblies in the next setup package, Windows Installer will not know this and will try to install the new assemblies with the incompatible .NET Framework in memory, which will fail with a 1935 and/or 2908 error. This problem is not very likely because the .NET Framework is generally designed to be backwards compatible and because it requires 2 setups to be run within 10 minutes. A couple examples of problematic scenarios are the following: Install .NET 1.0 and then try to install .NET 1.1 within 10 minutes by installing netfx.msi directly; and install and uninstall .NET 1.1 and then try to install .NET 1.0 within 10 minutes by installing netfx.msi directly.
As a side note, in the .NET Framework 2.0, we implemented a custom action to install assemblies using fusion APIs directly, in part to eliminate the "chicken and egg" problem. As a result, we see nearly no 1935 errors while installing .NET Framework 2.0. The install.exe setup wrapper still stops the Windows Installer service before and after installation because of possible interactions with other versions of .NET Framework setup due to copies of other versions of fusion being loaded into memory during the 10 minute window that the service would otherwise stay running after installation. Also, .NET 2.0 does not carry Windows Installer 2.0 because of the high market penetration of Windows Installer and because Windows Installer 3.1 has been posted as a mandatory update on Windows Update. That makes bullet #2 above much less of an issue for administrators and 3rd party developers. However, we still recommend installing .NET Framework 2.0 using the install.exe wrapper even though we've improved the scenario of installing using netfx.msi directly.
Even though we recommend using install.exe to install the .NET Framework 1.1 and 2.0, setup will work in most cases when running the MSI directly. It requires more care on the part of administrators or 3rd party setup developers who redistribute the .NET Framework. In controlled environments (such as OEM pre-installations of the .NET Framework), it is much easier to control cases where the Windows Installer service might be running and shut it down separately by running net stop msiserver for example.