This project is a zero-dependency, lightweight, native Windows implementation designed to bypass the traditional complexities of virtualized bash scripts (like SDKMAN!) on Windows operating systems.
Instead of constantly appending and pruning your Windows PATH variable to point to different JDK folders (which quickly leads to the 1024-character PATH limit and environment variable bloat), the manager maintains a single Directory Junction (mklink /J) at:
%LOCALAPPDATA%\DiamTek\JVM\current
Your system PATH only ever needs to contain %LOCALAPPDATA%\DiamTek\JVM\current\bin. When you switch Java versions, the manager simply tears down the old junction and repoints it to the target JDK directory. This provides O(1) symlink resolution for the OS.
The engine provides two distinct switching engines that users can toggle via the Settings menu or CLI flags:
-
Symlink Mode (Default, UAC-Free):
- Mechanism: Updates the NTFS Directory Junction pointer (
%LOCALAPPDATA%\DiamTek\JVM\current) in user-space. - Privileges: Standard user space (100% UAC-free, zero admin popups).
- Compatibility: Native for 99% of modern tools (Maven, Gradle, IntelliJ IDEA, VS Code, Eclipse).
- Mechanism: Updates the NTFS Directory Junction pointer (
-
Registry Mode (Legacy, UAC Required):
- Mechanism: Directly writes the absolute JDK path to the Machine-level Windows Registry (
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) and updates the system-wide MachinePATH. - Privileges: Requires Administrator (UAC) Elevation on every switch, spawning an elevated background PowerShell worker via
Start-Process -Verb RunAs. - Compatibility: 100% unbreakable fallback for legacy enterprise applications, obscure Windows service runners, or ancient classloaders that perform strict canonical path checks and cannot resolve NTFS Directory Junctions.
- Mechanism: Directly writes the absolute JDK path to the Machine-level Windows Registry (
To ensure deep OS integration without requiring users to download external binaries (like setx augmentations), the tool relies on inline PowerShell execution invoked seamlessly via cmd.exe.
- Updates to the global
PATHandJAVA_HOMEare performed natively using the .NET framework bridging in PowerShell:[Environment]::SetEnvironmentVariable('JAVA_HOME', $target, 'Machine') - The script detects if it is running in standard user space. If required, it dynamically generates an elevated PowerShell script (
jvm_elevate_XXXX.ps1) in%TEMP%and executes it viaStart-Process -Verb RunAs.
- Updating the Windows Registry does not update the live, running terminal session. To solve this, the script dynamically evaluates the environment block within the execution boundary.
- Dynamic Filtering: Instead of using batch string substitution (
!PATH:string=!), which is vulnerable to quote-collisions and delayed expansion parsing bugs, the manager pipes the variable manipulation to PowerShell using the-notoperator against$env:PATH. This guarantees 100% accurate string evaluation and prevents the accidental deletion of unrelated paths (e.g., pruningJAVA_HOME_Backupwhile searching forJAVA_HOME).
Like SDKMAN!, this tool intercepts commands for popular Java tools (Maven, Gradle, Kotlin, Scala, Groovy). The CLI acts as a universal router:
- It intercepts the
jvm install <candidate> <version>command. - It executes a PowerShell
Invoke-RestMethodto the respective API (Adoptium, GitHub Releases, Azul, etc.) to securely resolve the download URL and SHA-256 checksums. - The payloads are extracted via
Expand-Archiveand isolated in%LOCALAPPDATA%\DiamTek\JVM\candidates\<candidate>. - Specific
<CANDIDATE>_HOMEvariables are injected into the registry, mapping the ecosystem completely identically to native Java.
Because Windows process environments cannot ordinarily be modified by a child batch process, install.ps1 injects a native PowerShell function hook into $PROFILE.
When jvm switches an active tool or JDK:
jvm.batwrites target environment pairs (KEY=VALUE) to$env:TEMP\.jvm_session_target.- The PowerShell wrapper intercepts the return code and invokes
Set-JvmVar. Set-JvmVarsurgically strips the old\bindirectory from$env:Pathand prepends the new\bindirectory directly into the current PowerShell process memory.- It updates
$env:JAVA_HOME(or corresponding tool variables) live, providing instantaneous switching without reopening terminal tabs.
Windows cmd.exe does not natively support Bash-style heredocs (cat <<EOF). Embedding multi-line PowerShell scripts inside a batch ( ... ) > script.ps1 redirection block requires careful escaping:
- Redirection operators (
<,>) are escaped as^<,^>. - Pipes (
|) and command separators (&) are escaped as^|,^&. - Parentheses (
(,)) are escaped as^(,^)to prevent premature termination of the enclosing batch block. - Exclamation marks (
!) are escaped as^^!to prevent corruption by CMD's delayed variable expansion engine (setlocal enabledelayedexpansion).
The uninstaller subsystem (uninstall.ps1) is designed for 100% total system sanitization:
- UAC Escalation: Uses .NET security principals to check for elevated tokens; if missing, automatically spawns an elevated PowerShell host via
Start-Process -Verb RunAs. - Registry Integration: Registers under
HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\DiamTek.JVMwith native Windows "Installed apps" metadata, dynamicEstimatedSizecomputation (with a 1,024 KB floor for Windows 11 compatibility), and creates a Start Menu uninstaller shortcut inStart Menu\Programs\DiamTek. - Dual-Scope Cleanup: Cleans both
UserandMachineenvironment variables andPATHregistries, surgically strips the$PROFILEhook, deletes the AppData Ecosystem cache, purges Windows Terminal profiles, removes pinned taskbar shortcuts, cleans session files, and prompts to cleanC:\Program Files\Java.
To provide a first-class modern Windows developer experience while strictly maintaining 100% pure Batch & PowerShell code:
- Dynamic Profile Injection:
install.ps1scans for Windows Terminal configurations across Release, Preview, and Unpackaged locations (LocalState\settings.json). It injects a dedicated profile with GUID{b20650a4-4212-4d64-9edf-744e9285e2be}, pointing to high-resolutionassets/icon.png. - Tab Lifecycle Management: Configured with
cmd.exe /candcloseOnExit: always. When a developer exits the interactive JVM menu (exit /B 0), the hostingcmd.exeprocess terminates, signaling Windows Terminal to immediately close the tab. - Shortcut Synchronization: Creates Start Menu application shortcuts targeting
wt.exe -p "Java Version Manager"(falling back tocmd.exe /con systems without Windows Terminal). During installation and self-updates, the script automatically searches%APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\to detect and update existing pinned taskbar shortcuts in place. - AppUserModelID & Taskbar Mechanics: Windows Terminal is a packaged WinUI app that hardcodes its own process-level AppUserModelID (
Microsoft.WindowsTerminal...) on all hosting windows. By registering a dedicated profile with native icon and dropdown integration rather than forcing brittle binary wrappers, the utility respects the OS container model while maintaining a zero-binary, 100% script-based repository.
- Winget: Native YAML manifest (
packages\winget\DiamTek.JVM.yaml) declaring installer metadata and portable packaging. - Scoop: JSON manifest (
packages\scoop\jvm.json) that automates downloading and bootstrapsinstall.ps1. - Chocolatey: Package specification (
packages\choco\jvm.nuspec) with automatedchocolateyInstall.ps1andchocolateyUninstall.ps1scripts. - WiX Toolset v4 (MSI): Automated build script (
packages\msi\build-msi.ps1) that compiles native, per-user Windows Installers (.msi) bundlingjvm.bat, companion branding assets,uninstall.ps1,LICENSE, andREADME.md:- Embedded Cabinet Architecture: Built with
<MediaTemplate EmbedCab="yes" />to generate an internal#cab1.cabdata stream inside the.msibinary. This produces truly standalone, single-file installers (~900 KB) without loose external.cabfiles, simplifying distribution and offline caching. - Multi-Architecture Support (
x64&arm64): Compiles native installers targeting both 64-bit Intel/AMD and ARM64 Windows platforms via WiX v4-archswitches, setting native architecture properties while defaulting to building both ($Arch = "all"). - Upgrade & Downgrade Safety: Configured with
<MajorUpgrade DowngradeErrorMessage="..." Schedule="afterInstallInitialize" />allowing clean upgrades over prior versions while preventing accidental downgrade conflicts. - Deferred Action Execution Order & Hook Isolation:
- Isolated Hook Architecture: Internal hook scripts (
msi-install-hook.ps1andmsi-uninstall-hook.ps1) reside privately in%LOCALAPPDATA%\DiamTek\JVM\, strictly segregating them from the CLI%LOCALAPPDATA%\DiamTek\JVM\bin\folder so internal scripts never pollute the user's command line orPATH. - Install Hook: Scheduled
After="CreateShortcuts"(sequence 4501) rather thanAfter="InstallFiles"(sequence 4002). Standard Windows Installer actionCreateShortcutsgenerates the Start Menu.lnkat sequence 4500; scheduling the hook afterward ensures the shortcut exists before PowerShell attempts to polish it with Windows Terminal (wt.exe) profiles and custom arguments. - Path Resolution in
WixQuietExec: Standard Windows Installer deferred custom actions run in the Windows Installer service context without inheriting standard shell environment PATHs. Hardcoding[WindowsFolder]System32\WindowsPowerShell\v1.0\powershell.exeguarantees deterministic 64-bit PowerShell invocation, completely eliminating0x80070002("file not found") execution errors. - Uninstall Hook: Scheduled
Before="RemoveFiles"to ensure PowerShell profile cleanup, Windows Terminal configuration scrubbing, dangling sub-process termination, and environment variable removal occur while the installed components are still present on disk. - Start Menu Uninstaller Shortcut: Packages an explicit MSI shortcut targeting
[SystemFolder]msiexec.exe /x [ProductCode]underStart Menu\Programs\DiamTek, allowing instant uninstallation discovery via Windows Search ("Uninstall Java Version Manager" and "Uninstall JVM"). - Race Condition Elimination: The MSI uninstaller relies purely on standard Windows Installer actions (
RemoveFile,RemoveFolderEx) for directory teardown, omitting background asynchronous CMD deletions to avoid file-lock race conditions (Windows Installer Error 2318).
- Isolated Hook Architecture: Internal hook scripts (
- Automated Verification Suite (
packages\msi\test-msi.ps1): Implements an automated 18-point synthetic integration suite designed for CI/CD pipelines and GitHub Actions build provenance attestations (actions/attest-build-provenance). The suite actively tests live operating system integration (Windows Installer servicemsiexec, binary layout, CLIbin/directory hygiene, Start Menu application and uninstaller shortcuts indexed by Windows Search, registry metadata, PATH propagation, Windows Terminal profile injection, CLI sanity subshell execution, clean uninstallation, and zero filesystem residuals). Features an autonomous 4-tier fallback engine (local MSI -> local WiX compiler -> GitHub Release binary -> remote source bootstrap + user-space .NET SDK / WiX CLI toolchain) and supports-ShowUI(native progress dialog/qb) and-KeepInstalled(retaining JVM post-test for direct terminal usage).
- Embedded Cabinet Architecture: Built with