While working on my Prerequisite scripts for Exchange Server 2013 and 2016, I realized that the code section for .NET was no longer working. It turns out that there are quite a few recommended hotfixes that are required for .NET 4.6.1 and .NET 4.6.2 to install properly. In order to facilitate the installation of this for Prerequisite scripts I had to strip out the code for .NET and rebuild it in a separate script. This required a non-Windows 2016 server which has .NET 4.6.2 installed by default as well as a server that did not have .NET 4.6.1. So, using a base loaded Windows 2012 R2 server I was able to work out the script.
.NET Requirements
You will notice that the .NET 4.6.1 download page (found here) does not list any prerequisites in order to install it. However, when you install it, you will find that you need to install KB2919355. If you review the download page for this patch, there is a list of other patches that must be installed:
- These KB’s must be installed in the following order: clearcompressionflag.exe, KB2919355, KB2932046, KB2959977, KB2937592, KB2938439, and KB2934018.
- KB2919442 is a prerequisite for Windows Server 2012 R2 Update and should be installed before attempting to install KB2919355
So, for Windows 2012 R2 we’ll need to install the above patches in this order:
- KB2919442
- clearcompressionflag.exe
- KB2919355
- KB2932046
- KB2959977
- KB2937592
- KB2938439
- KB2934018
For scripting purposes I needed the download link for each of these patches which was accomplish by manually downloading the files and then copying the link for the Downloads pop-up box in IE. I noticed that most of the patches were MSU files. Running MSU files with the technique I used in the prerequisite script would not work – I tested this and found that I would get pop-ups from the WSUA installer program.
Installation Code
Here is the code in order to install .NET 4.6.1 and/or .NET 4.6.2. This script is still enhanced as this article is being published. Option 5 on the menu only shows what hotfixes are installed on the server and it does not check for the specific hotfixes for .NET. This should be in the next revision of the script (version 1.2). Otherwise the script allows you to install all prereqs (option 1) for .NET 4.6.1, install .NET 4.6.1 (option 2), the postfix for .NET 4.6.1 (option 3) and .NET 4.6.2 (option 4) installation. Below is the code and a sample run through. of the script.
** NOTE ** This will be added in the next revisions of the prerequisite scripts.
# These KB's must be installed in the following order: clearcompressionflag.exe, KB2919355, KB2932046, KB2959977, KB2937592, KB2938439, and KB2934018.
# KB2919442 is a prerequisite for Windows Server 2012 R2 Update and should be installed before attempting to install KB2919355
##################################
# Global Variable Definitions #
##################################
$Ver = (Get-WMIObject win32_OperatingSystem).Version
$OSCheck = $false
$Choice = "None"
$Date = get-date -Format "MM.dd.yyyy-hh.mm-tt"
$DownloadFolder = "c:\downloads"
$CurrentPath = (Get-Item -Path ".\" -Verbose).FullName
$Reboot = $false
$Error.clear()
Clear-Host
$Arg1 = "/quiet /norestart"
#######################
## Defined Functions ##
#######################
# Begin BITSCheck function
function BITSCheck {
$Bits = Get-Module BitsTransfer
if ($Bits -eq $null) {
write-host "Importing the BITS module." -ForegroundColor cyan
try {
Import-Module BitsTransfer -erroraction STOP
} catch {
write-host "Server Management module could not be loaded." -ForegroundColor Red
}
}
} # End BITSCheck function
# Begin FileDownload function
function FileDownload {
param ($sourcefile)
$Internetaccess = (Get-NetConnectionProfile -IPv4Connectivity Internet).ipv4connectivity
If ($Internetaccess -eq "Internet") {
if (Test-path $DownloadFolder) {
write-host "Target folder $DownloadFolder exists." -foregroundcolor white
} else {
New-Item $DownloadFolder -type Directory | Out-Null
}
BITSCheck
[string] $DownloadFile = $sourcefile.Substring($sourcefile.LastIndexOf("/") + 1)
if (Test-Path "$DownloadFolder\$DownloadFile"){
write-host "The file $DownloadFile already exists in the $DownloadFolder folder." -ForegroundColor Cyan
} else {
Start-BitsTransfer -Source "$SourceFile" -Destination "$DownloadFolder\$DownloadFile"
}
} else {
write-host "This machine does not have internet access and thus cannot download required files. Please resolve!" -ForegroundColor Red
}
} # End FileDownload function
# KB2919442 Install
function KB2919442 {
FileDownload "https://download.microsoft.com/download/D/6/0/D60ED3E0-93A5-4505-8F6A-8D0A5DA16C8A/Windows8.1-KB2919442-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2919442-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2919442-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2919442 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# clearcompressionflag.exe Install
function clearcompressionflag {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/clearcompressionflag.exe"
Set-Location $DownloadFolder
# [string]$expression = ".\clearcompressionflag.exe /quiet /norestart /l* $DownloadFolder\clearcompressionflag.log"
[string]$expression = ".\clearcompressionflag.exe /norestart /l* $DownloadFolder\clearcompressionflag.log"
write-host " "
Write-Host "File: clearcompressionflag.exe installing..." -NoNewLine
Invoke-Expression $expression
Start-Sleep -Seconds 60
Write-Host "`nClearcompressionflag.exe has been run" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2919355 Install
function KB2919355 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2919355-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2919355-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2919355-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2919355 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2932046 Install
function KB2932046 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2932046-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2932046-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2932046-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2932046 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2959977 Install
function KB2959977 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2959977-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2959977-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2959977-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2959977 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2937592 Install
function KB2937592 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2937592-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2937592-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2937592-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2937592 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2938439 Install
function KB2938439 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2938439-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2938439-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2938439-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2938439 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# KB2934018 Install
function KB2934018 {
FileDownload "https://download.microsoft.com/download/2/5/6/256CCCFB-5341-4A8D-A277-8A81B21A1E35/Windows8.1-KB2934018-x64.msu"
Set-Location $DownloadFolder
write-host " "
Write-Host "File: Windows8.1-KB2934018-x64.msu installing..." -NoNewLine
$HotFixInstall={
$arglist='Windows8.1-KB2934018-x64.msu','/quiet','/norestart'
Start-Process -FilePath 'c:\windows\system32\wusa.exe' -ArgumentList $arglist -NoNewWindow -Wait
}
Invoke-Command -ScriptBlock $HotFixInstall
Start-Sleep -Seconds 60
Write-Host "`nKB2934018 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# .NET 4.6.1 install function
function NET461 {
FileDownload "https://download.microsoft.com/download/E/4/1/E4173890-A24A-4936-9FC9-AF930FE3FA40/NDP461-KB3102436-x86-x64-AllOS-ENU.exe"
Set-Location $DownloadFolder
[string]$expression = ".\NDP461-KB3102436-x86-x64-AllOS-ENU.exe /quiet /norestart /l* $DownloadFolder\DotNET461.log"
write-host " "
Write-Host "File: NDP461-KB3102436-x86-x64-AllOS-ENU.exe installing..." -NoNewLine
Invoke-Expression $expression
Start-Sleep -Seconds 60
Write-Host "`n.NET 4.6.1 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# NET461Cleanup
Function NET461Cleanup {
# Download the Hotfix
FileDownload "http://download.microsoft.com/download/E/F/1/EF1FB34B-58CB-4568-85EC-FA359387E328/Windows8-RT-KB3146714-x64.msu"
Set-Location $DownloadFolder
[string]$expression = "wusa.exe .\Windows8-RT-KB3146714-x64.msu /quiet /norestart"
write-host " "
Write-Host "File: Windows8-RT-KB3146714-x64.msu installing..." -NoNewLine
Invoke-Expression $expression
Start-Sleep -Seconds 60
Write-Host "`n.HotFix KB3146714 is now installed" -Foregroundcolor Green
write-host " "
}
# .NET 4.6.2 Install function
function NET462 {
# Download the Hotfix
FileDownload "https://download.microsoft.com/download/F/9/4/F942F07D-F26F-4F30-B4E3-EBD54FABA377/NDP462-KB3151800-x86-x64-AllOS-ENU.exe"
Set-Location $DownloadFolder
[string]$expression = ".\NDP462-KB3151800-x86-x64-AllOS-ENU.exe /quiet /norestart /l* $DownloadFolder\DotNET461.log"
write-host " "
Write-Host "File: NDP462-KB3151800-x86-x64-AllOS-ENU.exe installing..." -NoNewLine
Invoke-Expression $expression
Start-Sleep -Seconds 60
Write-Host "`n.NET 4.6.2 is now installed" -Foregroundcolor Green
write-host " "
$Reboot = $true
}
# Check for all hotifxes
Function HotFixCheck {
Get-HotFix
}
#######################
## MAIN CODE SECTION ##
#######################
$Menu = {
Write-Host "*******************************************"
Write-Host "** .NET 4.6.1 and .NET 4.6.2 Installaton **"
Write-Host "*******************************************"
Write-Host " "
Write-Host "1) Install Pre-Patches for .NET 4.6.1"
Write-Host "2) Install .NET 4.6.1"
Write-Host "3) Cleanup POST 4.6.1"
Write-Host "4) Install .NET 4.6.2"
Write-Host "5) Check for pre 4.6.1 hotfixes."
Write-Host " "
Write-Host "99) Exit"
Write-Host " "
write-host "Enter a number: " -nonewline
}
Do {
invoke-command -scriptblock $Menu
$Choice = Read-Host
switch ($Choice) {
1 { #
KB2919442
ClearCompressionFlag
KB2919355
KB2932046
KB2959977
KB2937592
KB2938439
KB2934018
}
2 { # .NET 4.6.1 Install
NET461
}
3 { # Cleanup post 4.6.1
NET461Cleanup
}
4 { # .NET 4.6.2 Install
NET462
}
5 { # HotFix Check
HotFixCheck
Write-host " "
Write-host " "
Write-host " "
}
99 {# Exit
popd
Write-Host "Exiting..."
}
}
} while ($Choice -ne 99)

All patches install silently. The only install that shows or has any sort of visual indicator is .NET installers.

So, use Options 1-3 to get .NET 4.6.1 installed on the server. There is no check for OS type, but this is geared towards Windows Server 2012 R2.
