Cybergenik
Cybergenik

Reputation: 140

How to use java commands in powershell

All I'm trying to do here is determine whether or not this specific version of java is installed. The Program should only either return "Java is installed" or return a non-zero exit error with "Java is not installed".


 function Check_Java_Installed {

   $app = java -version | Out-String 

     if ($app -contains "1.8.0_141"){
         Write-Output "Java installed"
     }
     else{
         Write-Error -Message "Java not installed"
     }
 }

 Check_Java_Installed

Output (Powershell ISE):

java : java version "1.8.0_141"
At C:\temporary\Installers\java-checker.ps1:3 char:12
+    $app = (java -version) | Out-String
+            ~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (java version "1.8.0_141":String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Java(TM) SE Runtime Environment (build 1.8.0_141-b15
)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
Check_Java_Installed : Java not installed
At C:\temporary\Installers\java-checker.ps1:13 char:2
+  Check_Java_Installed
+  ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Check_Java_Installed

Output (Powershell):

wrong output

Upvotes: 2

Views: 3455

Answers (1)

mklement0
mklement0

Reputation: 438153

  • java -version prints to stderr, which the obsolescent PowerShell ISE treats as an error, unlike regular PowerShell console windows. To capture stderr output, you must use redirection 2>&1

    • Note: PowerShell wraps stderr lines from external programs in System.Management.Automation.ErrorRecord objects. In PowerShell [Core] v6+, these objects sensibly stringify to their original string content if you pipe to Out-String, for instance. Unfortunately, this is not true in Windows PowerShell (v5.1-), so you'll have to call .ToString() on them; the alternative is to shell out to cmd.exe and apply the redirection there (cmd /c 'java -version 2>&1'), but that is inefficient and can have side effects.
  • The -contains operator tests an array for the presence of an element, it doesn't perform a substring search; you can use the [string] type's .Contains() method for the latter, or - more PowerShell-idiomatically - the -match operator, though note that -match operates on regular expressions rather than literal strings, and is case-insensitive by default. Note that with -match the . chars. in search string 1.8.0_141 must then be \-escaped in order for them to be treated literally.

  • Write-Error writes to PowerShell's error stream, it doesn't set an exit code. While it is possible to assign to $global:LASTEXITCODE to set an exit code from a function, PowerShell doesn't use exit codes internally.
    Instead, name your function Test-* (Test is an approved verb) and make it return $true or $false.
    Alternatively, name it Assert-JavaInstalled and make it throw an error that aborts processing of the script.

To put it all together:

# Functions named Test-* should return $true or $false
function Test-JavaInstalled {
   # In Windows PowerShell, use:
   #   (java -version 2>&1 | % ToString | Out-String)
   (java -version 2>&1 | Out-String) -match '1\.8\.0_141'
}

# Call the function.
if (Test-JavaInstalled) {
  "Java installed"
} else {
  Write-Error"Java not installed"
}

Alternatively, name your function Assert-JavaInstalled and make it generate a script-terminating error via throw, if Java is found not to be installed:

function Assert-JavaInstalled {
   # In Windows PowerShell, use:
   #   (java -version 2>&1 | % ToString | Out-String)
   if ((java -version 2>&1 | Out-String) -match '1\.8\.0_141')) {
     "Java installed"
   }
   else {
     # Throw a script-terminating error.
     throw "Java not installed"
   }
}

# Call the function.
Assert-JavaInstalled

Upvotes: 1

Related Questions