WinRM Java Client 3.1.04
-
Home
- Reference
Migrating from 1.x
Version 2.0.00 is a major cleanup: the legacy Apache CXF backend and the SMB-based file copy are gone, leaving a dependency-free client. The 1.x entry points keep their signatures, but a few CXF/SMB-only public types were removed and several runtime behaviors changed (summarized below). Read this page before upgrading.
Version 2.0.00 also introduces the fluent WinRMClient[1] API, which the documentation is now written around. Upgrading does not require adopting it — the legacy API[2] keeps working — but moving is straightforward and worthwhile; see Moving to the fluent API below.
TL;DR
- The Apache CXF backend was removed; the dependency-free client is the only implementation.
- HTTPS now validates the certificate and verifies the hostname by default (1.x trusted every certificate). Self-signed hosts that used to work will now fail the TLS handshake until you trust the certificate or opt out.
- Kerberos over plain HTTP is rejected, even as a fallback: see Other behavior changes.
- File copy for
localFileToCopyListnow goes through the WinRM channel instead of SMB. - A few CXF/SMB-only classes were removed.
- A new fluent API (
WinRMClient) is the recommended way to use the library; the 1.x static helpers remain supported.
TLS is validated by default
The 1.x CXF client silently trusted every TLS certificate and skipped hostname verification. The 2.0.00 client uses the JDK's default validating socket factory instead, so HTTPS connections to hosts with self-signed or otherwise untrusted certificates now fail during the handshake.
To restore connectivity, either:
- install the server certificate (or its issuing CA) into a Java trust store —
-Djavax.net.ssl.trustStore=...(recommended); or - disable validation with
-Dorg.metricshub.winrm.tls.insecure=true(insecure — testing only).
See TLS / HTTPS[3] for details.
The CXF backend was removed
The dependency-free client is now the only implementation. There is no switch to fall back to the Apache CXF backend — if you still need it, stay on winrm-java 1.x.
File copy no longer uses SMB
Files listed in localFileToCopyList for WinRMCommandExecutor.execute(...)[4] are no longer copied over SMB. They are transferred through the WinRM command shell (chunked base64, decoded on the host with certutil and verified with a digest). The consequences:
- No SMB requirement — TCP port 445 no longer needs to be reachable, no administrative or temporary share is created on the host, and the copy now works from any client OS (1.x wrote through a Windows UNC path and only worked from a Windows client).
- Files land in
<windir>\Temp\winrm-upload-<CLIENT-COMPUTER-NAME>instead of 1.x'sSEN_ShareFor_<CLIENT-COMPUTER-NAME>$. Where ACLs are hardened, grant write access on the new path. Directories left by 1.x are not reused and can be deleted (Where files land[5]). - The remote copy is content-addressed: a fragment of the content digest is inserted before the file extension (for example
script.1a2b3c4d5e6f.vbs). Same-named files with different content can no longer overwrite each other, and a script that reads its own name (WScript.ScriptName) will see the digest fragment. - A file already present on the host with an identical digest is not transferred again.
- The transport is meant for small script files, not bulk data.
Other behavior changes
- Kerberos requires HTTPS. On an HTTP endpoint, any
authenticationlist that containsKERBEROSfails before connecting (Kerberos over WinRM requires HTTPS ...), even[NTLM, KERBEROS], which 1.x served with NTLM. Use HTTPS, or removeKERBEROSfrom lists used over HTTP (Authentication[6]). - Command output is decoded as UTF-8. The shell runs under console code page 65001 (1.x decoded the output with the host's ANSI code page), so non-ASCII characters now come through intact.
WindowsRemoteProcessUtils.getWindowsEncodingCharset()is deprecated. See Character encoding[7]. - Result collections are unmodifiable.
WinRMWqlExecutor.getHeaders()/getRows()andWqlQuery.getSelectedProperties()/getSubPropertiesMap()return unmodifiable collections: copy them before modifying.
Fewer dependencies
Removing CXF and SMB leaves the library with zero runtime dependencies: the Apache CXF / JAX-WS / JAXB stack is gone, and so are smbj, BouncyCastle, SLF4J, mbassador, and asn-one. The library is a single jar of a few hundred kB, and it no longer references any logging API — problems are reported through exceptions[8] only.
Removed types
These types and members were public in 1.x but are removed in 2.0.00. Code that referenced them will not compile against 2.0.00 (all were CXF- or SMB-specific):
KerberosCredentialsException— was thrown only by CXF internals.SmbTempShareandWindowsRemoteProcessUtils.copyLocalFilesToShare(...)— replaced by the WinRM-channel file transfer.WindowsTempSharekeeps its API, but the share it creates is nowwinrm-upload-<CLIENT-COMPUTER-NAME>: no trailing$, so it is no longer hidden.WindowsRemoteProcessUtils.buildNewOutputFileName()now starts names withwinrm-, notSEN_.- The Apache CXF-based
WinRMServiceand itsservice.clientinternals (AuthenticationEnumstays), along with the generated WSDL/XSD resources.
The 1.x entry points — WinRMWqlExecutor, WinRMCommandExecutor, WinRMEndpoint, WindowsRemoteCommandResult, the enums, and the exception types — keep their signatures.
Moving to the fluent API
The 1.x static helpers open a connection, authenticate, run one operation, and tear everything down. The fluent WinRMClient[1] authenticates once and runs any number of operations over the same connection — a large win for anything that polls a host — and replaces the 10-argument positional calls with builders. Migration is mechanical:
WQL queries
// 1.x style (still works)
WinRMWqlExecutor result = WinRMWqlExecutor.executeWql(
HTTP, "server", null, "DOMAIN\\user", password,
null, "SELECT Name, State FROM Win32_Service",
30_000L, null, singletonList(NTLM));
List<String> headers = result.getHeaders();
List<List<String>> rows = result.getRows();
// Fluent
try (WinRMClient client = WinRMClient.builder("server")
.credentials("DOMAIN\\user", password)
.timeout(Duration.ofSeconds(30))
.build()) {
WqlResult result = client.wql("SELECT Name, State FROM Win32_Service").execute();
List<String> columns = result.columns();
for (WqlRow row : result) {
row.string("Name"); // by name, case-insensitive — no more index arithmetic
}
}
Commands
// 1.x style (still works)
WindowsRemoteCommandResult result = WinRMCommandExecutor.execute(
"CSCRIPT c:\\collect.vbs", HTTPS, "server", null, "DOMAIN\\user", password,
null, 30_000L, List.of("c:\\collect.vbs"), null, singletonList(NTLM));
// Fluent
try (WinRMClient client = WinRMClient.builder("server").https()
.credentials("DOMAIN\\user", password)
.timeout(Duration.ofSeconds(30))
.build()) {
CommandResult result = client.command("CSCRIPT c:\\collect.vbs")
.upload(Path.of("c:\\collect.vbs"))
.execute();
result.stdout();
result.exitCode();
}
What maps to what
| 1.x | Fluent |
|---|---|
protocol argument (WinRMHttpProtocolEnum) |
https() / http() on the builder |
port argument |
port(int) |
namespace argument |
namespace(String) on the builder or per query |
timeout in milliseconds |
timeout(Duration) on the builder or per operation |
ticketCache argument |
ticketCache(Path) |
List<AuthenticationEnum> |
authentication(AuthScheme...) — same ordered-fallback semantics |
localFileToCopyList |
upload(Path...) on the command |
workingDirectory argument |
workingDirectory(String) on the command (applies to the client's first command only) |
getExecutionTime() |
elapsed() (a Duration) |
-Dorg.metricshub.winrm.tls.insecure=true |
trustAllCertificates() per client (or sslContext(...) for a dedicated trust store) |
getHeaders() / getRows() (parallel lists) |
WqlResult.columns() / iterable WqlRow with lookup by property name |
getStatusCode() |
CommandResult.exitCode() |
Exceptions become unchecked
The fluent API reports failures through the unchecked WinRMClientException[9] hierarchy instead of the 1.x checked exceptions — no more mandatory try/catch around every call, and WSMan faults expose their code and detail through getters:
| 1.x checked exception | Fluent unchecked exception |
|---|---|
WinRMException with Authentication error on ... message |
WinRMAuthenticationException[10] |
WinRMException carrying WSMan fault text |
WinRMFaultException[11] — getFaultCode(), getFaultDetail() instead of contains() on the message |
java.util.concurrent.TimeoutException |
WinRMTimeoutException[12] |
WqlQuerySyntaxException |
WqlSyntaxException[13] |
Except for timeouts, the exception messages are unchanged, so code that matches on message text keeps working after the switch. See Timeouts and Errors[8] for the complete picture.
- [1] apidocs/org/metricshub/winrm/WinRMClient.html
- [2] legacy.html
- [3] tls.html
- [4] legacy.html#remote-commands
- [5] file-transfers.html#where-files-land
- [6] authentication.html#kerberos-spnego
- [7] commands.html#character-encoding
- [8] timeouts-and-errors.html
- [9] apidocs/org/metricshub/winrm/exceptions/WinRMClientException.html
- [10] apidocs/org/metricshub/winrm/exceptions/WinRMAuthenticationException.html
- [11] apidocs/org/metricshub/winrm/exceptions/WinRMFaultException.html
- [12] apidocs/org/metricshub/winrm/exceptions/WinRMTimeoutException.html
- [13] apidocs/org/metricshub/winrm/exceptions/WqlSyntaxException.html
