Installing Java through SCCM

This post was migrated from my older blog.

I have been trying to get Java to install smoothly from SCCM for quite a while now. We need to deploy Java in a way that ensures that old versions of Java are removed, and both 32-bit and 64-bit versions of Java are installed. Here is a list of problems a ran into, as well as fixes for each.

The GUID is only Semi-Predictable

Uninstalling Java improves security as the Java installer frequently fails to remove previous versions. So, how do we uninstall Java remotely through SCCM? The most obvious approach is to remove Java by the GUID with MSIEXEC. Example:

MsiExec.exe /X{26A24AE4-039D-4CA4-87B4-2F06417067FF} /qn /norestart

This works well, but you have to know the GUIDs beforehand. If you search for the Java GUIDs you will likely find forums with comments stating to just replace parts of the GUID with the software version and bit version. We had a script that, mostly, worked based on this concept.

Here is the general suggestion you will find when you search for the Java GUIDs. The first bolded part of the following GUID is the bit version of Java, 32 or 64. The second bolded part relates to the specific version of Java. In this case, 7 update 55.

{26A24AE4-039D-4CA4-87B4-2F83217055FF}

This does not work all the time however.

Here’s an example:

Java 7 Update 55 {26A24AE4-039D-4CA4-87B4-2F83217055FF}
Java 7 Update 60 {26A24AE4-039D-4CA4-87B4-2F03217060FF}

The bolded parts changed outside the expected pattern.

That’s just one example, it seems as though subtle changes like that are littered through the Java releases. Most scripts that remove multiple versions of Java don’t seem to account for this. Our in-house script didn’t.

I noticed that the parts of the GUID that frequently change are only on the last segment of the GUID. The front segments of the GUID rarely change. I built a powershell script to remove Java on this concept.

Click here to go to the wiki page on the JavaRemoval script.

SCCM starts 32-bit Powershell by default

The removal works well by itself, but had issues when used in an SCCM package. It only removed 32-bit versions of Java. This leads to multiple 64-bit versions of Java. Thanks to the logging lines I added to the script I found out that it was only receiving the 32-bit keys, even from the 64-bit registry path. Turns out, SCCM executes the script with the 32-bit Powershell. This was a quick fix thanks to this technet post. I took jfvanroy’s answer and entered in the Powershell script name. It is working well so far. You can find a copy of it below.

If "%PROCESSOR_ARCHITEW6432%"=="" GOTO Native
%windir%\Sysnative\windowsPowershell\V1.0\PowerShell.exe -NoProfile -ExecutionPolicy Bypass -file %~dp0JavaRemoval.ps1
GOTO END
:Native
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -file %~dp0JavaRemoval.ps1
:END

The Uninstall Restart

The next problem I ran into with uninstalling/installing Java is a reboot requirement. Our original batch file uninstalled and installed Java in one run. This was hit or miss for 2 reasons. The first script that we made did not have a /norestart switch to the uninstall command. When a restart was required, the machine rebooted. The problem with that is it cancels the rest of the script which prevents Java from being installed. SCCM does not resume scripts that restart in the middle of their execution. As for the second reason; when we added the /norestart switch the install fails due to a pending restart. One of the main reasons a reboot was required is because IE or Java was still in use by a user at the deployment deadline.

We originally remedied these issues by using a task-sequence with a required reboot in-between an uninstall and install step. We added a few taskkill commands to our script to help with the program in-use issues. Not exactly elegant, but it worked… mostly. This was before we figured out the GUID issues. We are now using a single application package for uninstall and 2 application packages for install. This is done to bridge any gaps created by the install. For example, if you uninstall Java, then install the latest version, this causes a gap in the Java coverage for the user. To fix this, deploy two packages, x86 and x64, of Java. Then about a week later, deploy an uninstall package the removes all versions except for the version you want to standardize your users on.

The Installer doesn’t work with the 64-bit System Account

When you use the executable installer to install Java, it extracts an MSI and CAB file to the AppData folder. It then runs a MSIEXEC /i command to install the extracted MSI file. For home users this usually works, as it uses the home user’s account. SCCM, however, uses the system account. The system account is a little odd in that, it has two profiles. A 32-bit and a 64-bit profile. MSIEXEC is a 64-bit utility in 64-bit versions of windows, but the Java installer runs as 32-bit. The files that the installer extracts ends up in the 32-bit system profile. When MSIEXEC goes to install the MSI, it looks in the 64-bit profile and fails to find it.

