JDKManager.psm1
# JDK Manager PowerShell Module # Version: 1.0.0 # Module manifest $PSDefaultParameterValues['*:Verbose'] = $true # Module variables $script:JDKRegistryPaths = @( "HKLM:\SOFTWARE\JavaSoft\JDK", "HKLM:\SOFTWARE\JavaSoft\Java Development Kit", "HKLM:\SOFTWARE\Eclipse Adoptium\JDK", "HKLM:\SOFTWARE\Eclipse Foundation\JDK", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" ) $script:CommonJDKPaths = @( "C:\Program Files\Java", "C:\Program Files (x86)\Java", "C:\Program Files\Eclipse Adoptium", "C:\Program Files\Eclipse Foundation", "C:\Program Files\Amazon Corretto", "C:\Program Files\Microsoft\jdk", "C:\Program Files\Zulu\zulu-*", "C:\Program Files\BellSoft\LibericaJDK", "C:\Program Files\SAP\SapMachine" ) $script:CustomJDKRegistryKey = "HKCU:\Software\JDKManager\CustomJDKs" function Get-JDKInstallations { <# .SYNOPSIS Discover and list all JDK installations on the system. .DESCRIPTION Scans the system for JDK installations by checking registry entries and common installation paths. Returns detailed information about each JDK installation found. .EXAMPLE Get-JDKInstallations Lists all discovered JDK installations with their details. .OUTPUTS PSCustomObject[] - Array of JDK installation objects #> [CmdletBinding()] param() Write-Verbose "Scanning for JDK installations..." $installations = @() # Scan registry for JDK installations foreach ($registryPath in $script:JDKRegistryPaths) { if (Test-Path $registryPath) { Write-Verbose "Scanning registry path: $registryPath" try { $subKeys = Get-ChildItem -Path $registryPath -ErrorAction SilentlyContinue foreach ($subKey in $subKeys) { $installLocation = $null $displayName = $null $version = $null # Try to get installation location try { $installLocation = (Get-ItemProperty -Path $subKey.PSPath -Name "InstallLocation" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty InstallLocation).TrimEnd('\') } catch {} # Try to get display name try { $displayName = Get-ItemProperty -Path $subKey.PSPath -Name "DisplayName" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty DisplayName } catch {} # Try to get version try { $version = Get-ItemProperty -Path $subKey.PSPath -Name "Version" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Version } catch {} # If we found an installation location, validate it if ($installLocation -and (Test-Path $installLocation)) { $javaExe = Join-Path $installLocation "bin\java.exe" if (Test-Path $javaExe) { $javaVersion = & $javaExe -version 2>&1 | Select-String "version" | ForEach-Object { $_.ToString().Split('"')[1] } $installations += [PSCustomObject]@{ Version = $javaVersion DisplayName = $displayName InstallPath = $installLocation JavaExe = $javaExe Source = "Registry" RegistryKey = $subKey.PSPath } } } } } catch { Write-Warning "Error scanning registry path $registryPath : $_" } } } # Scan common installation paths foreach ($basePath in $script:CommonJDKPaths) { if (Test-Path $basePath) { Write-Verbose "Scanning directory: $basePath" try { $jdkDirs = Get-ChildItem -Path $basePath -Directory -ErrorAction SilentlyContinue foreach ($jdkDir in $jdkDirs) { $javaExe = Join-Path $jdkDir.FullName "bin\java.exe" if (Test-Path $javaExe) { try { $javaVersion = & $javaExe -version 2>&1 | Select-String "version" | ForEach-Object { $_.ToString().Split('"')[1] } $installations += [PSCustomObject]@{ Version = $javaVersion DisplayName = $jdkDir.Name InstallPath = $jdkDir.FullName JavaExe = $javaExe Source = "FileSystem" RegistryKey = $null } } catch { Write-Warning "Error getting version from $javaExe : $_" } } } } catch { Write-Warning "Error scanning directory $basePath : $_" } } } # Scan custom JDK paths from registry $customPaths = Get-CustomJDKPaths foreach ($customPath in $customPaths) { if ($customPath -and (Test-Path $customPath)) { $javaExe = Join-Path $customPath "bin\java.exe" if (Test-Path $javaExe) { try { $javaVersion = & $javaExe -version 2>&1 | Select-String "version" | ForEach-Object { $_.ToString().Split('"')[1] } $installations += [PSCustomObject]@{ Version = $javaVersion DisplayName = Split-Path $customPath -Leaf InstallPath = $customPath JavaExe = $javaExe Source = "Custom" RegistryKey = $script:CustomJDKRegistryKey } } catch { Write-Warning "Error getting version from $javaExe : $_" } } } } # Remove duplicates based on InstallPath $uniqueInstallations = $installations | Sort-Object InstallPath -Unique Write-Verbose "Found $($uniqueInstallations.Count) JDK installations" return $uniqueInstallations } function Set-JDKVersion { <# .SYNOPSIS Switch to a specific JDK version for the current session. .DESCRIPTION Sets the JAVA_HOME environment variable and updates the PATH to use the specified JDK version. This change is only effective for the current PowerShell session. .PARAMETER Version The JDK version to switch to (e.g., "17.0.2", "11.0.12") .PARAMETER InstallPath Direct path to JDK installation directory .EXAMPLE Set-JDKVersion -Version "17.0.2" Switches to JDK version 17.0.2 if found. .EXAMPLE Set-JDKVersion -InstallPath "C:\Program Files\Java\jdk-17.0.2" Switches to the JDK at the specified path. #> [CmdletBinding()] param( [Parameter(ParameterSetName = "ByVersion")] [string]$Version, [Parameter(ParameterSetName = "ByPath")] [string]$InstallPath ) $targetJDK = $null if ($InstallPath) { if (Test-Path $InstallPath) { $javaExe = Join-Path $InstallPath "bin\java.exe" if (Test-Path $javaExe) { $targetJDK = [PSCustomObject]@{ InstallPath = $InstallPath JavaExe = $javaExe } } else { throw "Java executable not found at $javaExe" } } else { throw "JDK installation path not found: $InstallPath" } } else { $installations = Get-JDKInstallations $targetJDK = $installations | Where-Object { $_.Version -like "*$Version*" } | Select-Object -First 1 if (-not $targetJDK) { throw "JDK version '$Version' not found. Available versions: $($installations.Version -join ', ')" } } # Set JAVA_HOME for current session $env:JAVA_HOME = $targetJDK.InstallPath # Update PATH to prioritize the selected JDK $javaBinPath = Join-Path $targetJDK.InstallPath "bin" $currentPath = $env:PATH -split ';' # Remove any existing Java paths from PATH $filteredPath = $currentPath | Where-Object { $_ -notlike "*\Java\*" -and $_ -notlike "*\jdk*\*" -and $_ -notlike "*\Eclipse*\*" -and $_ -notlike "*\Amazon Corretto\*" -and $_ -notlike "*\Microsoft\jdk\*" -and $_ -notlike "*\Zulu\*" -and $_ -notlike "*\BellSoft\*" -and $_ -notlike "*\SAP\*" } # Add the selected JDK's bin directory to the beginning of PATH $env:PATH = ($javaBinPath + ';' + ($filteredPath -join ';')) Write-Host "Switched to JDK at: $($targetJDK.InstallPath)" -ForegroundColor Green Write-Host "JAVA_HOME set to: $env:JAVA_HOME" -ForegroundColor Green # Verify the switch try { $currentVersion = & java -version 2>&1 | Select-String "version" | ForEach-Object { $_.ToString().Split('"')[1] } Write-Host "Current Java version: $currentVersion" -ForegroundColor Cyan } catch { Write-Warning "Could not verify Java version: $_" } } function Set-DefaultJDK { <# .SYNOPSIS Set the default JDK for the system (requires administrator privileges). .DESCRIPTION Sets the JAVA_HOME environment variable system-wide and updates the PATH to prioritize the selected JDK. This change affects all users and persists across reboots. .PARAMETER Version The JDK version to set as default (e.g., "17.0.2", "11.0.12") .PARAMETER InstallPath Direct path to JDK installation directory .EXAMPLE Set-DefaultJDK -Version "17.0.2" Sets JDK version 17.0.2 as the system default. #> [CmdletBinding()] param( [Parameter(ParameterSetName = "ByVersion")] [string]$Version, [Parameter(ParameterSetName = "ByPath")] [string]$InstallPath ) # Check if running as administrator if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Host "This command requires administrator privileges." -ForegroundColor Yellow Write-Host "Attempting to elevate privileges..." -ForegroundColor Cyan try { # Get the module path more reliably $modulePath = $null if ($MyInvocation.MyCommand.Module.Path) { $modulePath = $MyInvocation.MyCommand.Module.Path } else { # Try to find the module in the current directory $currentDir = Get-Location $modulePath = Join-Path $currentDir "JDKManager.psm1" if (-not (Test-Path $modulePath)) { throw "Could not locate JDKManager.psm1 module file" } } $arguments = @() if ($Version) { $arguments += "-Version" $arguments += "`"$Version`"" } if ($InstallPath) { $arguments += "-InstallPath" $arguments += "`"$InstallPath`"" } # Build the PowerShell command $psCommand = "Import-Module '$modulePath'; Set-DefaultJDK $($arguments -join ' ')" # Start a new elevated PowerShell process $process = Start-Process -FilePath "powershell.exe" -ArgumentList "-Command", $psCommand -Verb RunAs -Wait -PassThru -WindowStyle Hidden if ($process.ExitCode -ne 0) { Write-Error "Failed to set default JDK. Exit code: $($process.ExitCode)" Write-Host "Please run PowerShell as Administrator and try again." -ForegroundColor Yellow return } Write-Host "Default JDK set successfully." -ForegroundColor Green return } catch { Write-Error "Failed to elevate privileges: $_" Write-Host "Please run PowerShell as Administrator and try again." -ForegroundColor Yellow return } } $targetJDK = $null if ($InstallPath) { if (Test-Path $InstallPath) { $javaExe = Join-Path $InstallPath "bin\java.exe" if (Test-Path $javaExe) { $targetJDK = [PSCustomObject]@{ InstallPath = $InstallPath JavaExe = $javaExe } } else { throw "Java executable not found at $javaExe" } } else { throw "JDK installation path not found: $InstallPath" } } else { $installations = Get-JDKInstallations $targetJDK = $installations | Where-Object { $_.Version -like "*$Version*" } | Select-Object -First 1 if (-not $targetJDK) { throw "JDK version '$Version' not found. Available versions: $($installations.Version -join ', ')" } } # Set JAVA_HOME system-wide [Environment]::SetEnvironmentVariable("JAVA_HOME", $targetJDK.InstallPath, [EnvironmentVariableTarget]::Machine) # Update system PATH $javaBinPath = Join-Path $targetJDK.InstallPath "bin" $currentSystemPath = [Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::Machine) $pathArray = $currentSystemPath -split ';' # Remove any existing Java paths from system PATH $filteredPath = $pathArray | Where-Object { $_ -notlike "*\Java\*" -and $_ -notlike "*\jdk*\*" -and $_ -notlike "*\Eclipse*\*" -and $_ -notlike "*\Amazon Corretto\*" -and $_ -notlike "*\Microsoft\jdk\*" -and $_ -notlike "*\Zulu\*" -and $_ -notlike "*\BellSoft\*" -and $_ -notlike "*\SAP\*" } # Add the selected JDK's bin directory to the beginning of system PATH $newSystemPath = ($javaBinPath + ';' + ($filteredPath -join ';')) [Environment]::SetEnvironmentVariable("PATH", $newSystemPath, [EnvironmentVariableTarget]::Machine) # Update current session environment variables $env:JAVA_HOME = $targetJDK.InstallPath $env:PATH = $newSystemPath Write-Host "System default JDK set to: $($targetJDK.InstallPath)" -ForegroundColor Green Write-Host "JAVA_HOME set system-wide to: $env:JAVA_HOME" -ForegroundColor Green Write-Host "Note: You may need to restart applications or open new command prompts for changes to take effect." -ForegroundColor Yellow } function Get-CurrentJDK { <# .SYNOPSIS Get information about the currently active JDK. .DESCRIPTION Returns information about the JDK that is currently active in the PATH. .EXAMPLE Get-CurrentJDK Shows information about the currently active JDK. #> [CmdletBinding()] param() try { $javaExe = Get-Command java -ErrorAction Stop $javaPath = $javaExe.Source $javaDir = Split-Path $javaPath -Parent $jdkRoot = Split-Path $javaDir -Parent $javaVersion = & java -version 2>&1 | Select-String "version" | ForEach-Object { $_.ToString().Split('"')[1] } return [PSCustomObject]@{ Version = $javaVersion JavaExe = $javaPath InstallPath = $jdkRoot JAVA_HOME = $env:JAVA_HOME } } catch { Write-Warning "No Java installation found in PATH" return $null } } function Add-JDKPath { <# .SYNOPSIS Add a custom JDK installation path to the registry. .PARAMETER Path The path to the JDK installation directory. .EXAMPLE Add-JDKPath -Path "C:\MyJDKs\jdk-21" #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path ) $jdkPath = $Path.TrimEnd('\') $javaExe = Join-Path $jdkPath "bin\java.exe" if (-not (Test-Path $jdkPath)) { throw "JDK path does not exist: $jdkPath" } if (-not (Test-Path $javaExe)) { throw "No java.exe found in $jdkPath\bin" } if (-not (Test-Path $script:CustomJDKRegistryKey)) { New-Item -Path $script:CustomJDKRegistryKey -Force | Out-Null } $existing = Get-ItemProperty -Path $script:CustomJDKRegistryKey -Name Paths -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Paths -ErrorAction SilentlyContinue $paths = @() if ($existing) { $paths = $existing -split ';' } if ($paths -contains $jdkPath) { Write-Host "Path already exists in custom JDKs: $jdkPath" -ForegroundColor Yellow return } $paths += $jdkPath Set-ItemProperty -Path $script:CustomJDKRegistryKey -Name Paths -Value ($paths -join ';') Write-Host "Added custom JDK path: $jdkPath" -ForegroundColor Green } function Remove-JDKPath { <# .SYNOPSIS Remove a custom JDK installation path from the registry. .PARAMETER Path The path to remove. .EXAMPLE Remove-JDKPath -Path "C:\MyJDKs\jdk-21" .EXAMPLE Remove-JDKPath Shows a numbered list of custom JDK paths and prompts for selection. #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$Path ) if (-not (Test-Path $script:CustomJDKRegistryKey)) { Write-Host "No custom JDK paths configured." -ForegroundColor Yellow return } $existing = Get-ItemProperty -Path $script:CustomJDKRegistryKey -Name Paths -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Paths -ErrorAction SilentlyContinue if (-not $existing) { Write-Host "No custom JDK paths configured." -ForegroundColor Yellow return } $paths = $existing -split ';' # If no path specified, show numbered list and prompt for selection if (-not $Path) { Write-Host "`nAvailable custom JDK paths:" -ForegroundColor Cyan for ($i = 0; $i -lt $paths.Count; $i++) { Write-Host "$($i + 1). $($paths[$i])" -ForegroundColor White } do { $selection = Read-Host "`nEnter the number of the path to remove (1-$($paths.Count))" $index = [int]$selection - 1 } while ($index -lt 0 -or $index -ge $paths.Count -or -not [int]::TryParse($selection, [ref]$null)) $jdkPath = $paths[$index] } else { $jdkPath = $Path.TrimEnd('\') } if ($paths -notcontains $jdkPath) { Write-Host "Path not found in custom JDKs: $jdkPath" -ForegroundColor Yellow return } $paths = $paths | Where-Object { $_ -ne $jdkPath } Set-ItemProperty -Path $script:CustomJDKRegistryKey -Name Paths -Value ($paths -join ';') Write-Host "Removed custom JDK path: $jdkPath" -ForegroundColor Green } function Get-CustomJDKPaths { [CmdletBinding()] param() if (-not (Test-Path $script:CustomJDKRegistryKey)) { return @() } $existing = Get-ItemProperty -Path $script:CustomJDKRegistryKey -Name Paths -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Paths -ErrorAction SilentlyContinue if (-not $existing) { return @() } return $existing -split ';' } # Export functions Export-ModuleMember -Function @( 'Get-JDKInstallations', 'Set-JDKVersion', 'Set-DefaultJDK', 'Get-CurrentJDK', 'Add-JDKPath', 'Remove-JDKPath', 'Get-CustomJDKPaths' ) |