WinRM Java Client 3.1.04
-
Home
- Usage
Command-Line Client
Every release ships a self-contained executable jar that bundles the client and a small CLI: download winrm-java-3.1.04-standalone.jar (shortened to winrm-java-standalone.jar in the synopsis and short examples) from the latest release[1] and run it with Java 11 or later. This page is its manual.
Synopsis
java -jar winrm-java-standalone.jar [options] wql <query>
java -jar winrm-java-standalone.jar [options] command|cmd|exec|run <command line...>
java -jar winrm-java-standalone.jar [options] shell
java -jar winrm-java-standalone.jar [options] ls <directory> [ls options]
java -jar winrm-java-standalone.jar [options] stat <path> [--json]
java -jar winrm-java-standalone.jar [options] cat <file> [cat options]
java -jar winrm-java-standalone.jar [options] get <file> [<local path>]
java -jar winrm-java-standalone.jar --help | --version
Subcommands
| Subcommand | Description |
|---|---|
wql <query> |
Run a WQL query in the ROOT\CIMV2 namespace and print the rows to stdout as UTF-8 JSON Lines[2]. |
command <command line...> |
Run a command on the remote host, forwarding its output. cmd, exec, and run are aliases. |
shell |
Open an interactive cmd.exe session on the remote host (see Interactive shell). |
ls <directory> |
List a remote directory, or a tree, one entry per line (see Remote files). |
stat <path> |
Print the properties of a remote file or directory. |
cat <file> |
Copy the bytes of a remote file, or of a byte range, to stdout. |
get <file> [<local path>] |
Download a remote file to a local file, digest-verified. |
For wql and command, everything after the subcommand is the query or the command line, quoted by your local shell's rules. For command, the arguments are joined with spaces, and one that contains a space is double-quoted: write command dir 'C:\Program Files', not command 'dir "C:\Program Files"'. The remote cmd.exe then parses the line, so its operators (&, |, <, >, ^, %) keep their meaning outside quotes: command ipconfig '|' findstr IPv4 filters on the host. Git Bash rewrites an argument that starts with / into a Windows path: double the slash of a switch (ipconfig //all). shell takes no argument. The file subcommands take a remote path and their own file options, in any order. All other options go before the subcommand.
Options
| Option | Description |
|---|---|
-h, --hostname <host> |
Target hostname or IP address (required). |
-u, --username <user> |
User name, optionally DOMAIN\user (required). |
-p, --password <password> |
Password. Command-line arguments may be visible to other local processes: avoid in automation. |
-pf, --password-file <file> |
Read the password from a UTF-8 file (preferred for automation, see below). |
-P, --port <port> |
Target port. Default: 5985 for HTTP, 5986 for HTTPS. |
-t, --timeout <ms> |
Operation timeout in milliseconds. Default: 60000. See Timeout semantics. |
-d, --directory <path> |
Working directory the remote command or interactive shell starts in, like winrs -d (only with command and shell). Default: the user's profile directory, or C:\Users\Default when that profile is not loaded (see --profile). |
--env <NAME=VALUE> |
Environment variable set in the remote shell, like winrs -env (only with command and shell). Repeatable — one occurrence per variable; the value is split on the first =, so it may itself contain =. |
--profile |
Load the user profile in the remote shell (only with command and shell): %APPDATA%, the user's HKEY_CURRENT_USER hive. Not loaded by default, the reverse of winrs, where -noprofile turns it off; see Loading the user profile[3]. |
-i, --stdin |
Always forward the local standard input to the remote command (only with command); forwarding is automatic when it is redirected, see below. |
--https |
Connect over HTTPS. The certificate is validated against the Java trust store: for a self-signed or private-CA host, run java -Djavax.net.ssl.trustStore=<file> -jar ... (see Trusting a certificate[4]). |
--https-permissive |
Trust any HTTPS certificate and hostname. Intentionally insecure: testing and isolated hosts only. Requires --https. |
--ntlm |
Authenticate with NTLM (the default). |
--kerberos |
Authenticate with Kerberos. Requires --https. |
--basic |
Authenticate with HTTP Basic. Use with --https so the credential is not sent in the clear. |
--kerberos-kdc <host> |
Set the Kerberos KDC for this invocation; the realm is inferred from its DNS suffix (see below). |
--kerberos-realm <realm> |
Override the realm inferred from --kerberos-kdc. |
--allow-delegate |
Let the remote command use your Kerberos credentials to reach a further host (a UNC path, another server), like winrs -allowdelegate. Requires --kerberos and a forwardable ticket (see Kerberos). |
--help |
Print the usage summary. |
--version |
Print the build version. |
--ntlm, --kerberos, and --basic are mutually exclusive, as are the two password options.
File options
The options of ls, stat and cat come after the subcommand, before or after the path:
| Option | Description |
|---|---|
--glob <pattern> |
ls: only the entries whose name matches a Windows wildcard pattern: * any sequence, ? one character, case-insensitive, whole name (*.log matches app.log, not app.log.1). |
--recursive |
ls: list the whole tree below the directory, depth-first. |
--depth <n> |
ls: list the tree down to depth n (1 is the directory's own entries); implies --recursive. |
--files-only |
ls: files only. |
--directories-only |
ls: directories only. Mutually exclusive with --files-only. |
--modified-after <date> |
ls: only the entries last modified after an ISO-8601 date (2026-01-31, midnight UTC) or date-time with an offset (2026-01-31T12:00:00Z, 2026-01-31T14:00:00+02:00). |
--min-size <bytes> |
ls: only the files of at least this size (directories are not filtered by size). |
--json |
ls, stat: print UTF-8 JSON Lines[2] instead of text. |
--offset <bytes> |
cat: start at this byte; a negative offset counts from the end of the file. |
--length <bytes> |
cat: read at most this many bytes. |
--charset <name> |
cat: decode the file with this charset (UTF-8, UTF-16LE, windows-1252…) and print the text, instead of copying the bytes. |
Passwords
If neither -p nor -pf is supplied, the CLI securely requests the password from the interactive console without echoing it. The prompt needs a console, and there is none when standard input or output is redirected or piped (| jq, > out.txt): such runs must use --password-file (or, less securely, --password).
Password files are decoded as UTF-8. Exactly one final LF, CRLF, or CR is removed; every other byte — including whitespace, earlier line endings, and a byte order mark — is part of the password.
Kerberos
With --kerberos, pass the host's FQDN to -h, not an IP address: the service principal is HTTP/<host> (see Kerberos[5]). By default, Kerberos uses the ambient JDK configuration (krb5.conf / -Djava.security.krb5.*). The CLI can instead configure the JDK for the current invocation with --kerberos-kdc <host>. If no --kerberos-realm is supplied, the realm is inferred by removing the KDC hostname's first DNS label and uppercasing the remaining suffix — for example, a KDC of camus.internal.example.net infers the realm INTERNAL.EXAMPLE.NET. The inference follows a common Active Directory DNS naming convention; it is not guaranteed by Kerberos, so specify --kerberos-realm when the realm does not match the KDC's DNS suffix or when the KDC is not a fully qualified DNS name. Both options are valid only with --kerberos, and --kerberos-realm requires --kerberos-kdc.
--allow-delegate forwards your Kerberos ticket to the host, so the remote command can reach a further host as you — a UNC path, another server — where it would otherwise get access denied. The ticket must be forwardable, which the JDK asks for only when a krb5.conf says forwardable = true in its [libdefaults] section (--kerberos-kdc cannot set it): otherwise the CLI exits with an authentication error (77) saying so. Only delegate to hosts you trust; see Credential delegation[6] for the details.
Basic
--basic authenticates with HTTP Basic, sending the credential in the Authorization header of every request. It has no message protection, so the credential and payload are plaintext over HTTP — combine it with --https so TLS protects them. Do not combine it with --https-permissive: any host impersonating the server would receive the password. For a self-signed host, trust its certificate instead (see --https). On Windows, use a bare local account name with -u: the WinRM service rejects Basic for domain accounts and for any DOMAIN\-qualified name.
See Authentication[7] for how NTLM, Kerberos, and Basic work on the wire.
Output
Diagnostics go only to standard error, so standard output can always be piped or parsed.
wql
Each result row is printed as one compact UTF-8 JSON object per line (JSON Lines[2]); property order follows the WinRM response. The rows are streamed: each one is written and flushed as it arrives from the host, so a downstream pipe starts working immediately and memory stays bounded regardless of the result size. A mid-stream failure can therefore leave partial output on standard output, signalled by the nonzero exit code.
command
Remote stdout and stderr are forwarded live to the corresponding local streams while the command runs — each chunk is flushed as it arrives, so a long-running command can be followed in real time. The output is decoded as UTF-8: the remote shell is created with console code page 65001, so no code-page detection is needed and non-ASCII output survives whatever the remote locale. A few legacy tools (net.exe, chcp.com) ignore the console code page: their non-ASCII characters arrive as U+FFFD (see Character encoding[8]).
When the local standard input is piped or redirected, it is forwarded as the remote command's standard input, with pipe semantics, so filters just work:
java -jar winrm-java-standalone.jar -h server -u 'DOMAIN\user' -pf pw.txt command sort < data.txt
Forwarding engages automatically when the standard input is detectably redirected: it is a seekable file (any < file redirection, including an empty file or the null device), or bytes are already waiting on it at startup (a normal pipe). An interactive terminal is never consumed, even when only the output is redirected (... command hostname > result.txt). The one undetectable case is a pipe whose producer has written nothing by the time the CLI starts: pass -i/--stdin to force forwarding there. The input is delivered in full before the output is read: piping a large input into a command that floods its output at the same time can deadlock both sides (the classic pipe deadlock). Input the command does not read, because it exits first, is discarded, as with a local pipe.
ls, stat, cat, get
See Remote files.
Interactive shell
java -jar winrm-java-standalone.jar -h server.example.net -u 'DOMAIN\user' -pf pw.txt shell
shell starts cmd.exe on the remote host and bridges it to the local terminal until the remote shell exits (type exit, or send end-of-input — Ctrl+Z then Enter on Windows, Ctrl+D elsewhere — which closes the remote shell's input, so cmd.exe exits). The remote exit code is propagated through the usual exit-code contract.
- Echo is off — the remote shell runs
cmd.exe /Q, so the input you forward is never repeated back: your terminal already shows what you type, and the output stream carries the prompts and the command output only. - The session runs under the host's ANSI code page (from
Win32_OperatingSystem.CodeSet, 1252 when the host cannot answer), not UTF-8: under code page 65001, a remotecmd.exereading its input loses every non-ASCII character, as withwinrs. So characters outside that code page cannot be typed or displayed (éon a Western-European host is fine).wqlandcommandkeep full UTF-8 output, and piped input tocommandtransfers bytes unconverted. - Line-oriented, like
winrs— input is line-buffered by the local terminal and forwarded when you press Enter. There is no raw-terminal/PTY mode: full-screen programs, cmd.exe line editing, tab completion, and ANSI cursor control are not supported. Command output echoes back with sub-second latency; a line typed while the session is idle can wait up to the poll cadence (about one second — the WSMan protocol's floor for a bounded poll) before it is forwarded. - Ctrl+C interrupts the remote command, not the session — it is forwarded as the WSMan
ctrl_csignal, which stops the running remote child (like a console Ctrl+C) and returns to the remote prompt. - An idle session does not time out —
-t/--timeoutbounds each protocol round trip, and every round trip of an idle session completes with the protocol's “nothing yet” answer. Only a server that stops answering altogether trips the timeout. A--timeoutbelow 1000 ms is rejected forshell: one poll round trip cannot complete faster.
Remote files
ls, stat, cat, and get reach the remote file system through the WinRM connection itself — no SMB, no share, no extra port — with the library's remote file access[9]: a small PowerShell script does the work on the host, which needs PowerShell 2.0 or later in FullLanguage mode. Nothing is written on the host.
# List: long format, machine-readable timestamps and sizes
java -jar winrm-java-standalone.jar -h server -u 'DOMAIN\user' -pf pw.txt \
ls 'C:\inetpub\logs' --glob '*.log' --depth 3
# One path's properties
java -jar winrm-java-standalone.jar ... stat 'C:\Windows\Temp\collect.log'
# Content to stdout
java -jar winrm-java-standalone.jar ... cat 'C:\Windows\Temp\collect.log'
java -jar winrm-java-standalone.jar ... cat 'D:\logs\huge.log' --offset -8192 # the last 8 KiB
java -jar winrm-java-standalone.jar ... cat 'D:\logs\huge.log' --offset 1073741824 --length 65536
java -jar winrm-java-standalone.jar ... cat 'C:\legacy\report.txt' --charset windows-1252
# Whole file to a local file, digest-verified
java -jar winrm-java-standalone.jar ... get 'C:\Windows\Temp\collect.log' ./collect.log
ls
ls lists the entries of a directory — or, with --recursive or --depth, the whole tree, depth-first — one line per entry, as the host walks the tree: each line is written and flushed as it arrives, so a pipe starts working immediately and memory stays bounded. The format is fixed and independent of the locale:
d----- 0 2026-01-02T03:04:05.6789012Z C:\inetpub\logs\LogFiles
-a---- 1048576 2026-01-02T03:04:05.6789012Z C:\inetpub\logs\LogFiles\u_ex260101.log
- The mode, like the
Modecolumn of Windows PowerShell:ddirectory,aarchive,rread-only,hhidden,ssystem,lreparse point (a junction or a symbolic link),-otherwise. - The size in bytes (0 for a directory), right-aligned on 12 characters.
- The last modification time: ISO-8601 UTC with the 100 ns precision of Windows file times, always 28 characters, so it sorts as a string.
- The full path, as the host reports it: the rest of the line.
Every filter is evaluated on the host, so only the matching entries travel. The filters select what is reported, not where the walk goes: with --recursive, every subdirectory is traversed, whatever the glob. Reparse points are listed, never descended into, so a junction looping back to its parent cannot make the walk run forever.
A subdirectory that cannot be read (typically, access denied) does not stop the walk: its path is reported on stderr (winrm-java: cannot read directory C:\...), the rest of the tree is listed, and ls then exits with 1. The directory named on the command line must be readable: otherwise ls fails. An administrator's WinRM session holds the backup privilege, so directory permissions mostly stop other accounts.
With --json, each entry is one UTF-8 JSON object per line (JSON Lines[2]):
{"path":"C:\\inetpub\\logs\\LogFiles\\u_ex260101.log","mode":"-a----","attributes":32,"size":1048576,"lastModified":"2026-01-02T03:04:05.6789012Z","created":"2025-12-01T08:00:00.0000000Z","lastAccessed":"2026-01-02T03:04:05.6789012Z"}
attributes is the raw Windows FileAttributes value, for the flags the mode leaves out (e.g. 2048 compressed, 16384 encrypted). attributes and size are numbers; the timestamps have the format above, so they compare correctly as strings — jq 'select(.lastModified > "2026-01-01")'. The text output encodes the paths for the local console, which may not represent every character; --json is always UTF-8.
stat
stat prints the properties of one file or directory, one name: value per line, with the fields and formats of ls --json (which stat also accepts as --json):
path: C:\Windows\Temp\collect.log
mode: -a----
attributes: 32
size: 1048576
lastModified: 2026-01-02T03:04:05.6789012Z
created: 2025-12-01T08:00:00.0000000Z
lastAccessed: 2026-01-02T03:04:05.6789012Z
A path that does not exist exits with 66, a path that cannot be read (access denied, for example) with 70: stat doubles as an existence test.
cat
cat writes the bytes of the file to stdout as they arrive — no charset conversion, no newline translation — so binary content and redirection both work: ... cat 'C:\x.bin' > x.bin produces a byte-exact copy in POSIX shells and in cmd.exe. Not in Windows PowerShell 5.1, whose > decodes a native program's output as text and writes it back re-encoded: use get there, or run the redirection in cmd.exe. PowerShell 7.4 and later keep the bytes.
--offset <n>starts at byten. A negative offset counts from the end:--offset -8192reads the last 8 KiB, the size being read by the same remote invocation that seeks, so a growing log is tailed from its current end. The seek happens on the host: the end of a huge log costs the same as its start. An offset past the end reads nothing.--length <n>reads at mostnbytes, from the offset or from the start of the file.--charset <name>decodes the file with that charset and prints the text in the local console's encoding, instead of the bytes: the way to read a file whose encoding is not the local one. A range boundary can split a multibyte character, printed asU+FFFD.
When the output is closed early — ... cat 'D:\logs\huge.log' | head — cat stops the remote read instead of transferring the rest of the file for nobody, and exits with 74. The transfer runs at about 2 MB/s (see Read performance[10]): logs and configuration files, not bulk data.
get
get downloads the whole file to a local file: digest-verified, atomic, and skipped when the local copy is already identical[11]. Without a local path, the file is written in the current directory under its remote name; an existing directory receives it under its remote name too. Nothing is printed on success. --timeout is the deadline of the whole download: at about 1.8 MB/s, the default 60 seconds covers files up to about 100 MB — raise it for larger ones.
Quoting remote paths
Remote paths reach the host untouched (the client quotes them for PowerShell itself), but the local shell parses them first:
- POSIX shells (bash, zsh, Git Bash): single-quote Windows paths —
'C:\path with spaces\x.log','\\server\share\x.log'. Inside double quotes,\\becomes\and\"is a literal quote:"\\server\share"loses a backslash, and"C:\logs\"does not end where it seems. - cmd.exe and Windows PowerShell 5.1: a backslash just before a closing double quote escapes the quote —
"C:\my logs\"arrives asC:\my logs", merged with the arguments that follow. This happens with PowerShell's single quotes too ('C:\my logs\'), which it turns into double quotes for a path with spaces. Leave the trailing backslash out ("C:\my logs"), or double it ("C:\my logs\\").
Timeout semantics
-t/--timeout follows the operation:
- For
wql,ls, andcat, it is the inactivity timeout of the stream — the longest tolerated silence between two server responses. A large result or file can stream for longer than the timeout, as long as the server keeps answering; a walkinglssignals it is alive every second. - For
command,stat, andget, it is the overall deadline covering the whole operation. - For
shell, it bounds each protocol round trip; an idle interactive session never trips it (see Interactive shell).
See Timeouts and Errors[12] for the underlying semantics.
Exit codes
| Exit code | Meaning |
|---|---|
0 |
Success. |
0–255 |
Remote command exit code (command, shell), when it fits in that range. |
1 |
ls: some directories could not be read (reported on stderr); the rest of the tree was listed. |
64 |
Invalid CLI usage. |
66 |
Remote path not found (ls, stat, cat, get). |
69 |
Connection, DNS, socket, or TLS failure. |
70 |
WinRM protocol or other remote failure (including access denied to a remote path, an invalid WQL query, and a remote exit code not representable in 0–255). |
74 |
Local I/O failure: stdout closed or not writable (ls, stat, cat), or a file-system error on the local file of get (access denied, a missing drive). |
77 |
Authentication failure. |
124 |
Operation timeout. |
Examples
Run a WQL query over NTLM and HTTP, reading the password from a file:
java -jar winrm-java-3.1.04-standalone.jar \
--hostname server.example.net --username 'DOMAIN\user' \
--password-file password.txt --ntlm \
wql 'SELECT Name,State FROM Win32_Service'
Run a remote command over HTTPS:
java -jar winrm-java-3.1.04-standalone.jar \
-h server.example.net -u Administrator -pf password.txt --https \
exec ipconfig /all
Kerberos with an explicit KDC (realm inferred as INTERNAL.EXAMPLE.NET):
java -jar winrm-java-3.1.04-standalone.jar \
-h server.internal.example.net -u 'DOMAIN\user' -pf password.txt \
--https --kerberos --kerberos-kdc camus.internal.example.net \
command whoami
List a share on a third machine from the remote host, with Kerberos credential delegation (the krb5.conf says forwardable = true):
java -Djava.security.krb5.conf=krb5.conf -jar winrm-java-3.1.04-standalone.jar \
-h server.internal.example.net -u 'DOMAIN\user' -pf password.txt \
--https --kerberos --allow-delegate \
exec dir '\\fileserver\share'
Stream WQL rows into jq as they arrive:
java -jar winrm-java-3.1.04-standalone.jar \
-h server.example.net -u 'DOMAIN\user' -pf password.txt \
wql 'SELECT * FROM Win32_NTLogEvent' | jq -r .Message
- [1] https://github.com/metricshub/winrm-java/releases/latest
- [2] https://jsonlines.org/
- [3] commands.html#loading-the-user-profile
- [4] tls.html#trusting-a-certificate
- [5] authentication.html#kerberos-spnego
- [6] authentication.html#credential-delegation
- [7] authentication.html
- [8] commands.html#character-encoding
- [9] files.html
- [10] files.html#read-performance
- [11] file-transfers.html#downloading-a-file
- [12] timeouts-and-errors.html
