Thursday, December 18, 2014

Deploy Java Runtime Environment with PS AppDeploy Toolkit

*Update 4/21/2015 - Please use this method to deploy Java, I find it works much better and requires less work.

*Update 3/10/2015 - I no longer use this method to deploy, I am finding the requirement evaluations are taking too long, instead I now use 2 applications with 1 deployment type for each. One application set for no user logged in, and one set for only when a user is logged in. I am creating a new post about how this works with an updated install script which uninstalls old versions of Java and installs Java 8 using the new enterprise msi installers.

When we deploy Java, we use to have the deployment set to only deploy when no user was logged in. This would help ensure that IE was not open, as IE had to be closed for Java to install correctly. This left a good number of machines without the latest Java as most users rarely have their machines turned on without being logged in for any appreciable amount of time. I thought I could use the PS AppDeploy Toolkit to help solve the issue of having IE open when trying to update Java, therefore I went about thinking of a way to create one Java application that would deploy in the following scenarios:
  1. If no user logged in, silently deploy Java.
  2. If a user was logged in and IE was not open, silently deploy Java.
  3. If a user was logged in and IE was open, notify user to close IE or give option to postpone the installation.

First download the newest version of the PS AppDeploy Toolkit and extract. (While I was writing this up I found out their was a newer version than what I originally used, so I recreated my application with the newer version.) Inside the extracted folder Toolkit you will find the necessary files and folders, copy the contents to your source so it looks like this:

Next you will need the Java msi and cab file for the version you want to install. I obtain this by downloading the Windows Offline installer. Run the installer, when the Welcome to Java (License Agreement) pops up, you will find the JRE1.x.xxxx.msi file in C:\users\<username>\AppData\LocalLow\Sun\Java\jre1.x.xxxx\
You can cancel out of the install and grab the .msi and the .cab file and move them to the PS AppDeploy "Files" folder you put in your Java application source location.

Then you will need to edit the Deploy-Application.ps1 file in your source. Here is where we will put the install commands as well as logic to skip the dialog prompts if IE is not open. Scroll down to the Pre-Installation section. I only want to notify the user that Java is being installed if IE is open, so I wrap the "Show-InstallationWelcome" command in an If statement. Make your Pre-Installation section like below:

[string]$installPhase = 'Pre-Installation'
## Show Message if IE is open, give prompt to close, allow up to 3 deferrals, verify there is enough disk space to complete the install, and persist the prompt
if ( get-process iexplore -ErrorAction SilentlyContinue | Where-Object {$_.MainWindowTitle -ne ""} )
 Show-InstallationWelcome -CloseApps "iexplore" -AllowDefer -DeferTimes 3 -CheckDiskSpace -PersistPrompt
 Show-InstallationProgress "Installing the latest version of Java to improve your web browsing experience"
 Set-Variable -Name IEOPEN -Value "Yes"

Make the Installation section like so:
[string]$installPhase = 'Installation'
Execute-MSI -Action Install -Path "jre1.7.0_71.msi" -Parameter "/q /norestart AUTOUPDATECHECK=0 JAVAUPDATE=0 JU=0 STATIC=0" 

Make the Post-Installation section like so, but be careful, some versions of the PS AppDeploy Toolkit have an ElseIF statement in the Post-Installation section at the bottom, be careful to leave that there with its corresponding brackets. This was in version 3.5, but in version 3.1.4 the ElseIf was down in the Uninstallation section. I only want to notify them that Java is done installing, if I they got the dialog box about the Java install in the first place:
[string]$installPhase = 'Post-Installation'

# Perform post-installation tasks here
# Remove useless Java shortcuts from Program menu
Remove-Item "$ENV:PROGRAMDATA\Microsoft\Windows\Start Menu\Programs\Java" -Recurse -Force
# If IE was Open, Inform User that Installation is Done.
if ( $IEOPEN -match "Yes")
 Show-InstallationPrompt -Message "Java update complete." -ButtonRightText "Ok" -Icon Information -NoWait
 remove-item $IEOPEN

Now we will create our deployment types. We are going to need 2 deployment types, the reason you need 2 is that you cannot select the "Allow users to view and interact with the program installation" when you have the Logon requirement of "Whether or not a user is logged on" when creating an Application deployment type. You could if this was a package, but I rather keep the advantages of the application model so I create two deployment types.

The first deployment type I call "Oracle JRE Install - user logged in". It looks like so:

Now I am going to set the logon requirement here for "Only when a user is logged on" and "Allow users to view and interact with the program installation". The logic we added to the "Deploy-Application.ps1" will keep the user from having to interact with the installation if IE is not open.

On the Requirements tab we have to create a custom requirement to run this deployment type only if a user is logged in. I will explain why this is necessary later. Click Add, change Category to Custom, click Create, give the custom condition a name and select Settings Type: Script, Data type: Boolean, Click Add Script, Script Language is Powershell and put in:
[bool] (Get-Process explorer –ea 0)

It should look like this:
The Operator is Equals, the value is True.

Create a second deployment type, I call mine Oracle JRE Install - No user logged in. This one will be much like the first except it will not have any Requirements set, and the User Experience tab should be set like:

The deployment types will look like so, notice the Priority levels for each Deployment Type:

You need to have the user logged on requirement set for the highest priority deployment type, or the second deployment type will never run. With no requirements set, what will happen is the first deployment type will wait to run until a user is logged in, the second deployment type will never run. I do not want that, I want it to run whether or not a user is logged in when the computer finds out about the application deployment. We have computers that have maintenance windows coordinated with their Deep Freeze thaw times, which is when they install software, during these maintenance windows there are no users logged in, and I want the application to run. So having it run only when a user is logged on is not an option.

I can think of one scenario where this may not work properly, that is if when the computer finds out about the application deployment, it is unfrozen, there is a user logged in, and it is not in its maintenance window. The computer may download deployment type "oracle JRE Install - user logged in" and wait to run it until the maintenance window comes around. When the maintenance window does comes, there will be no user logged in, so it will not run. This scenario will be rare as the machines are generally frozen when students are using them.

I tested the above scenario, once another Machine Policy Retrieval and Evaluation is run, which happens once the computer turns on inside its maintenance window, the computer will use the no user logged in deployment type instead of the user logged in deployment type it knew about previously. So it is capable of changing the deployment type that it is going to run if it needs to in those rare situations. In this situation the computer did download 2 copies of the deployment though, one for each deployment type it was going to run.

We do some other modifications to the wording of the prompts a user would see if they had IE open when the installation tries to take place. We change the icon's and use our own branding by replacing the .png files in the AppDeployToolkit folder. You can modify the wording of the prompts and labels of the buttons on the windows by modifying the AppDeployToolkitConfig.xml file. The documentation for PS AppDeploy Toolkit some of this or you can dig though the .xml files to find what you are looking for.

For this installation I also set ShowBalloonNotifications to False in the AppDeployToolkitConfig.xml. Otherwise the user will get an installation finished balloon from the toolkit after installation.

The downside to this method is the application will not be available to install in an OSD task sequence. You will have to create a duplicate application with a deployment type set to "Whether or not a user is logged on" and install that during OSD deployments.

Update: Please also see this post, about an issue with the PS AppDeploy Toolkit version 3.5 and Windows 8