diff --git a/CHANGELOG.md b/CHANGELOG.md
index 165a794..e77c21d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,8 +45,9 @@ Consequences:
### ⚠️ Breaking — the CXF backend was removed
Version 2.0.0 removes the legacy Apache CXF backend. The dependency-free client introduced in the
-previous release is the only implementation; the public API is unchanged, so calling code is
-unaffected. Consequences:
+previous release is the only implementation; the documented entry points are unchanged, so typical
+calling code is unaffected (though a few CXF/SMB-only public types were removed — see Removed).
+Consequences:
- **WinRM over HTTPS with self-signed certificates**: unlike the CXF-based client — which silently
trusted every TLS certificate and skipped hostname verification — this client **validates the
@@ -56,8 +57,6 @@ unaffected. Consequences:
(`-Djavax.net.ssl.trustStore=...`); or
- disable TLS validation with `-Dorg.metricshub.winrm.tls.insecure=true`
(**insecure — for testing only**).
-- Setting `-Dorg.metricshub.winrm.backend=cxf` now fails with a clear error instead of selecting
- the removed backend: remove the property (or stay on winrm-java 1.x).
- The jar shrinks dramatically: the Apache CXF / JAX-WS / JAXB stack is gone, and with the SMB
file copy replaced by a WinRM-native transfer (see above), the library has **zero runtime
dependencies**.
diff --git a/README.md b/README.md
index d5bbec0..1823662 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,6 @@


