0

I'm currently writing a PowerShell script for the first time. I just want to find out which Java versions I have running on my Windows machines. It is searching for all java.exe instants, writes it in a file and then it should execute each line and write the output in a file. But I can't use my variable $command to execute anything. So the for loop is just running one time, because of an error and then quits.

#declaration
$file = ".\text.txt"
$i = 3
$out = ".\output.txt"

Get-ChildItem -Path C:\ -Filter java.exe -Recurse -ErrorAction SilentlyContinue -Force |
    Select-Object Directory >> $file
$count = Get-Content $file | Measure-Object -Line

#remove spaces and append "java.exe"
(Get-Content $file | Foreach {$_.TrimEnd()}) | Set-Content $file
(Get-Content $file | foreach {$_ + "\java.exe' -version"}) | Set-Content $file
(Get-Content $file).Replace("C:", "'C:") | Set-Content $file

#remove last 2 lines of the file
$count = $count.Lines - 2

#execute the stored paths

$i = 3
for ($i=3; $i -le $count; $i++) {
    $command = Get-Content $file | Select -Index $i;
    $command >> $out;
    & $command 2> $out;   # <----------------This line wont work
    echo "_____________________" >> $out;
}
2
  • So basically you want to run C:\paht\java.exe -version on each installation you have to find the version of java installed? Commented Sep 13, 2019 at 13:18
  • Using your code, you would need to run & exe argument on a line not & somestring. If you are adding the single quotes to make this part of the code work, then that is not necessary. For yours to work as is, you would need to do something like this & ($command -split " (-version)" -replace "'")[0] ($command -split " (-version)" -replace "'")[1]. The reason is because the first set of double quotes after & is interpreted as the command rather than the command and arguments. Commented Sep 13, 2019 at 13:21

3 Answers 3

1

Although I'm not sure what your desired output should look like, but below creates an array of PSObjects that you can output on screen or write to CSV file.

$result = Get-ChildItem -Path C:\ -Filter java.exe -File -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = $_.FullName
    $pinfo.Arguments = "-version"
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $pinfo
    $process.Start() | Out-Null
    $process.WaitForExit()
    $output = $process.StandardOutput.ReadToEnd()
    if (!$output) { $output = $process.StandardError.ReadToEnd() }
    [PsCustomObject]@{
        'FileName'    = $_.FullName
        'VersionInfo' = $output
    }
}
# output on screen
$result | Format-List

# output to CSV file (VersionInfo field uses multiple lines)
$result | Export-Csv -Path 'D:\javaversions.csv' -UseCulture -NoTypeInformation

Result on screen wil look something like:

FileName    : C:\Program Files\Java\jdk1.8.0_31\bin\java.exe
VersionInfo : java version "1.8.0_31"
              Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
              Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)


FileName    : C:\Program Files\Java\jdk1.8.0_31\jre\bin\java.exe
VersionInfo : java version "1.8.0_31"
              Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
              Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)


FileName    : C:\Program Files\Java\jre1.8.0_221\bin\java.exe
VersionInfo : java version "1.8.0_221"
              Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
              Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your help. But there is a problem. Your script just writes the java-version into my file. But not the further information like "Java(TM) SE Runtime Environment (build 1.8.0_221-b11)". Fixed it with removing the parameters for Export-Csv
@BastianJaeger Nope, it's all there. As i said, the result is multi-lined. When opened in Excel you'll have to go into the cell properties and turn TextWrapping on.
Ah, my bad. Thank you!
0

Your code doesn't work because you're writing entire commandlines to the intermediate file and then try to invoke the command strings from this file via the call operator. That doesn't work because a command "'C:\path\to\java.exe' -version" doesn't exist. You should be getting an error like this:

PS C:\> $command = "'C:\path\to\java.exe' -version"
PS C:\> & $command
& : The term ''C:\path\to\java.exe' -version' is not recognized as the name of
a cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
At line:1 char:3
+ & $command
+   ~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ('C:\path\to\java.exe' -version:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

The simplest way to make your code work is to just invoke the executables directly:

Get-ChildItem -Path 'C:\' -Filter 'java.exe' -Recurse -EA SilentlyContinue -Force |
    ForEach-Object {
        $_.FullName + ' -version'
        & $_.FullName -version 2>&1
        '__________________'
    } |
    Set-Content $out

If you want to stick with the approach using an intermediate file you need to prepend the commandline with the call operator, convert it to a scriptblock, and then invoke that.

Get-Content $file | ForEach-Object {
    $command
    & ([Scriptblock]::Create("& $command")) 2>&1
    '__________________'
} | Out-File $out

4 Comments

I like your first code pretty much. But it doesnt work the way i want. It just writes the path in the $out-file with -version sticked to it. But not the actual output of the command.
@BastianJaeger What is the output of the Get-ChildItem? Also, you shouldn't accept an answer when your question is not actually answered yet.
It answered my question and its all i need, the output of the console ist enough for me. I just noticed it today that the file is not the output of the console. The Ouput gives me this: Mode LastWriteTime Length Name ---- ------------- ---- -a---- 21.08.2017 15:51 191040 java.exe
@BastianJaeger Ah, the stupid Java executable writes the version information to STDERR. <_< See updated answer.
0

An alternative solution to @Theo is using a temporary file like so:

$GetParams = @{
    Path        = 'C:\'
    Filter      = 'java.exe'
    Recurse     = $true
    Force       = $true
    File        = $true
    ErrorAction = 'SilentlyContinue'
}
$JavaExeFiles = Get-ChildItem @GetParams | select -First 1

$StartParams = @{
     ArgumentList          = '-version'
     NoNewWindow           = $true
     RedirectStandardError = '.\javaver.txt'
}

$JaveExeDetails = foreach ($JaveExe in $JavaExeFiles) {
    Remove-Item -Path $StartParams.RedirectStandardError -EA Ignore

    Start-Process @StartParams -FilePath $JaveExe.FullName -Wait

    [PSCustomObject]@{
        File    = $JaveExe.FullName
        Version = Get-Content -Path $StartParams.RedirectStandardError
    }
}

# For viewing in the console
$JaveExeDetails | fl *

# For export to a file
$JaveExeDetails | fl * | Out-File -FilePath ./JavaVersions.txt

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.