Skip to content

v3.0.00

Choose a tag to compare

@github-actions github-actions released this 29 Sep 23:51
· 44 commits to main since this release

Version 3.0.00 turns winrm-java into a complete remote file client: read, inspect, list and
download files on the Windows host, from the library and from the command line. That is the
major feature behind the new major version.

Highlights

Remote file access: read, stat, list, download (#146, #145, #147, #148)

client.file(path) is a new entry point for remote files, the counterpart of uploadFile(...).
Everything travels through the WinRM channel: no SMB, no share, no extra port.

byte[] content = client.file("C:\\Windows\\Temp\\collect.bin").readBytes();
String tail    = client.file("D:\\logs\\huge.log").offset(-8192).readText(StandardCharsets.UTF_8);
String sha256  = client.file("C:\\Windows\\Temp\\collect.bin").digest("SHA256");

try (InputStream in = client.file("D:\\exports\\big.csv").openStream()) { ... }   // bounded memory

Optional<RemoteFileInfo> info = client.file("C:\\Windows\\Temp\\collect.log").info();
RemoteFileList logs = client.file("C:\\inetpub\\logs").list()
    .glob("*.log").recursive().maxDepth(3).filesOnly()
    .modifiedAfter(Instant.now().minus(Duration.ofDays(1)))
    .execute();

client.downloadFile("C:\\Windows\\Temp\\collect.log", Path.of("collect.log"));   // digest-verified, atomic

Reads support byte ranges and negative offsets (tails), files held open by another process,
and a maxBytes cap for the in-memory terminals. Downloads are verified with a digest and
skipped when the local copy is already identical. File content is sent as raw bytes rather
than base64, about 1.3× faster than the first implementation (#175).

The CLI gets four matching subcommands: ls, stat, cat and get.

winrm-java -h server -u 'DOMAIN\user' -pf pw.txt ls 'C:\inetpub\logs' --glob '*.log' --recursive --depth 3
winrm-java ... stat 'C:\Windows\Temp\collect.log' --json
winrm-java ... cat 'D:\logs\huge.log' --offset -8192          # the last 8 KiB
winrm-java ... get 'C:\Windows\Temp\collect.log' ./collect.log

See Remote files and the
CLI reference.

Kerberos credential delegation (#141)

Like winrs -allowdelegate: the remote command can use your credentials to reach a further host
(a UNC path, Active Directory, another server) instead of failing with access denied on the
second hop.

WinRMClient client = WinRMClient.builder("server.example.net")
    .https()
    .authentication(AuthScheme.KERBEROS)
    .allowDelegation()
    .credentials("DOMAIN\\user", password)
    .build();

CLI: --allow-delegate (requires --kerberos and a forwardable ticket). See
Credential delegation.

Load the user profile in the remote shell (#139)

The remote shell no longer has to run with WINRS_NOPROFILE. loadUserProfile() on the builder,
or --profile on the CLI, loads the user's profile (%APPDATA%, HKEY_CURRENT_USER) in every
shell the client creates. The default is unchanged: not loaded. See
Loading the user profile.

Behavior changes

  • WQL array properties keep all their elements (#189). A WMI array (IPAddress, IPSubnet,
    DefaultIPGateway, Capabilities, ...) used to yield only its last element, silently.
    Its elements are now joined with | ("192.0.2.10|fe80::1"); arraySeparator(String) on the
    builder changes the separator. Code that parsed such a value as a single element must now split it.
    See Reading the result.
  • Streaming terminals report protocol failures as WinRMClientException (#188).
    wql().stream(), command().start(), file().openStream()/openReader(), list().stream()
    and RemoteProcess.close() used to let a raw IllegalStateException escape on an unexpected
    HTTP status, an exhausted authentication fallback or a malformed response. They now throw the
    documented WinRMClientException, as the blocking terminals always did.
  • Stdin a command does not read is discarded instead of failing the run (#183). When the
    command exits before reading its input, the server answers with WSManFault 232 ("The pipe is
    being closed"). This is now treated like a broken pipe on a local Process: the caller gets the
    command's actual output and exit code. Piping input into the CLI's exec no longer exits 70.

Fixed

  • Multi-line WHERE clauses (Java text blocks) are accepted in WQL queries instead of being
    rejected with WqlSyntaxException (#190) — #192
  • The UTF-8 byte order mark that PowerShell 2.0 (Windows Server 2008 R2, Windows 7) writes ahead
    of its output is dropped from stdout() and stderr() — #178
  • Closing a streaming read (openStream(), openReader(), a listing's stream()) or a
    RemoteProcess before the command completed took the whole operation timeout and then threw
    from close(); it now returns in about a second — #181

Documentation

  • Full pre-release review of the site and README: wrong statements corrected, missing options
    documented, and a Client options table
    on the index page — #187
  • Basic authentication: Windows accepts local accounts only, addressed by their bare user
    name (#172) — #173

Dependencies

  • Bump spotbugs-maven-plugin 4.10.3.0 → 4.10.4.1 and spotbugs-annotations 4.10.3 → 4.10.4 — #168, #174, #167
  • Bump maven-surefire-report-plugin 3.5.6 → 3.6.0 — #170

Pull requests

  • Read remote files: client.file(path) with byte ranges, streaming and digests (#146) — #177
  • File properties and directory listing: info(), exists(), list() (#145) — #179
  • Download remote files: downloadFile() and downloadTo() (#147) — #180
  • CLI: ls, stat, cat and get subcommands (#148) — #181
  • Remote files: raw bytes instead of base64 (#175) — #186
  • Kerberos credential delegation (#141) — #182
  • Configurable user-profile loading (#139) — #184
  • Discard unread stdin instead of failing on WSManFault 232 (#183) — #185
  • Report streaming protocol failures as WinRMClientException (#188) — #191
  • Keep every element of WQL array properties (#189) — #193

Full Changelog: v2.2.00...v3.0.00