Workaround to allow pre-installing the .NET Framework 2.0 during the T13 phase of OS setup using svcpack.inf

I previously wrote about a scenario where installing the .NET Framework 2.0 fails when launching it from svcpack.inf during the T13 phase of OS setup. When I originally wrote that post, the only workarounds that I had to offer were to install the .NET Framework 2.0 during the GuiRunOnce phase at the end of OS setup or by using a RunOnce/RunOnceEx registry value to launch .NET Framework 2.0 setup during the first boot of the OS.

A couple of weeks ago, a customer posted a workaround that they found that allows .NET Framework 2.0 installation to succeed when using svcpack.inf during OS setup. I have spent some time since then investigating further to make sure I understood this workaround and the root cause better before posting more about it. Now I want to explain the workaround and root cause in more detail for folks who want to be able to install the .NET Framework 2.0 in this way.

In order to allow the .NET Framework 2.0 to successfully install during the T13 phase of OS setup, you can include the following commands in svcpack.inf:

[SetupHotfixesToRun]
reg delete HKLM\Software\Microsoft\PCHealth\ErrorReporting\DW /f
reg add HKLM\SYSTEM\Setup /v SystemSetupInProgress /t REG_DWORD /d 0 /f
dotnetfx.exe /Q /C:"install.exe /Q"
reg add HKLM\SYSTEM\Setup /v SystemSetupInProgress /t REG_DWORD /d 1 /f

Deleting the DW registry key is necessary because .NET Framework 2.0 setup tries to write a value under this registry key and does not have the required permissions to write that value during OS setup.

Setting the SystemSetupInProgress value to 0 is necessary because when that value is set to 1 (which it is by default during OS installation), the action that installs assemblies to the GAC during .NET Framework 2.0 setup will fail with the following error:

Error 25007.Error occurred while initializing fusion. Setup could not load fusion with LoadLibraryShim(). Error: The handle is invalid.

I am not sure if setting the SystemSetupInProgress value back to 1 is strictly necessary, but it is safest to do this as well because that value signals to OS and application setup processes that OS setup is in progress.

When I looked in more detail into why .NET Framework 2.0 setup failed with error code 25007 when SystemSetupInProgress = 1, I found that I was able to produce an error with a simple test application to call LoadLibrary and then trying to call LoadLibrary for the file fusion.dll. Trying to do this gave me the following error:

LoadLibrary failed for 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\fusion.dll' with error code 14001 - This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.

This was the root cause of the 25007 error because one of the first things that .NET Framework setup attempts to do when installing assemblies to the GAC is to call LoadLibrary on fusion.dll.

I could not figure out why LoadLibrary was failing for fusion.dll (because LoadLibrary succeeded when I tried to load other DLLs in system32 on the same machine in the same circumstances). Eventually, I received the answer from Junfeng Zhang. The core issue resides in fusion side-by-side loading logic. An underlying design decision was made in some of the code in sxs.dll that causes side-by-side publisher policy to not be applied when the SystemSetupInProgress registry value is set to 1. The intention behind this decision is that OS setup should only use a pre-defined set of binaries, and should not be able to use arbitrary 3rd party binaries. The Visual C++ runtime files that ship with the .NET Framework 2.0 and Visual Studio 2005 (the VC80 versions) are installed to the side-by-side store (%windir%\WinSxS), and fusion.dll is built using these VC80 runtime files. Attempting to call LoadLibrary on fusion.dll when SystemSetupInProgress = 1 fails because fusion.dll cannot find the VC80 runtime files in the side-by-side store that it needs to load correctly.

This underlying issue exists for all side-by-side assemblies that any process on the system attempts to load when SystemSetupInProgress = 1. Junfeng's team is currently evaluating whether or not to change this design. The fix would have to be made in the file sxs.dll, which is an OS file. As a result, the fix would have to be delivered via a future service pack for Windows XP and Windows Server 2003.

In the meantime, however, the workaround described at the beginning of this blog post should work fine if you need to install the .NET Framework 2.0 during the T13 phase of OS setup using svcpack.inf.