This is a known bug and has been for a while. Shavlik submitted a bug report to Java back in 2010 on the issue, however it was recently resolved with the resolution “Won’t Fix”.

A workaround to this, is to extract the MSI, and CAB file for older versions, and run those directly. It works but it is an unsupported practice according to Oracle. Update: You were once able to find instructions on how to do that at Oracle’s website. This page now advertises their enterprise “My Oracle Support” option. As such, I will include the instructions below.

  1. Download the Java SE JRE Offline installers from the Java SE Downloads page
  2. Run the installers but do not click next or continue the installation!
  3. Once the installer is visible, navigate to “C:\Users\[Your UserName]\AppData\LocalLow\Oracle\Java” or “%APPDATA%\..\LocaLow\Oracle\Java”. Inside this directory you should see a folder matching the version of Java you started the installer for. For example “jre1.8.0_112_x64”. Copy everything inside the folder to wherever you need the install files to be. Pre Java 8 Update 20, this folder usually contained an MSI and CAB file. Afterwards, it is usually just a single MSI file. Either way, that MSI file and any supporting files in that folder make up the extracted installer. Repeat this as needed for the 32/64 bit versions if you are installing those as well.

Java extracts two files (Pre 8 Update 20)

I briefly attempted to deploy Java through SCUP. I sent a test deployment out and it half worked. Some received the update, some didn’t. Mostly it was just a mess. At the time I was not fully sure why, but it is likely that it was due to the same issue I had deploying Java as an application package. It extracted to the wrong system profile

Before entirely giving up on the idea, I decided to see if I could send it out using the extracted MSI files. It was not even plausible as a concept as Java extracts to 2 files, a MSI and a CAB. Both files are required for the install to succeed. SCUP does not support multi-file installers unfortunately.

Update 2016-01-07: The 2 file issue appears to have stopped. Extracting Java now only seems to produce a single MSI file. I have not attempted a SCUP deployment however. If it does work, the next problem will still be an issue.

Java doesn’t remove old versions in silent mode

Java recently, starting with an update of 8, started to prompt during install to remove previous version of Java. This does works well for home users, but for enterprise environments, this does not work in silent mode. There are currently no switches you can use to get the MSI to remove old versions.

Java doesn’t install in silent mode correctly without a config file

Another recent development with Java, is that it now appears to require a config file in order to install in silent mode correctly. The /q switch for msiexec is no longer enough.

The config file needs to be saved to “C:\ProgramData\Oracle\Java\java.settings.cfg”. The file is a plain text file with install commands on every line. The line we need to ensure a functional silent install is “INSTALL_SILENT=1”. See below for an example config file.

AUTO_UPDATE=0
EULA=0
INSTALL_SILENT=1
SPONSORS=0
WEB_ANALYTICS=0

There is a sub issue related to this. If you leave the config file in place after the install occurs, then any administrator that then needs to manually update or remove Java in the future will not see their installer/uninstaller run. More than likely, they will troubleshoot their “failing” installer until they finally realize that the installer actually is running, but is forced into silent mode by the left over file.

My Complete Solution

I have a 3 Deployment solution that appears to work solidly in SCCM. Instructions on how to create the solution is located at Java_Install_Package

In general though, the package can be built as such:

  1. Create an application package. Ensure the source folder contains the extracted installers for whatever version of Java you are installing.
  2. Add to the source folder a silent install config file, and a batch file that installs the config file, installs java, then removes the config file.
  3. Repeat for any other versions of Java.
  4. Use the JavaRemoval script and the batch code from Problem 2 to create a Java Removal package that removes all versions of Java except the ones that you just built packages for.
  5. Deploy the 2 installers for x86 and x64 in SCCM.
  6. Deploy the uninstaller about a week later when 95% or more of your clients have your new version of Java.

The end effect of all this is, when the install program is deployed it will install Java. The uninstall package which should be deployed a week later will uninstall un-needed versions of Java.