Previously, we examined how Microsoft ships an old version of the .NET Framework for newer versions of its operating systems. This time, we will examine how Microsoft ships a new version of the .NET Framework for older versions of its operating systems.
You may find it helpful to review the history of .NET Framework releases and the servicing methods they employed. I refer you to MSDN blogger Aaron Stebner for a pretty comprehensive description of how the various versions of .NET were bundled with Windows: Mailbag: What version of the .NET Framework is included in what version of the OS? Peter Marcu also has a graphic that shows OS .NET bundling information for Windows Vista, Windows 7, and their server counterparts.
Beginning in .NET 4, the servicing model changed. Versions 3.x were additional features added on top of version 2.0. In contrast, any version above 4.0 with a major version number of ‘4’—4.5, 4.5.1, 4.5.2, 4.6, and 4.6.1—were complete, in-place replacements for all previous 4.x versions (but could exist alongside a 3.x version). These were installable on all supported operating systems at the time of their releases, and they shipped with the following OS releases:
- Version 4.5 shipped as an operating system component in Windows 8.
- Version 4.5.1 shipped as an operating system component in Windows 8.1.
- Version 4.5.2 was released separately.
- Version 4.6 was shipped as an operating system component in Windows 10.
- Version 4.6.1 was shipped as an operating system component in Windows 10 November Update (v1511).
Because some version of .NET 4.x shipped as an operating system component in each version of Windows since Windows 8/Server 2012, all subsequent versions are delivered as OS feature updates packaged as CAB files. These are then wrapped by an executable installer, which, in the 4.5.x versions, can extract the CAB files with the /createlayout switch. Unfortunately, it seems that Microsoft now really wants us to use the EXE installer: It has disabled the /createlayout switch in the installers for .NET 4.6 and higher.
It is still possible to retrieve the CAB files in 4.6.1, but it is difficult, and you aren’t going to like the results. Here are two methods:
- Run the offline installer on each platform for which you need to obtain the feature update CAB. The installer will extract the CAB file for only that platform into a temporary folder.
- Use a third-party tool like 7-Zip to extract the entire contents of the offline installer executable.
Reason you won’t like the results: In what I can only speculate is a move to discourage the very methods I have described, Microsoft has padded the CAB files to be gigantic. While the offline installer is less than 50 MB, each extracted CAB file is hundreds of megabytes in size.
When I found this out, I surrendered: “OK, Microsoft! I’ll do it your way!” I built a Configuration Manager Application using the executable installer, and I rearranged my operating system image build process in Microsoft Deployment Toolkit to use the executable installer as well. Then I made a very annoying discovery: The executable installer does not work on Server Core installations. The embedded setup program fails and displays a list of “problem signatures”, including None_UI_Interactive_Crash and 0xc000008c. I am still investigating the cause and possible solutions to this problem, but I will not be finished in time for this blog post’s publication date. My goal here is to always provide complete solutions, but for now, I must limit the scope to what actually works, and that means that our .NET Framework 4.6.1 application package will only work on client OSes and full installations of server OSes.
Acquiring the Tools and Installation Files
To build a Configuration Manager Application for Microsoft .NET Framework 4.6.1, you will need:
Because Windows 10 November Update (v1511) includes .NET 4.6.1 as an OS component, it will have its own, nearly-sourceless deployment type just as Windows 7 did in our .NET 3.5 application package. You might think that all remaining OS versions could share a deployment type that just runs the executable installer, but take a look at this text under the Additional Information heading on the offline installer’s download page:
When you install this package you will see following packages/updates installed as per operating system:
- On Windows 7 SP1 / Windows Server 2008 R2 SP1, you will see the Microsoft .NET Framework 4.6.1 as an installed product under Programs and Features in Control Panel.
- On Windows 8 / Windows Server 2012 you can find this as Update for Microsoft Windows (KB3102439) under Installed Updates in Control Panel.
- On Windows 8.1 / Windows Server 2012 R2 you can find this as Update for Microsoft Windows (KB3102467) under Installed Updates in Control Panel.
- On Windows 10 you can find this as Update for Microsoft Windows (KB3102495) under Installed Updates in Control Panel.
Indeed, simply using the /uninstall switch on the offline installer fails on all platforms except for Windows 7/Server 2008 R2, so each platform must have its own deployment type that utilizes the Windows Update Standalone Installer (wusa.exe) to uninstall the corresponding update. These separate deployment types can share the same installation source folder, though.
On your application staging file share (wherever you put application source files for Configuration Manager to find), create a folder structure for .NET 4.6.1. Mine will be \\fileserver\software$\Microsoft\.NET Framework 4.6.1. Under this folder, create the following subfolders.
Folder Name |
Description |
PreWin10v1511 |
Windows 7, Windows 8, Windows 8.1, Windows 10 RTM (64-bit and 32-bit); Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2 (64-bit) |
Win10v1511 |
Windows 10 November Update (64-bit and 32-bit) |
Win6.1×64Core |
Windows Server 2008 R2 (64-bit) (Server Core) |
Win6.2×64Core |
Windows Server 2012 (64-bit) (Server Core) |
Win6.3×64Core |
Windows Server 2012 R2 (64-bit) (Server Core) |
Ignore the *Core folders for now; they are just placeholders, and we’ll return to them in a future post. Download NDP461-KB3102436-x86-x64-AllOS-ENU.exe (the offline installer linked above) into the PreWin10v1511 folder.
As with .NET 3.5 on Windows 7, we must provide Configuration Manager with a source file location, and so I created a text file with Notepad containing the following text and saved it into the Win10v1511 folder as readme.txt:
The Microsoft .NET Framework 4.6.1 is included in Windows 10 version 1511, so installation files are neither required nor available.
That explains the presence of the otherwise empty folder to anyone reviewing this folder structure.
Building the Configuration Manager Application
Windows 7 and Windows Server 2008 R2 (64-bit and 32-bit)
In the Configuration Manager Console, create a new Application. Here are the values I provided in mine:
Property |
Value |
Application Properties |
Name |
Microsoft .NET Framework 4.6.1 |
Publisher |
Microsoft |
Version |
4.6.1 |
Deployment Type Properties |
Name |
Offline Installer – Windows 7 and Windows Server 2008 R2 (64-bit and 32-bit) |
Technology |
Script Installer |
Content location |
\\fileserver\software$\Microsoft\.NET Framework 4.6.1\PreWin10v1511\ |
Installation program |
“NDP461-KB3102436-x86-x64-AllOS-ENU.exe” /q /norestart /ChainingPackage ADMINDEPLOYMENT |
Uninstall program |
“NDP461-KB3102436-x86-x64-AllOS-ENU.exe” /q /norestart /uninstall |
Detection method |
Rule 1:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
Value: Release
Data type: Integer
Greater than or equal to 394271 |
Rule 2:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentVersion
Data Type: String
Equals 6.1 |
Installation behavior |
Installation behavior: Install for system
Logon requirement: Whether or not a user is logged on
Installation program visibility: Hidden
Configuration Manager behavior: Determine behavior based on return codes |
Requirements |
Operating system
One of Windows 7 SP1 (64-bit), Windows 7 SP1 (32-bit), Windows 2008 R2 SP1 (64-bit) |
Return Codes |
0 |
Success (no reboot) |
Installation completed successfully. |
1602 |
Failure (no reboot) |
The user canceled installation. |
1603 |
Failure (no reboot) |
A fatal error occurred during installation. |
1641 |
Hard reboot |
A restart is required to complete the installation. This message indicates success. |
3010 |
Soft reboot |
A restart is required to complete the installation. This message indicates success. |
5100 |
Failure (no reboot) |
The user’s computer does not meet system requirements. |
Take a look at the installation program:
"NDP461-KB3102436-x86-x64-AllOS-ENU.exe" /q /norestart /ChainingPackage ADMINDEPLOYMENT
You can display all available command line parameters for this program by running it with the /? switch or consulting the .NET Framework Deployment Guide for Developers. This is a typical installation command that suppresses all user interaction (/q for “quiet”) and prohibits the program from attempting to restart the computer. The ChainingPackage switch inserts whatever string is specified into the installation log, so that if something goes wrong, you can track down where the installation came from. The first detection rule and the return codes are also taken from the .NET Framework Deployment Guide for Developers.
There are two details to note here. First, Windows Server 2008 R2 Sp1 Core (64-bit) is omitted in the operating system requirements. As described above, the offline installer does not work on Server Core. Second, there is a second detection rule that tests the operating system version. You may remember that we did not need a similar rule for the .NET 3.5 package, and it is unclear to me why we need it now. I just know that without it, the Configuration Manager client was unable to select which application package to use for uninstallation, and so the Uninstall button would be disabled in Software Center. Adding this check fixed the problem.
Windows 8 and Windows Server 2012
The deployment type for Windows 8 and Windows Server 2012 is similar to that for Windows 7 and Windows Server 2008 R2. Duplicate everything in the Windows 7/Server 2008 R2 deployment type except for the properties in the table below.
Property |
Value |
Deployment Type Properties |
Name |
Offline Installer/Windows Update Uninstaller – Windows 8 and Windows Server 2012 |
Uninstall program |
“%SystemRoot%\System32\wusa.exe” /uninstall /kb:3102439 /quiet /norestart /log:”%TEMP%\netfx461uninstallation.log” |
Detection method |
Rule 1:
Same as Windows 7/Server 2008 R2 rule 1. |
Rule 2:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentVersion
Data Type: String
Equals 6.2 |
Requirements |
Operating system
One of All Windows 8 (64-bit), All Windows 8 (32-bit), Windows Server 2008 R2 (64-bit)Custom:
OS InstallationType
Not equal to Server Core |
Note that the second detection rule has the kernel version for Windows 8 and Server 2012 (6.2), and also note that we made use of the OS InstallationType custom Global Condition we built last time to make sure we don’t try to install on Server Core. (Unlike with Windows Server 2008 R2, the there are no built-in requirement options to select or omit Server Core installations.)
Windows 8.1 and Windows Server 2012 R2
As with Windows 8 and Server 2012, the deployment type for Windows 8.1 and Windows Server 2012 R2 is similar to that for Windows 7 and Windows Server 2008 R2. Once again, duplicate everything except for the properties in the table below.
Property |
Value |
Deployment Type Properties |
Name |
Offline Installer/Windows Update Uninstaller – Windows 8.1 and Server 2012 R2 |
Uninstall program |
“%SystemRoot%\System32\wusa.exe” /uninstall /kb:3102467 /quiet /norestart /log:”%TEMP%\netfx461uninstallation.log” |
Detection method |
Rule 1:
Same as Windows 7/Server 2008 R2 rule 1. |
Rule 2:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentVersion
Data Type: String
Equals 6.3 |
Rule 3:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentBuild
Data Type: String
Equals 9600 |
Requirements |
Operating system
One of All Windows 8.1 (64-bit), All Windows 8.1 (32-bit), Windows Server 2012 R2 (64-bit)Custom:
OS InstallationType
Not equal to Server Core |
Once again, we’ve adjusted the second detection rule to test for the proper Windows kernel version (6.3), and we again made use of our custom Global Condition to prevent installation attempts on Server Core.
Hopefully you noticed that I added a third rule to the requirements that tests the build number. With every release of Windows, Microsoft has to deal with compatibility issues caused by outside software vendors checking for exact versions of Windows rather than checking for a certain version or higher. In what I believe is the latest example of combating this problem by tricking such errant programs, Microsoft has stopped incrementing the CurrentVersion registry value. Windows 8.1, Windows Server 2012 R2, Windows 10 Release, and Windows 10 November Update all have a CurrentVersion value of 6.3. Since our uninstallers are specific to OS version, that means that we need some other value to let us differentiate between these systems. I chose the CurrentBuild value because I verified that it is different between Windows 8.1/Server 2012 R2, Windows 10 Release, and Windows 10 November Update and therefore fits our needs perfectly here. Microsoft may abandon this registry value in the future, too, or actually release an OS with the same build number, but at least for today, it works. (I did not use the new CurrentMajorVersionNumber and CurrentMinorVersionNumber values because they don’t differentiate between feature releases of Windows 10; both the Release and November Update have 10 and 0 for these registry values, respectively.)
Windows 10 Release
Copy the deployment type for Windows 8.1/Server 2012 R2, and make the changes shown in the table below.
Property |
Value |
Deployment Type Properties |
Name |
Offline Installer/Windows Update Uninstaller – Windows 10 Release |
Uninstall program |
“%SystemRoot%\System32\wusa.exe” /uninstall /kb:3102495 /quiet /norestart /log:”%TEMP%\netfx461uninstallation.log” |
Detection method |
Rule 1:
Same as Windows 7/Server 2008 R2 rule 1. |
Rule 2:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentVersion
Data Type: String
Equals 6.3 |
Rule 3:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentBuild
Data Type: String
Equals 10240 |
Requirements |
Operating system
One of Windows 10Custom:
OS BuildNumber
Equals 10240 |
The only thing new here is that we are using a different Global Condition in the requirements to ensure that this deployment type only works on the initial release of Windows 10 (build 10240). The OS InstallationType Global Condition is not needed because no server release accompanied the Windows 10 Release, so there will never be a Windows Server with the same build number as Windows 10 Release. The same is true for Windows 10 November Update.
Windows 10 November Update
We end with the easy one this time. Version 4.6.1 of the .NET Framework is a built-in operating system component in Windows 10 November Update, and it cannot be disabled. All deployment types must have an installation command, so we will just include a command to display the readme.txt file and exit. (This won’t actually display anything to the user because we specified Installation program visibility: Hidden.) No uninstallation command is required, so we’ll leave that box blank.
Copy the deployment type for Windows 10 Release, and make the changes shown in the table below.
Property |
Value |
Deployment Type Properties |
Name |
Feature Installation – Windows 10 Version 1511 |
Installation program |
“%SystemRoot%\System32\cmd.exe” /C type readme.txt |
Uninstall program |
None; leave blank. |
Detection method |
Rule 1:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full
Value: Release
Data type: Integer
Greater than or equal to 394254 |
Rule 2:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentVersion
Data Type: String
Equals 6.3 |
Rule 3:
Hive/Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Value: CurrentBuild
Data Type: String
Equals 10586 |
Requirements |
Operating system
One of Windows 10Custom:
OS BuildNumber
Equals 10586 |
Although the Name property begins with “Feature Installation”, again, we cannot actually install anything because the feature is included in the OS and cannot be removed. We need a deployment type so that we can use this application as a prerequisite for another application and have it succeed on Windows 10 November Update; if we didn’t have this deployment type, installation of another application with this one as a prerequisite would fail on the only OS that has the needed feature built in!
Note that we are testing for a different .NET 4.6.1 release number as described by the MSDN article referenced above, and we differentiate this deployment type from the one for Windows 10 Release by adjusting the OS BuildNumber value under Requirements.
Coming Up
Next time, we’ll build a Configuration Manager Application that ensures that some version of .NET starting with ‘4’ is installed on the computer, and we’ll reuse part of our work on .NET 4.6.1 to do so.