🏠 Overview • 📦 Installation • 📖 Usage • 🏗️ Architecture • ❓ FAQ • ⚖️ SDKMAN! Comparison • 📜 Changelog • 🛡️ Security • 🤝 Contributing • 💬 Support
First off, thank you for considering contributing! It's developers like you that keep this tool fast, secure, and rock-solid for the Windows engineering community.
Because jvm.bat actively modifies system and user environment variables (PATH, JAVA_HOME), testing changes directly in your primary environment can disrupt your local development workflow. Follow these sandbox testing practices:
When testing local changes in your cloned repository, invoke the script directly from your working directory rather than relying on the installed command:
# In CMD or PowerShell, run the local working copy directly:
.\jvm.bat list
.\jvm.bat current
.\jvm.bat which
.\jvm.bat 21 --sessionNote
Remember: If you already have JVM installed and present in your system PATH, simply typing jvm will invoke the globally installed executable rather than your local working copy. When developing and testing locally, always prefix the command with .\ (e.g. .\jvm.bat list or .\jvm.bat 21 --session). PowerShell argument tab-completion natively supports all three invocation styles: jvm <Tab>, jvm.bat <Tab>, and .\jvm.bat <Tab>! Once installed into PATH, standard users run jvm without prefixes from any directory.
Always use the --session flag during manual CLI testing. This mutates only the memory of the active subshell process and leaves your global Windows Registry and User environment untouched:
# CMD subshell verification:
cmd.exe /c ".\jvm.bat 21 --session && java -version"Tip
In PowerShell, running .\jvm.bat 21 --session spawns a transient child cmd.exe process, so session environment mutations do not persist into the parent PowerShell process. The global jvm command in PowerShell persists session variables because it is wrapped by the PowerShell $PROFILE hook function (function jvm). When developing locally in PowerShell, use the cmd.exe /c pattern above to test session switching.
To test directory junction creation and candidate downloads in total isolation, redirect the storage root temporarily before launching jvm.bat:
set "LOCALAPPDATA=%TEMP%\JVM_Sandbox"
.\jvm.bat listDiamTek JVM includes a synthetic 21-point integration test suite (packages\msi\test-msi.ps1) used by our CI/CD pipeline to validate real operating system integration (13 installation & system registration checks + 8 uninstallation & residual hygiene checks).
Open PowerShell (Run as Administrator if testing elevated MSI installation) and execute:
# Run the complete test suite against local build artifacts:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1
# Run with interactive Windows Installer UI dialogs visible:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1 -ShowUI
# Keep the test installation for manual inspection post-run:
powershell -ExecutionPolicy Bypass -File packages\msi\test-msi.ps1 -KeepInstalledTo verify installer packaging changes:
build-msi.ps1 automatically detects the product version and build number directly from jvm.bat:
# Compiles both x64 and arm64 MSIs into packages\msi\:
powershell -ExecutionPolicy Bypass -File packages\msi\build-msi.ps1 -Arch allbuild-choco.ps1 automatically detects the version from jvm.bat, synchronizes jvm.nuspec and fallback URLs, and packages .nupkg:
# Updates nuspec and compiles Chocolatey nupkg into packages\choco\:
powershell -ExecutionPolicy Bypass -File packages\choco\build-choco.ps1The core jvm.bat engine is nearly 100 KB of mathematically optimized Windows Batch script. When contributing code, you must adhere to these battle-tested rules:
- The Issue: Windows
cmd.exeparses batch scripts line-by-line using byte offsets. If a batch file is checked out with UNIX (LF) line endings,cmd.exemiscalculates byte offsets when parsing multi-line blocks, corruptingechostatements intoe+cho(the infamous "'cho' is not recognized" bug). - The Rule: Never commit LF-only scripts. Ensure git respects
.gitattributes(*.bat text eol=crlf).
- The Issue: When
setlocal enabledelayedexpansionis active,cmd.exeeagerly parses exclamation marks (!) as variable references. A file path containing an exclamation mark (e.g.C:\Projects\Test!App) will have its name destroyed. - The Rule:
- Never reference raw user input or unquoted paths inside delayed expansion blocks without prior sanitization.
- In inline PowerShell strings executed via CMD, never use
!for logical negation. Always use the-notoperator (e.g.Where-Object { -not ($_.Name -eq 'foo') }).
- The Issue:
PATHstrings on real-world Windows machines often contain rogue unclosed quotes (e.g.,C:\Program Files\Foo"Bar;C:\Java). Standardfor /f "tokens=*" %%a in (...)loops treat quotes as token delimiters, interpreting path segments as nonexistent files. - The Rule: All variable-passing loops must use double-quote encapsulation:
for /f "tokens=*" %%A in ('""!DYNAMIC_CMD!""') do ( ... )
- The Issue: Untrusted project
.java-versionand.sdkmanrcfiles can embed shell redirection operators (&,|,<,>) to execute arbitrary code. - The Rule: All file parsing pipelines must enforce metacharacter rejection:
for /f "usebackq tokens=*" %%v in (`type "%CONFIG_FILE%" 2^>nul ^| findstr /v "[&|<>]"`) do ( ... )
- The Rule:
jvm.batmust run cleanly out-of-the-box on a fresh, clean install of Windows 10/11. - Never add external dependencies (
.dll, standalone.exe,curl.exe,tar.exe,unzip.exe, or external.ps1files). All networking, extraction, and cryptographic hashing must rely solely on native Windows APIs and inline PowerShell bridging.
We actively welcome contributions! Follow this workflow for a seamless review:
- Fork the repository on GitHub.
- Create a topic branch from
main:git checkout -b feat/add-candidate-scala # or git checkout -b fix/path-quote-handling - Write Conventional Commits:
feat: add Scala support to Universal Candidate Enginefix: resolve delayed expansion path collision in BYO-JDKdocs: update Intune silent deployment switchestest: add synthetic validation case for ARM64 detection
- Run the Pre-Flight Checklist:
-
cmd.exe /c "jvm.bat --version"executes cleanly with exit code0. - Verified in standard Command Prompt (
cmd.exe). - Verified in Windows PowerShell (5.1) and PowerShell (7+).
- Verified in Windows Terminal.
- UAC-free Symlink Mode switches without prompts.
- No temporary script files left behind in
%TEMP%.
-
- Open a Pull Request targeting the
mainbranch with a clear description and testing proof.
This project adheres to the Contributor Covenant. By participating, you agree to uphold a welcoming, respectful, and inclusive environment for everyone.
Questions or architecture discussions? Reach out to Alexéy Shishkin on Discord (@thehawk01) or via email (salexey09@gmail.com).