-This project uses [WS-Man Client](https://github.com/OpenNMS/wsman) and [winrm4j](https://github.com/cloudsoft/winrm4j/)
-
See **[Project Documentation](https://metricshub.org/winrm-java)** and the [Javadoc](https://metricshub.org/winrm-java/apidocs) for more information on how to use this library in your code.
The Windows Remote Management (WinRM) Java Client is a library that enables to:
@@ -16,7 +14,8 @@ The Windows Remote Management (WinRM) Java Client is a library that enables to:
> ## ⚠️ Upgrading from 1.x
>
> Version 2.0.0 **removed the legacy Apache CXF backend**: the dependency-free **light** client is
-> the only implementation (same public API — calling code is unaffected). Two consequences:
+> the only implementation (same documented entry points; a few CXF/SMB-only public types were
+> removed). The main consequence:
>
> * Unlike the CXF-based client, which silently trusted every TLS certificate, the light client
> **validates the server certificate and verifies the hostname by default**.
@@ -24,8 +23,6 @@ The Windows Remote Management (WinRM) Java Client is a library that enables to:
> will fail** during the TLS handshake unless you install the server certificate (or its issuing
> CA) into a Java trust store (e.g. `-Djavax.net.ssl.trustStore=...`) or disable TLS validation
> with `-Dorg.metricshub.winrm.tls.insecure=true` (**insecure — for testing only**).
-> * Setting `-Dorg.metricshub.winrm.backend=cxf` now fails with a clear error instead of selecting
-> the removed backend. Remove the property (or stay on winrm-java 1.x).
## The WinRM client
diff --git a/pom.xml b/pom.xml
index 00c8572..5d5105e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,8 @@
- 2025-04-03T12:15:29Z
+
+ 2026-07-24T00:00:00Z
@@ -202,12 +203,82 @@
+
+
+ maven-site-plugin
+ 4.0.0-M16
+
+
+ org.sentrysoftware.maven
+ maven-skin-tools
+ 1.8.00
+
+
+
+
+
+
+
+
+ maven-project-info-reports-plugin
+ 3.9.0
+
+
+
+ ci-management
+ dependencies
+ dependency-info
+ distribution-management
+ issue-management
+ licenses
+ plugins
+ scm
+ summary
+ team
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+ 3.6.0
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+ javadoc
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-report-plugin
+ 3.5.6
+
+
maven-pmd-plugin
@@ -222,6 +293,17 @@
+
+
+ maven-changelog-plugin
+
+
+
+
+
+
+
diff --git a/src/site/markdown/authentication.md b/src/site/markdown/authentication.md
new file mode 100644
index 0000000..4cd6ecb
--- /dev/null
+++ b/src/site/markdown/authentication.md
@@ -0,0 +1,111 @@
+keywords: authentication, ntlm, kerberos, spnego, domain, realm, kdc, krb5, ticket cache
+description: Authenticate to WinRM with NTLM or Kerberos (SPNEGO), including domain accounts and Kerberos configuration.
+
+# Authentication
+
+
+
+The client authenticates with either **NTLM** or **Kerberos (SPNEGO)**. The scheme is chosen by the
+`authentications` argument, a
+`List<`[`AuthenticationEnum`](apidocs/org/metricshub/winrm/service/client/auth/AuthenticationEnum.html)`>`
+that both `executeWql(...)` and `WinRMCommandExecutor.execute(...)` accept.
+
+```java
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+
+singletonList(NTLM); // NTLM only (also the default when null or empty)
+singletonList(KERBEROS); // Kerberos only
+```
+
+If the list is `null` or empty, **NTLM** is used.
+
+## User name and domain
+
+The user name may be given as `DOMAIN\user` or as a bare `user`. When a backslash is present, the
+part before it is treated as the Windows domain and the part after it as the account name. In Java,
+remember to escape the backslash in a string literal:
+
+```java
+"DOMAIN\\Administrator" // domain = DOMAIN, user = Administrator
+"Administrator" // no domain
+```
+
+## NTLM
+
+NTLM is the default. It works over both transports:
+
+* **HTTP** — the WinRM payload is protected with **NTLM message encryption**, so credentials and
+ data are not sent in the clear even without TLS.
+* **HTTPS** — NTLM runs inside the TLS tunnel. See [TLS / HTTPS](tls.html).
+
+NTLM needs no extra configuration beyond the user name and password.
+
+## Kerberos (SPNEGO)
+
+Kerberos authentication uses SPNEGO through the JDK's GSS-API and **requires HTTPS**.
+
+```java
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;
+
+executeWql(
+ HTTPS, "server.example.com", null,
+ "DOMAIN\\Administrator", password, null,
+ "SELECT Name FROM Win32_ComputerSystem",
+ 30_000L,
+ ticketCache, // optional java.nio.file.Path to a ticket cache
+ singletonList(KERBEROS)
+);
+```
+
+### Kerberos configuration
+
+By default, Kerberos relies on the **ambient JDK Kerberos configuration** — the platform `krb5.conf`
+(or the file named by `-Djava.security.krb5.conf`), or the realm and KDC given directly with
+`-Djava.security.krb5.realm` and `-Djava.security.krb5.kdc`:
+
+```bash
+java -Djava.security.krb5.realm=EXAMPLE.COM \
+ -Djava.security.krb5.kdc=dc01.example.com \
+ -cp ... MyApp
+```
+
+The optional `ticketCache` parameter points to a Kerberos ticket cache to use for the connection.
+
+## Choosing the scheme on the command line
+
+The standalone jar selects the scheme with `--ntlm` (the default) or `--kerberos`. The two are
+mutually exclusive, and `--kerberos` requires `--https`:
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.example.com -u 'DOMAIN\user' -pf password.txt \
+ --https --kerberos \
+ command whoami
+```
+
+Instead of relying on the ambient configuration, the CLI can set the JDK Kerberos configuration for
+the current invocation:
+
+| Option | Meaning |
+| --- | --- |
+| `--kerberos-kdc ` | Sets the KDC and, unless `--kerberos-realm` is given, infers the realm from the KDC's DNS suffix. |
+| `--kerberos-realm ` | Overrides the inferred realm. Requires `--kerberos-kdc`. |
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.internal.example.com -u 'DOMAIN\user' -pf password.txt \
+ --https --kerberos --kerberos-kdc dc01.internal.example.com \
+ command whoami
+```
+
+Here the realm is inferred as `INTERNAL.EXAMPLE.COM` by dropping the KDC's first DNS label and
+upper-casing the rest. This follows a common Active Directory naming convention but is not
+guaranteed by Kerberos — pass `--kerberos-realm` when the realm does not match the KDC's DNS suffix,
+or when the KDC is not a fully qualified DNS name.
+
+## See also
+
+* [TLS / HTTPS](tls.html) — required for Kerberos and recommended for NTLM
+* [Timeouts and Errors](timeouts-and-errors.html) — how authentication failures surface
diff --git a/src/site/markdown/commands.md b/src/site/markdown/commands.md
new file mode 100644
index 0000000..f14414f
--- /dev/null
+++ b/src/site/markdown/commands.md
@@ -0,0 +1,142 @@
+keywords: command, execute, cmd, stdout, stderr, exit code, file copy, script
+description: Execute remote commands with WinRMCommandExecutor, capture output and exit codes, and copy local files to the host.
+
+# Remote Commands
+
+
+
+The client can run an arbitrary command on the remote host and hand back its standard output,
+standard error, and exit code. It can also copy local script files to the host first and rewrite the
+command so it references them.
+
+## `WinRMCommandExecutor.execute(...)`
+
+Commands are run with the static method
+[`WinRMCommandExecutor.execute(...)`](apidocs/org/metricshub/winrm/command/WinRMCommandExecutor.html),
+which returns a
+[`WindowsRemoteCommandResult`](apidocs/org/metricshub/winrm/WindowsRemoteCommandResult.html).
+
+```java
+import static java.util.Collections.singletonList;
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+
+import org.metricshub.winrm.WindowsRemoteCommandResult;
+import org.metricshub.winrm.command.WinRMCommandExecutor;
+
+WindowsRemoteCommandResult result = WinRMCommandExecutor.execute(
+ "ipconfig /all", // command (mandatory)
+ HTTPS, // protocol
+ "server.example.com", // hostname (mandatory)
+ null, // port (null → 5985 for HTTP, 5986 for HTTPS)
+ "DOMAIN\\Administrator", // username (mandatory)
+ "the-password".toCharArray(), // password
+ null, // working directory (nullable)
+ 30_000L, // timeout in milliseconds
+ null, // local files to copy (nullable)
+ null, // Kerberos ticket cache (null for NTLM)
+ singletonList(NTLM) // authentication schemes
+);
+
+System.out.println("exit code: " + result.getStatusCode());
+System.out.print(result.getStdout());
+System.err.print(result.getStderr());
+```
+
+### Parameters
+
+| Parameter | Type | Notes |
+| --- | --- | --- |
+| `command` | `String` | The command line to run. **Mandatory.** |
+| `protocol` | [`WinRMHttpProtocolEnum`](apidocs/org/metricshub/winrm/WinRMHttpProtocolEnum.html) | `HTTP` or `HTTPS`. `null` defaults to `HTTP`. |
+| `hostname` | `String` | Host name or IP address. **Mandatory.** |
+| `port` | `Integer` | `null` uses the protocol default. |
+| `username` | `String` | `DOMAIN\user` or `user`. **Mandatory.** |
+| `password` | `char[]` | The password. |
+| `workingDirectory` | `String` | Working directory of the spawned process on the remote host. May be `null`. |
+| `timeout` | `long` | Timeout in milliseconds. Must be **greater than zero**. |
+| `localFileToCopyList` | `List` | Local files to copy to the host before running (see below). May be `null`. |
+| `ticketCache` | `java.nio.file.Path` | Kerberos ticket cache path. `null` for NTLM. |
+| `authentications` | `List<`[`AuthenticationEnum`](apidocs/org/metricshub/winrm/service/client/auth/AuthenticationEnum.html)`>` | Requested schemes. `null` or empty means NTLM only. |
+
+## The result
+
+[`WindowsRemoteCommandResult`](apidocs/org/metricshub/winrm/WindowsRemoteCommandResult.html) is an
+immutable value:
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getStdout()` | `String` | The command's standard output. |
+| `getStderr()` | `String` | The command's standard error. |
+| `getStatusCode()` | `int` | The process exit code. |
+| `getExecutionTime()` | `float` | The measured execution time of the command. |
+
+## Character set
+
+The output character set does not need to be specified: the client detects the remote host's active
+code page before the command runs and decodes standard output and standard error accordingly.
+
+## Copying local files to the host
+
+Pass one or more local paths in `localFileToCopyList` to have them copied to the remote host before
+the command runs. Every reference to a listed file in the `command` string is rewritten to the path
+where the file lands on the host — typically under `C:\Windows\Temp`. For example:
+
+```java
+WinRMCommandExecutor.execute(
+ "CSCRIPT c:\\MyScript.vbs",
+ /* protocol */ HTTPS,
+ /* hostname */ "server.example.com",
+ /* port */ null,
+ /* username */ "DOMAIN\\Administrator",
+ /* password */ password,
+ /* workingDir */ null,
+ /* timeout */ 30_000L,
+ /* files */ java.util.List.of("c:\\MyScript.vbs"),
+ /* ticket */ null,
+ /* auth */ singletonList(NTLM)
+);
+```
+
+copies `c:\MyScript.vbs` to the host and runs the equivalent of:
+
+```text
+CSCRIPT "C:\Windows\Temp\...\MyScript.vbs"
+```
+
+How the transfer works, and what to keep in mind:
+
+* Files travel **through the WinRM command shell itself** — chunked base64, decoded on the host with
+ `certutil` and verified with a digest. There is **no SMB**: TCP port 445 does not need to be
+ reachable, no administrative share is created, and the copy works from any client OS.
+* The transfer is **content-addressed**: a fragment of the content digest is inserted before the
+ file extension (for example `MyScript.1a2b3c4d.vbs`), so files with the same name but different
+ content never overwrite each other. A script that inspects its own name (`WScript.ScriptName`)
+ therefore sees the digest fragment.
+* A file already present on the host with an identical digest is **not transferred again**.
+* The mechanism is designed for **small script files**, not bulk data — base64 over SOAP is not a
+ fast bulk transport.
+
+## Exceptions
+
+`execute(...)` declares:
+
+| Exception | When |
+| --- | --- |
+| `java.io.IOException` | An I/O error, including a copied-file problem. |
+| `java.util.concurrent.TimeoutException` | The operation did not complete within `timeout`. |
+| [`WindowsRemoteException`](apidocs/org/metricshub/winrm/exceptions/WindowsRemoteException.html) | Any problem on the remote host (in practice a [`WinRMException`](apidocs/org/metricshub/winrm/exceptions/WinRMException.html)). |
+
+See [Timeouts and Errors](timeouts-and-errors.html) for details.
+
+## From the command line
+
+The standalone jar runs a command with the `command` subcommand (aliases: `cmd`, `exec`, `run`).
+Standard output and standard error are forwarded to the corresponding local streams, and the
+process exits with the remote exit code when it fits in 0–255:
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.example.com -u 'DOMAIN\user' -pf password.txt --https \
+ exec ipconfig /all
+```
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index ad29726..cfd50ab 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -1,71 +1,100 @@
+keywords: winrm java client, windows remote management, wsman, dependency-free, overview
+description: A dependency-free Java client for Windows Remote Management (WinRM): run WQL queries and remote commands over NTLM or Kerberos.
+
# WinRM Java Client
-The Windows Remote Management (WinRM) Java Client is a library that enables to:
-* Connect to a remote Windows server using one of the two authentication types (NTLM, KERBEROS)
-* Execute WMI Query Language (WQL) queries which uses HTTP/HTTPS protocols.
-
-> ## ⚠️ Upgrading from 1.x
->
-> Version 2.0.0 **removed the legacy Apache CXF backend**: the dependency-free client is the only
-> implementation (same public API). Unlike the CXF-based client, which silently trusted every TLS
-> certificate, it **validates the server certificate and verifies the hostname by default**, so
-> **WinRM-over-HTTPS connections to hosts with self-signed or untrusted certificates will fail**
-> during the TLS handshake. To restore connectivity, either install the certificate into a Java
-> trust store or set `-Dorg.metricshub.winrm.tls.insecure=true` (insecure — for testing only).
-> The client supports NTLM over HTTP/HTTPS and Kerberos (SPNEGO) over HTTPS. Setting
-> `-Dorg.metricshub.winrm.backend=cxf` now fails with a clear error; remove the property (or stay
-> on winrm-java 1.x).
-
-# How to run the WinRM Client inside Java
-
-Add WinRM in the list of dependencies in your [Maven **pom.xml**](https://maven.apache.org/pom.html):
-
-```xml
-
-
-
- ${project.groupId}
- ${project.artifactId}
- ${project.version}
-
-
-```
+
+
+## Overview
+
+The **WinRM Java Client** is a small library that talks to the Windows Remote Management
+(WS-Management) service on a remote Windows host. It lets a Java application:
+
+* run **WQL / WMI queries** such as `SELECT Name, State FROM Win32_Service` and read the rows back
+ ([WQL Queries](wql.html)), and
+* **execute remote commands**, capturing standard output, standard error and the exit code —
+ optionally copying local script files to the host first ([Remote Commands](commands.html)).
+
+It supports **NTLM** over HTTP (with message encryption) and HTTPS, and **Kerberos (SPNEGO)** over
+HTTPS ([Authentication](authentication.html)).
+
+Since 2.0.0 the client has **zero runtime dependencies** (no Apache CXF / JAX-WS / JAXB stack, no SMB
+stack) and is immune by construction to JAXP `ServiceLoader` conflicts, because it uses the
+JDK-default XML factories. Problems are reported through exceptions only — the library pulls in no
+logging framework.
+
+> [!WARNING]
+> **Upgrading from 1.x?** Version 2.0.0 removed the legacy Apache CXF backend and now
+> **validates TLS certificates and verifies hostnames by default**. If you connect over HTTPS to
+> hosts with self-signed certificates, read [Migrating from 1.x](migrating-from-1x.html) first.
+
+## Add the dependency
+
+The library is published on [Maven Central](https://central.sonatype.com/artifact/${project.groupId}/${project.artifactId}).
-Use it as follows:
-```Java
-import static java.nio.file.Paths.get;
+> [!TABS]
+> * Maven
+> ```xml
+>
+> ${project.groupId}
+> ${project.artifactId}
+> ${project.version}
+>
+> ```
+> * Gradle (Groovy)
+> ```groovy
+> implementation '${project.groupId}:${project.artifactId}:${project.version}'
+> ```
+> * Gradle (Kotlin)
+> ```kotlin
+> implementation("${project.groupId}:${project.artifactId}:${project.version}")
+> ```
+
+See [Installation](installation.html) for the coordinates, the supported JDKs, and the standalone
+command-line jar.
+
+## A first WQL query
+
+Everything starts with the static
+[`WinRMWqlExecutor.executeWql(...)`](apidocs/org/metricshub/winrm/wql/WinRMWqlExecutor.html) method:
+
+```java
import static java.util.Collections.singletonList;
import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTP;
import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
import static org.metricshub.winrm.wql.WinRMWqlExecutor.executeWql;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-import org.metricshub.winrm.exceptions.WinRMException;
-import org.metricshub.winrm.exceptions.WqlQuerySyntaxException;
-import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
import org.metricshub.winrm.wql.WinRMWqlExecutor;
-public class Main {
+public class Example {
- public static void main(String[] args) throws WinRMException, WqlQuerySyntaxException, TimeoutException {
+ public static void main(String[] args) throws Exception {
- final String wqlQuery = "SELECT Name, Path, Type FROM Win32_Share";
- final String hostname = "my-hostname-or-ip-address";
- final String username = "my-username";
- final char[] password = "my-password".toCharArray();
- final long timeout = 50 * 1000L; // in milliseconds
- final Path ticketCache = get("path");
+ WinRMWqlExecutor result = executeWql(
+ HTTP, // protocol (HTTP or HTTPS)
+ "server.example.com", // hostname (mandatory)
+ 5985, // port (null for the protocol default)
+ "DOMAIN\\Administrator", // username (DOMAIN\user or user)
+ "the-password".toCharArray(), // password
+ null, // namespace (null → ROOT\CIMV2)
+ "SELECT Name, State FROM Win32_Service", // WQL query
+ 30_000L, // timeout in milliseconds
+ null, // Kerberos ticket cache (null for NTLM)
+ singletonList(NTLM) // authentication schemes
+ );
- // Authentication type : NTLM or KERBEROS
- final List authentications = singletonList(NTLM);
-
- // Execute a WQL Query in the hostname and print the result
- executeWql(HTTP, hostname, 5985, username, password, null, wqlQuery, timeout, ticketCache, authentications)
- .getRows().forEach(System.out::println);
-
- }
+ System.out.println(result.getHeaders()); // [Name, State]
+ result.getRows().forEach(System.out::println); // one List per row
+ }
}
```
+
+## Where to go next
+
+* [Installation](installation.html) — coordinates, supported JDKs, and the standalone CLI jar
+* [WQL Queries](wql.html) — query WMI and read the result
+* [Remote Commands](commands.html) — run commands and copy files to the host
+* [Authentication](authentication.html) — NTLM and Kerberos
+* [TLS / HTTPS](tls.html) — certificate validation and trust stores
+* [Timeouts and Errors](timeouts-and-errors.html) — timeout semantics and the exception surface
+* [Migrating from 1.x](migrating-from-1x.html) — the 2.0.0 breaking changes
diff --git a/src/site/markdown/installation.md b/src/site/markdown/installation.md
new file mode 100644
index 0000000..4a7461e
--- /dev/null
+++ b/src/site/markdown/installation.md
@@ -0,0 +1,88 @@
+keywords: install, maven, gradle, dependency, standalone, cli, jdk
+description: Add the WinRM Java Client to your build, or run the standalone command-line jar.
+
+# Installation
+
+
+
+## Coordinates
+
+The library is published on
+[Maven Central](https://central.sonatype.com/artifact/${project.groupId}/${project.artifactId}) under:
+
+| Field | Value |
+| --- | --- |
+| `groupId` | `${project.groupId}` |
+| `artifactId` | `${project.artifactId}` |
+| `version` | `${project.version}` |
+
+## Add it to your build
+
+> [!TABS]
+> * Maven
+> ```xml
+>
+> ${project.groupId}
+> ${project.artifactId}
+> ${project.version}
+>
+> ```
+> * Gradle (Groovy)
+> ```groovy
+> implementation '${project.groupId}:${project.artifactId}:${project.version}'
+> ```
+> * Gradle (Kotlin)
+> ```kotlin
+> implementation("${project.groupId}:${project.artifactId}:${project.version}")
+> ```
+
+For other build tools, the [dependency information](dependency-info.html) report lists the snippet
+for Ivy, SBT, Leiningen, and others.
+
+## Supported JDKs
+
+The library targets **Java 11** and runs on any later JDK.
+
+## Runtime dependencies
+
+Since 2.0.0 the client has **zero runtime dependencies**. There is no longer an Apache CXF /
+JAX-WS / JAXB stack, no BouncyCastle, and no SMB stack (`smbj`) on the classpath — the client speaks
+WS-Management over the JDK's own HTTP and XML APIs, and copies files through the WinRM channel
+itself. If you upgraded from 1.x, see [Migrating from 1.x](migrating-from-1x.html) for the details
+and the behavior changes this implies.
+
+## Standalone command-line jar
+
+Every release also ships a self-contained executable jar that bundles the client and a small CLI.
+Download `${project.artifactId}-${project.version}-standalone.jar` from the
+[latest release](https://github.com/metricshub/winrm-java/releases/latest), then run it with Java:
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar --help
+```
+
+Run a WQL query:
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ --hostname server.example.com --username 'DOMAIN\user' \
+ --password-file password.txt --ntlm \
+ wql 'SELECT Name, State FROM Win32_Service'
+```
+
+Run a remote command (`cmd`, `exec`, and `run` are aliases for `command`):
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.example.com -u Administrator -pf password.txt --https \
+ exec ipconfig /all
+```
+
+The CLI is covered in more detail throughout the [Usage](wql.html) pages; `--version` prints the
+build version.
+
+## Where to go next
+
+* [WQL Queries](wql.html)
+* [Remote Commands](commands.html)
+* [Authentication](authentication.html)
diff --git a/src/site/markdown/migrating-from-1x.md b/src/site/markdown/migrating-from-1x.md
new file mode 100644
index 0000000..797be58
--- /dev/null
+++ b/src/site/markdown/migrating-from-1x.md
@@ -0,0 +1,77 @@
+keywords: migration, upgrade, 1.x, 2.0, cxf, tls, smb, breaking changes
+description: What changed in WinRM Java Client 2.0.0 and how to upgrade from the 1.x releases.
+
+# Migrating from 1.x
+
+
+
+Version 2.0.0 is a major cleanup: the legacy Apache CXF backend and the SMB-based file copy are
+gone, leaving a **dependency-free** client. The **documented entry points are unchanged**, so typical
+calling code is unaffected — but a few CXF/SMB-only public types were removed (see the *Removed types*
+section below), and two runtime behaviors changed. Read this page before upgrading.
+
+## 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.
+* File copy for `localFileToCopyList` now goes **through the WinRM channel** instead of SMB.
+* A few CXF/SMB-only classes were removed.
+
+## TLS is validated by default
+
+The 1.x CXF client silently trusted every TLS certificate and skipped hostname verification. The
+2.0.0 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](tls.html) for details.
+
+## The CXF backend was removed
+
+The dependency-free client introduced in the previous release 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(...)`](commands.html) 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).
+* The remote copy is **content-addressed**: a fragment of the content digest is inserted before the
+ file extension (for example `script.1a2b3c4d.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.
+
+## 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
+standalone CLI jar shrinks from around 9 MB to a few hundred kB, and the library no longer references
+any logging API — problems are reported through [exceptions](timeouts-and-errors.html) only.
+
+## Removed types
+
+These types and members were public in 1.x but are **removed** in 2.0.0. Code that referenced them
+will not compile against 2.0.0 (all were CXF- or SMB-specific):
+
+* `KerberosCredentialsException` — was thrown only by CXF internals.
+* `SmbTempShare` and `WindowsRemoteProcessUtils.copyLocalFilesToShare(...)` — replaced by the
+ WinRM-channel file transfer. `WindowsTempShare` is unchanged.
+* The Apache CXF-based `WinRMService` and its `service.client` internals, along with the generated
+ WSDL/XSD resources.
+
+The documented entry points — `WinRMWqlExecutor`, `WinRMCommandExecutor`, `WinRMEndpoint`,
+`WindowsRemoteCommandResult`, the enums, and the exception types — are unchanged.
diff --git a/src/site/markdown/timeouts-and-errors.md b/src/site/markdown/timeouts-and-errors.md
new file mode 100644
index 0000000..3c8ac57
--- /dev/null
+++ b/src/site/markdown/timeouts-and-errors.md
@@ -0,0 +1,71 @@
+keywords: timeout, exception, error, winrmexception, wsmanfault, exit code
+description: Timeout semantics and the exception surface of the WinRM Java Client, plus the command-line exit codes.
+
+# Timeouts and Errors
+
+
+
+## Timeouts
+
+Both `executeWql(...)` and `WinRMCommandExecutor.execute(...)` take a `timeout` in
+**milliseconds**. The value must be **greater than zero** — passing `0` or a negative value throws
+an `IllegalArgumentException` immediately.
+
+The `timeout` applies to the remote operation and to the preparatory steps the client performs —
+opening the connection, detecting the remote code page, and (for commands) copying files. It is
+enforced **per step**, not as a single cumulative deadline: each major step is given up to `timeout`
+to complete, so a call that chains several slow steps can take longer than one `timeout` overall
+before a step finally exceeds its own limit and throws `java.util.concurrent.TimeoutException`. (When
+files are copied, the later stages are budgeted against the time already spent, so that path stays
+close to a single overall deadline.)
+
+```java
+try {
+ executeWql(HTTP, host, null, user, password, null, query, 30_000L, null, singletonList(NTLM));
+} catch (java.util.concurrent.TimeoutException e) {
+ // the operation did not finish within 30 seconds
+}
+```
+
+## The exception surface
+
+| Exception | Checked? | Meaning |
+| --- | --- | --- |
+| [`WindowsRemoteException`](apidocs/org/metricshub/winrm/exceptions/WindowsRemoteException.html) | yes | Base type for a problem on the remote host. |
+| [`WinRMException`](apidocs/org/metricshub/winrm/exceptions/WinRMException.html) | yes | A WinRM/WSMan failure — authentication rejection, WMI error, protocol fault, connection or TLS problem. Extends `WindowsRemoteException`. |
+| [`WqlQuerySyntaxException`](apidocs/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.html) | yes | The WQL query does not match the supported `SELECT` syntax. |
+| `java.util.concurrent.TimeoutException` | yes | The operation exceeded its `timeout`. |
+| `java.io.IOException` | yes | Declared by `WinRMCommandExecutor.execute(...)` for I/O problems (including copied-file errors). |
+| `IllegalArgumentException` | no | A mandatory argument is missing, or `timeout` is not greater than zero. |
+
+`executeWql(...)` declares `WinRMException`, `WqlQuerySyntaxException`, and `TimeoutException`.
+`WinRMCommandExecutor.execute(...)` declares `IOException`, `TimeoutException`, and
+`WindowsRemoteException`.
+
+### Fault detail
+
+When the remote host returns a WSMan fault, the exception message carries the detailed `WSManFault`
+text — including the provider-level detail such as WMI `WBEM_E_*` mnemonics — alongside the SOAP
+reason text, so the underlying cause is visible in the message.
+
+### Authentication failures
+
+A rejected credential surfaces as a `WinRMException` whose message is of the form
+`Authentication error on with user name ""`.
+
+## Command-line exit codes
+
+The standalone jar maps outcomes to stable process exit codes:
+
+| Exit code | Meaning |
+| ---: | --- |
+| `0` | Successful WQL query or remote command. |
+| `0`–`255` | Remote command exit code, when it fits in that range. |
+| `64` | Invalid CLI usage. |
+| `69` | Connection, DNS, socket, or TLS failure. |
+| `70` | WinRM protocol or other remote failure. |
+| `77` | Authentication failure. |
+| `124` | Operation timeout. |
+
+Diagnostics are written only to standard error, so a WQL query's JSON Lines output on standard
+output is never mixed with error messages.
diff --git a/src/site/markdown/tls.md b/src/site/markdown/tls.md
new file mode 100644
index 0000000..c79f841
--- /dev/null
+++ b/src/site/markdown/tls.md
@@ -0,0 +1,78 @@
+keywords: tls, https, certificate, trust store, hostname verification, insecure, self-signed
+description: How the client validates TLS certificates over HTTPS, how to trust a certificate, and the insecure test-only opt-out.
+
+# TLS / HTTPS
+
+
+
+Use HTTPS by passing `HTTPS` as the protocol. HTTPS uses port **5986** by default (HTTP uses
+**5985**); pass an explicit `port` to override either.
+
+```java
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
+
+executeWql(HTTPS, "server.example.com", null, /* ... */);
+```
+
+## Validation is on by default
+
+Since 2.0.0 the client uses the JDK's default, **validating** `SSLSocketFactory`: it checks the
+server certificate against the platform trust store and **verifies the server hostname** during the
+handshake.
+
+> [!WARNING]
+> This is a change from the 1.x CXF-based client, which silently trusted every certificate and
+> skipped hostname verification. Connections over HTTPS to hosts with **self-signed or otherwise
+> untrusted certificates now fail** during the TLS handshake unless you trust the certificate or
+> explicitly opt out (below). See [Migrating from 1.x](migrating-from-1x.html).
+
+## Trusting a certificate
+
+The recommended fix for a self-signed or private-CA host is to add the server certificate (or its
+issuing CA) to a Java trust store and point the JVM at it with the standard system properties:
+
+```bash
+java -Djavax.net.ssl.trustStore=/path/to/truststore.jks \
+ -Djavax.net.ssl.trustStorePassword=changeit \
+ -cp ... MyApp
+```
+
+Because the client uses the JDK default socket factory, any trust store configured this way (or the
+platform's default trust store) applies automatically.
+
+## Disabling validation (insecure — testing only)
+
+For a self-signed test host where installing a trust store is not practical, set the system property
+`org.metricshub.winrm.tls.insecure` to `true`. This trusts **all** certificates and skips hostname
+verification:
+
+```bash
+java -Dorg.metricshub.winrm.tls.insecure=true -cp ... MyApp
+```
+
+> [!WARNING]
+> This defeats the protection TLS provides against man-in-the-middle attacks. Use it only for
+> testing or for isolated hosts, never in production.
+
+## On the command line
+
+The standalone jar mirrors this behavior:
+
+| Option | Meaning |
+| --- | --- |
+| `--https` | Use HTTPS (port 5986 by default). |
+| `--https-permissive` | Trust any certificate and hostname. Intentionally insecure; testing only. Requires `--https`. |
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.example.com -u 'DOMAIN\user' -pf password.txt \
+ --https --https-permissive \
+ wql 'SELECT Name FROM Win32_ComputerSystem'
+```
+
+`--https-permissive` sets `org.metricshub.winrm.tls.insecure=true` for that invocation.
+
+## See also
+
+* [Authentication](authentication.html) — Kerberos requires HTTPS
+* [Timeouts and Errors](timeouts-and-errors.html) — a TLS failure surfaces as a connection error
diff --git a/src/site/markdown/wql.md b/src/site/markdown/wql.md
new file mode 100644
index 0000000..0f553ff
--- /dev/null
+++ b/src/site/markdown/wql.md
@@ -0,0 +1,124 @@
+keywords: wql, wmi, query, win32, namespace, root cimv2, cim
+description: Run WQL / WMI queries with WinRMWqlExecutor and read the result rows.
+
+# WQL Queries
+
+
+
+WQL (WMI Query Language) is the SQL-like language used to query the Windows Management
+Instrumentation (WMI) repository. The client runs a query on the remote host and returns the rows.
+
+## `WinRMWqlExecutor.executeWql(...)`
+
+A query is executed with the static method
+[`WinRMWqlExecutor.executeWql(...)`](apidocs/org/metricshub/winrm/wql/WinRMWqlExecutor.html). It
+opens a connection, runs the query, collects every row, closes the connection, and returns a
+[`WinRMWqlExecutor`](apidocs/org/metricshub/winrm/wql/WinRMWqlExecutor.html) holding the result.
+
+```java
+import static java.util.Collections.singletonList;
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTP;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+import static org.metricshub.winrm.wql.WinRMWqlExecutor.executeWql;
+
+import org.metricshub.winrm.wql.WinRMWqlExecutor;
+
+WinRMWqlExecutor result = executeWql(
+ HTTP, // protocol
+ "server.example.com", // hostname
+ null, // port (null → 5985 for HTTP, 5986 for HTTPS)
+ "DOMAIN\\Administrator", // username
+ "the-password".toCharArray(), // password
+ "ROOT\\CIMV2", // namespace (null → ROOT\CIMV2)
+ "SELECT Name, State FROM Win32_Service", // WQL query
+ 30_000L, // timeout in milliseconds
+ null, // Kerberos ticket cache (null for NTLM)
+ singletonList(NTLM) // authentication schemes
+);
+```
+
+### Parameters
+
+| Parameter | Type | Notes |
+| --- | --- | --- |
+| `protocol` | [`WinRMHttpProtocolEnum`](apidocs/org/metricshub/winrm/WinRMHttpProtocolEnum.html) | `HTTP` or `HTTPS`. `null` defaults to `HTTP`. |
+| `hostname` | `String` | Host name or IP address. **Mandatory.** |
+| `port` | `Integer` | `null` uses the protocol default (5985 for HTTP, 5986 for HTTPS). |
+| `username` | `String` | `DOMAIN\user` or `user`. **Mandatory.** See [Authentication](authentication.html). |
+| `password` | `char[]` | The password. |
+| `namespace` | `String` | WMI namespace. `null` or blank defaults to `ROOT\CIMV2`. Backslashes and forward slashes are both accepted. |
+| `wqlQuery` | `String` | The WQL query. **Mandatory.** |
+| `timeout` | `long` | Timeout in milliseconds. Must be **greater than zero** (an `IllegalArgumentException` is thrown otherwise). See [Timeouts and Errors](timeouts-and-errors.html). |
+| `ticketCache` | `java.nio.file.Path` | Kerberos ticket cache path. `null` for NTLM. See [Authentication](authentication.html). |
+| `authentications` | `List<`[`AuthenticationEnum`](apidocs/org/metricshub/winrm/service/client/auth/AuthenticationEnum.html)`>` | Requested schemes. `null` or empty means NTLM only. |
+
+## Reading the result
+
+The returned [`WinRMWqlExecutor`](apidocs/org/metricshub/winrm/wql/WinRMWqlExecutor.html) exposes:
+
+| Method | Returns | Description |
+| --- | --- | --- |
+| `getHeaders()` | `List` | The property (column) names. |
+| `getRows()` | `List>` | One `List` per row, with values in the same order as the headers. |
+| `getExecutionTime()` | `long` | Wall-clock time of the whole call, in milliseconds. |
+
+```java
+List headers = result.getHeaders(); // e.g. [Name, State]
+for (List row : result.getRows()) {
+ System.out.println(headers + " = " + row);
+}
+```
+
+### Property order and case
+
+* When you select explicit properties (`SELECT Name, State FROM ...`), the headers keep the **order
+ of the query** and the **exact case reported by WMI**.
+* With `SELECT * FROM ...`, the properties are returned in **alphabetical order** (case-insensitive).
+* If the query returns no rows, the headers fall back to the property names exactly as written in
+ the query (WMI's own casing cannot be recovered from an empty result set).
+
+## Supported WQL syntax
+
+The client validates that the query is a simple `SELECT`:
+
+```sql
+SELECT * FROM Win32_OperatingSystem
+SELECT Name, State, StartMode FROM Win32_Service
+SELECT Name FROM Win32_Process WHERE Name = 'explorer.exe'
+```
+
+The grammar is a single `SELECT` of either `*` or a comma-separated property list, a `FROM` clause,
+and an optional `WHERE` clause. Joins, sub-selects, and other advanced constructs are not part of
+the supported syntax. An invalid query raises a
+[`WqlQuerySyntaxException`](apidocs/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.html).
+
+## Choosing a namespace
+
+Most Windows classes live under the default `ROOT\CIMV2` namespace. To query a different one — for
+example `ROOT\Microsoft\SqlServer` or `ROOT\WMI` — pass it as the `namespace` argument. Both
+`ROOT\WMI` and `ROOT/WMI` are accepted.
+
+## Exceptions
+
+`executeWql(...)` declares three checked exceptions:
+
+| Exception | When |
+| --- | --- |
+| [`WqlQuerySyntaxException`](apidocs/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.html) | The query does not match the supported `SELECT` syntax. |
+| [`WinRMException`](apidocs/org/metricshub/winrm/exceptions/WinRMException.html) | Any WinRM/WSMan problem on the remote host (authentication, WMI error, protocol fault, ...). |
+| `java.util.concurrent.TimeoutException` | The operation did not complete within `timeout`. |
+
+See [Timeouts and Errors](timeouts-and-errors.html) for the full exception surface.
+
+## From the command line
+
+The standalone jar exposes the same capability through the `wql` subcommand, printing one compact
+UTF-8 JSON object per row ([JSON Lines](https://jsonlines.org/)):
+
+```bash
+java -jar ${project.artifactId}-${project.version}-standalone.jar \
+ -h server.example.com -u 'DOMAIN\user' -pf password.txt --ntlm \
+ wql 'SELECT Name, State FROM Win32_Service'
+```
+
+Property order follows the WinRM response; diagnostics go only to standard error.
diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css
index e85911b..24a024c 100644
--- a/src/site/resources/css/site.css
+++ b/src/site/resources/css/site.css
@@ -64,7 +64,7 @@
--heading-font: "Poppins", sans-serif;
--content-font: "Poppins", sans-serif;
- --content-font-size: medium;
+ --content-font-size: 15px;
--banner-font-size: 40px;
--banner-font-weight: 800;
diff --git a/src/site/site.xml b/src/site/site.xml
index d042bbf..c4a25f5 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -1,36 +1,71 @@
-
-
+
+org.sentrysoftware.mavensentry-maven-skin
- 6.4.01
+ 8.0.00true
- winrm
+ winrm, wql, wmi, windows, ntlm, kerberos, java, remote management
+
+
+ WinRM Java Client on GitHub
+ https://github.com/metricshub/winrm-java
+ fa-brands fa-github
+
+
+
+
+ Issue Tracker
+ https://github.com/metricshub/winrm-java/issues
+
+
+ Licenses
+ licenses.html
+
+
+ Releases
+ https://github.com/metricshub/winrm-java/releases
+
+
-
- images/metricshub-logo-only.png
- https://metricshub.org
+
+
-
+
+
+
-
-
\ No newline at end of file
+