Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 37 additions & 30 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,43 @@

All notable changes to this project are documented in this file.

## [Unreleased] — 2.0.0
## 3.1.00

### Fixed

- **A long-lived client no longer exhausts the host's operation quota** (#196). Every command
run in a shell holds one of the user's WSMan operations until the shell is deleted, even once
terminated, and the client reused its shell forever: a client polling indefinitely ended up
with every command refused with WSManFault 2150859174 (*the maximum number of concurrent
operations for this user has been exceeded*), after 15 commands on Windows Server 2008 R2 and
1500 on later versions, until it was recreated. The client now replaces its shell every 10
commands (the new `WinRMClient.Builder.maxCommandsPerShell(int)` changes that number) and never
reuses a shell holding a command it could not terminate (its terminate `Signal` failed or was
skipped). On Windows Server 2008 R2, whose quota fault carries its WSManFault code, a command
the quota refuses in a shell that already ran commands is also retried once in a new shell;
later versions send that fault with no code, so nothing reliable identifies it. The new shell
gets the same working directory, environment and profile; deleting the old one ends any process
a previous command left running in it, as closing the client always did.

- **A streaming read resumed after a long pause no longer times out spuriously** (#198). When a
streaming consumer (e.g. a `RemoteProcess` read slowly) paused longer than the inactivity
timeout and the host dropped the idle connection meanwhile, the reconnection inherited the
expired deadline of the previous request: its TCP connect and TLS handshake got a 1 ms budget
and failed with a timeout (*No response from the WinRM service*). Each
reconnection now gets a full inactivity timeout of its own.

- **A WQL row is no longer dropped when none of its selected properties came back** (#201).
WinRM leaves an empty or `NULL` array out of the response, so `SELECT IPSecPermitTCPPorts FROM
Win32_NetworkAdapterConfiguration` returned no rows at all, where WMI returns one per adapter.
Each instance is now a row, on which `string()` returns `null` for the missing property.
`WqlResult.columns()` now also reads the property names of every row, not just the first one:
with `SELECT * FROM Win32_NetworkAdapterConfiguration`, a first adapter without IP configuration
hid `IPAddress`, `DefaultIPGateway`, ... from the columns of all the rows.

## 2.0.00 to 3.0.00

Highlights of these versions; see [GitHub Releases](https://github.com/metricshub/winrm-java/releases)
for the complete notes of each one.

### Added — HTTP Basic authentication

Expand Down Expand Up @@ -158,41 +194,12 @@ Consequences:

### Fixed

- **A long-lived client no longer exhausts the host's operation quota** (#196). Every command
run in a shell holds one of the user's WSMan operations until the shell is deleted, even once
terminated, and the client reused its shell forever: a client polling indefinitely ended up
with every command refused with WSManFault 2150859174 (*the maximum number of concurrent
operations for this user has been exceeded*), after 15 commands on Windows Server 2008 R2 and
1500 on later versions, until it was recreated. The client now replaces its shell every 10
commands (the new `WinRMClient.Builder.maxCommandsPerShell(int)` changes that number) and never
reuses a shell holding a command it could not terminate (its terminate `Signal` failed or was
skipped). On Windows Server 2008 R2, whose quota fault carries its WSManFault code, a command
the quota refuses in a shell that already ran commands is also retried once in a new shell;
later versions send that fault with no code, so nothing reliable identifies it. The new shell
gets the same working directory, environment and profile; deleting the old one ends any process
a previous command left running in it, as closing the client always did.

- **A streaming read resumed after a long pause no longer times out spuriously** (#198). When a
streaming consumer (e.g. a `RemoteProcess` read slowly) paused longer than the inactivity
timeout and the host dropped the idle connection meanwhile, the reconnection inherited the
expired deadline of the previous request: its TCP connect and TLS handshake got a 1 ms budget
and failed with a timeout (*No response from the WinRM service*). Each
reconnection now gets a full inactivity timeout of its own.

- **WQL array properties keep all their elements** (#189). A WMI array (`IPAddress`,
`DefaultIPGateway`, `Capabilities`, ...) used to yield only its last element, without any
error. Its elements are now joined with `|` (`"192.0.2.10|fe80::1"`); the new
`WinRMClient.Builder.arraySeparator(String)` changes the separator. The `WqlRow` Javadoc now
says what the code does: a WMI `NULL` is an empty string, `null` means "no such property".

- **A WQL row is no longer dropped when none of its selected properties came back** (#201).
WinRM leaves an empty or `NULL` array out of the response, so `SELECT IPSecPermitTCPPorts FROM
Win32_NetworkAdapterConfiguration` returned no rows at all, where WMI returns one per adapter.
Each instance is now a row, on which `string()` returns `null` for the missing property.
`WqlResult.columns()` now also reads the property names of every row, not just the first one:
with `SELECT * FROM Win32_NetworkAdapterConfiguration`, a first adapter without IP configuration
hid `IPAddress`, `DefaultIPGateway`, ... from the columns of all the rows.

- **Streaming terminals now report protocol failures as `WinRMClientException`** (#188).
`WqlRequest.stream()`, `CommandRequest.start()`, `RemoteFile.openStream()`/`openReader()`,
`RemoteDirectoryListing.stream()` and the closing of a `RemoteProcess` let raw
Expand Down
2 changes: 1 addition & 1 deletion src/site/markdown/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Everything between `command(...)` and `execute()` is optional (see
| --- | --- | --- |
| `timeout(Duration)` | the client's timeout | Wall-clock deadline covering file uploads and the command itself with `execute()`; inactivity timeout with `start()`. |
| `charset(Charset)` | `UTF-8` | The charset used to decode the command output (see below). |
| `workingDirectory(String)` | remote default | Working directory of the remote process. The remote shell is created by the client's **first** command (remote file operations and `uploadFile(...)` count too) and reused afterward, so this only takes effect on that first command, and never on a request with `upload(...)`. |
| `workingDirectory(String)` | remote default | Working directory of the remote process. The remote shell is created by the client's **first** command (remote file operations and `uploadFile(...)` count too) and reused afterward (every shell that [replaces it](#shell-reuse) gets the same settings), so this only takes effect on that first command, and never on a request with `upload(...)`. |
| `environment(String, String)` | none | Environment variable set in the remote shell, like `winrs -env` — call it once per variable, insertion order is preserved. Shell-scoped like `workingDirectory`: only takes effect on the client's **first** command. |
| `upload(Path...)` | none | Local files to copy to the host before running (see below). |
| `stdin(String)` / `stdin(Path)` / `stdin(InputStream)` | none | Standard input fed to the command — the remote equivalent of a `< file` redirection (see below). |
Expand Down
7 changes: 6 additions & 1 deletion src/site/markdown/timeouts-and-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ transparently when the server drops an idle one). What is **never** retried:
* credential rejections
([`WinRMAuthenticationException`](apidocs/org/metricshub/winrm/exceptions/WinRMAuthenticationException.html));
* WSMan faults
([`WinRMFaultException`](apidocs/org/metricshub/winrm/exceptions/WinRMFaultException.html)).
([`WinRMFaultException`](apidocs/org/metricshub/winrm/exceptions/WinRMFaultException.html)),
except the refusals that prove a command never ran, whatever the policy: a shell the host
reaped and, on Windows Server 2008 R2, the operation quota are retried once in a new shell (see
[Shell reuse](commands.html#shell-reuse)), and [file transfers](file-transfers.html) and
[remote file operations](files.html) then retry a quota refusal up to 4 more times, with
escalating delays (5/10/15/20&nbsp;s) bounded by their timeout.

Retries stay inside each operation's **wall-clock deadline**: when the timeout elapses mid-pause,
the operation fails with
Expand Down
3 changes: 2 additions & 1 deletion src/site/markdown/wql.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ lookups in it are case-sensitive.

* When you select explicit properties (`SELECT Name, State FROM ...`), the columns keep the **order
of the query** and the **exact case reported by WMI**.
* With `SELECT * FROM ...`, the columns are in **alphabetical order** (case-insensitive).
* With `SELECT * FROM ...`, the columns are the properties of **every** row (a row may lack an
empty array that others have), in **alphabetical order** (case-insensitive).
* If the query returns no rows, the columns are the selected property names in lower case (WMI's
own casing cannot be recovered from an empty result set), or an empty list for `SELECT *`.

Expand Down
Loading