This particular requirement was to use a management server to run a script on all the Windows devices at a timed interval in this case that was every 24 hours, and the job of the software is check for Java JDK and JRE - it also needs to report on any versions that are marked as non-compliant - which will be unique to your particular situation.
If this was found which can be queried by the registry key for this particular example in the location "HKLM:\SOFTWARE\JavaSoft\Java Development Kit"
We also need to register a new event source before we can write the Event ID to the Event Log, which means we need this to run from an evaluated command prompt for the first time to registered successfully, once registered it no longer requires the elevation.
We also need an Event ID that we can then monitor for with our alerting solution to give us an alert if the JDK is found, so we need to add this as the requirement below:
Event Log = Application
Source = JDK Check
Event ID if JDK is found : 6666
Event ID if JDK is no found : 6665
Right, now we need to summon the Powershell genie to get this script done, so I need a keyboard and a plan (which is above) now lets rub the lamp a couple of times and we get the script below.
CheckJavato Event Log Script
# CheckJava.ps1
# Function to check Java in the registry
function Check-RegistryForJava {
param (
[string]$path
)
try {
$key = Get-Item -Path $path -ErrorAction Stop
return $key
} catch {
return $null
}
}
# Function to create event source if it doesn't exist
function Ensure-EventSource {
param (
[string]$source,
[string]$logName
)
if (-not [System.Diagnostics.EventLog]::SourceExists($source)) {
[System.Diagnostics.EventLog]::CreateEventSource($source, $logName)
}
}
# Define registry paths to check for JDK and JRE
$jdkPath = "HKLM:\SOFTWARE\JavaSoft\Java Development Kit"
$jrePath = "HKLM:\SOFTWARE\JavaSoft\Java Runtime Environment"
# Ensure the event source exists
$eventSource = "Java Check"
$eventLog = "Application"
Ensure-EventSource -source $eventSource -logName $eventLog
# Define non-compliant Java versions
$nonCompliantVersions = @(
"1.7.0_80", # Java 7 Update 80
"11", # Java 11
"9", "10", "12", "13", "14", "15", "16" # Java 9,10,12-16
)
function Is-NonCompliantVersion {
param (
[string]$version
)
Write-Output "Checking version $version for compliance..."
# Check for exact matches in the non-compliant list
foreach ($nonCompliant in $nonCompliantVersions) {
if ($version -like "$nonCompliant*") {
Write-Output "Version $version matches non-compliant version $nonCompliant"
return $true
}
}
# Check for Java 8 Update 211 or greater
if ($version -match "^1\.8\.0_(\d+)$") {
$updateVersion = [int]$matches[1]
Write-Output "Java 8 detected with update version $updateVersion"
if ($updateVersion -ge 211) {
Write-Output "Java 8 Update $updateVersion is non-compliant"
return $true
}
}
Write-Output "Version $version is compliant"
return $false
}
# Check for JDK
$jdkRegistryKey = Check-RegistryForJava -path $jdkPath
$jdkInstalled = $jdkRegistryKey -ne $null
$jdkVersion = if ($jdkInstalled) { $jdkRegistryKey.GetValue("CurrentVersion") } else { "Not installed" }
# Check for JRE
$jreRegistryKey = Check-RegistryForJava -path $jrePath
$jreInstalled = $jreRegistryKey -ne $null
$jreVersion = if ($jreInstalled) { $jreRegistryKey.GetValue("CurrentVersion") } else { "Not installed" }
# Output results and log events
if ($jdkInstalled) {
Write-Output "JDK is installed, version $jdkVersion"
[System.Diagnostics.EventLog]::WriteEntry($eventSource, "Java Development Kit (JDK) is installed. Version: $jdkVersion", [System.Diagnostics.EventLogEntryType]::Warning, 6666)
} else {
Write-Output "JDK is not installed"
[System.Diagnostics.EventLog]::WriteEntry($eventSource, "Java Development Kit (JDK) is not installed.", [System.Diagnostics.EventLogEntryType]::Information, 6665)
}
if ($jreInstalled) {
Write-Output "JRE is installed, version $jreVersion"
[System.Diagnostics.EventLog]::WriteEntry($eventSource, "Java Runtime Environment (JRE) is installed. Version: $jreVersion", [System.Diagnostics.EventLogEntryType]::Warning, 6664)
if (Is-NonCompliantVersion -version $jreVersion) {
Write-Output "JRE version $jreVersion is non-compliant"
[System.Diagnostics.EventLog]::WriteEntry($eventSource, "Java Runtime Environment (JRE) version $jreVersion is non-compliant.", [System.Diagnostics.EventLogEntryType]::Error, 6667)
exit 4
}
} else {
Write-Output "JRE is not installed"
[System.Diagnostics.EventLog]::WriteEntry($eventSource, "Java Runtime Environment (JRE) is not installed.", [System.Diagnostics.EventLogEntryType]::Information, 6663)
}
# Exit codes: 0 = JDK and JRE not installed, 1 = JDK installed, 2 = JRE installed, 3 = Both installed, 4 = Non-compliant JRE version
if ($jdkInstalled -and $jreInstalled) {
exit 3
} elseif ($jdkInstalled) {
exit 1
} elseif ($jreInstalled) {
exit 2
} else {
exit 0
}
Run this script now and if you run it interactively you will get this retuned:
However if you get a non-compliant version it will look like this:
Now we have this we can setup an alert to monitor for that Event ID and Source, so using for weapon of choice and in this instance is System Centre Operations Manager, and from here will need a new monitor that will be triggered from the Event Log, you will need to add this to a management pack as well....
Then we need the name of the script and the actual script as below (this was from above)
Then we need the "unhealthy" expression, which will need to contain:
Parameter Name: Property[@Name='StdOut']
Operator : Equals
Value : 1
This is where you can configure an alert for the script state and that will work, but that would mean the Event ID would be pointless, but to drive that Event ID you need this script to run to start with, so you can either choose to alert here or you can do another rule to monitor for that alert as another monitor.
If you want an alert on the Event ID then you can create another monitor this time as a simple manual reset event detection: