Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public class WinRmClient implements AutoCloseable {
private final Locale locale;
private final Map<String, String> environment;
private final PayloadEncryptionMode payloadEncryptionMode;
private final int codePage;
private final WinRm service;
private AsyncHttpEncryptionAwareConduitFactory factoryToCleanup;

Expand Down Expand Up @@ -205,6 +206,7 @@ public Builder(String endpoint, String authenticationScheme) {

this.workingDirectory = builder.workingDirectory;
this.locale = builder.locale;
this.codePage = builder.codePage;
this.operationTimeout = toDuration(builder.operationTimeout);
this.retryReceiveAfterOperationTimeout = builder.retryReceiveAfterOperationTimeout;
this.environment = builder.environment;
Expand Down Expand Up @@ -534,7 +536,7 @@ public ShellCommand createShell() {
optSetCreate.getOption().add(optNoProfile);
OptionType optCodepage = new OptionType();
optCodepage.setName("WINRS_CODEPAGE");
optCodepage.setValue("437");
optCodepage.setValue(Integer.toString(codePage));
optSetCreate.getOption().add(optCodepage);

ResourceCreated resourceCreated = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@

public class WinRmClientBuilder {
private static final java.util.Locale DEFAULT_LOCALE = java.util.Locale.US;

/**
* Older Windows systems may have issues with a modern UTF-8, so the default sticks with
* the legacy codepage 437 which is referred by en-us. However, for modern systems,
* the UTF-8 variant 65001 may be more suitable.
*/
public static final int DEFAULT_CODEPAGE = 437;

/**
* Means using a UTF-8 codepage. If the remote system is older, this may have issues.
*/
public static final int UTF8_CODEPAGE = 65001;

/**
* Timeout applied by default on client side for the opening of the socket (0 meaning infinite waiting).
*/
Expand Down Expand Up @@ -52,6 +65,7 @@ public class WinRmClientBuilder {
protected String password;
protected String workingDirectory;
protected Locale locale;
protected int codePage;
protected long operationTimeout;
protected Predicate<String> retryReceiveAfterOperationTimeout;
protected long connectionTimeout;
Expand Down Expand Up @@ -79,6 +93,7 @@ public class WinRmClientBuilder {
this.endpoint = WinRmClient.checkNotNull(endpoint, "endpoint");
authenticationScheme(AuthSchemes.NTLM);
locale(DEFAULT_LOCALE);
codePage(DEFAULT_CODEPAGE);
operationTimeout(DEFAULT_OPERATION_TIMEOUT);
retryReceiveAfterOperationTimeout(alwaysRetryReceiveAfterOperationTimeout());
connectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
Expand Down Expand Up @@ -116,6 +131,14 @@ public WinRmClientBuilder locale(java.util.Locale locale) {
return this;
}

/**
* @param codePage The shell's codePage
*/
public WinRmClientBuilder codePage(int codePage) {
this.codePage = codePage;
return this;
}

/**
* If operations cannot be completed in a specified time,
* the service returns a fault so that a client can comply with its obligations.
Expand Down
49 changes: 46 additions & 3 deletions winrm4j/src/main/java/io/cloudsoft/winrm4j/winrm/WinRmTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ public class WinRmTool {
public static final int DEFAULT_WINRM_HTTPS_PORT = 5986;
public static final Boolean DEFAULT_SKIP_COMMAND_SHELL = Boolean.FALSE;

/**
* @see WinRmClientBuilder#DEFAULT_CODEPAGE
*/
public static final int DEFAULT_CODEPAGE = WinRmClientBuilder.DEFAULT_CODEPAGE;

/**
* @see WinRmClientBuilder#UTF8_CODEPAGE
*/
public static final int UTF8_CODEPAGE = WinRmClientBuilder.UTF8_CODEPAGE;

// TODO consider make them non-final and accessing the properties directly from builder.
// This impose moving getEndpointUrl() to the WinRmTool.
private final String address;
Expand All @@ -64,6 +74,7 @@ public class WinRmTool {
private final WinRmClientContext context;
private final boolean requestNewKerberosTicket;
private PayloadEncryptionMode payloadEncryptionMode;
private int codePage = DEFAULT_CODEPAGE;

public static class Builder {
private String authenticationScheme = AuthSchemes.NTLM;
Expand All @@ -83,6 +94,7 @@ public static class Builder {
private WinRmClientContext context;
private boolean requestNewKerberosTicket;
private PayloadEncryptionMode payloadEncryptionMode;
private int codePage = DEFAULT_CODEPAGE;

private static final Pattern matchPort = Pattern.compile(".*:(\\d+)$");

Expand Down Expand Up @@ -173,12 +185,17 @@ public Builder payloadEncryptionMode(PayloadEncryptionMode x) {
return this;
}

public Builder codePage(int codePage) {
this.codePage = codePage;
return this;
}

public WinRmTool build() {
return new WinRmTool(getEndpointUrl(address, useHttps, port),
domain, username, password, authenticationScheme,
allowChunking, disableCertificateChecks, workingDirectory,
environment, hostnameVerifier, sslSocketFactory, sslContext,
context, requestNewKerberosTicket, payloadEncryptionMode);
context, requestNewKerberosTicket, payloadEncryptionMode, codePage);
}

// TODO remove arguments when method WinRmTool.connect() is removed
Expand Down Expand Up @@ -219,12 +236,36 @@ private static String getEndpointUrl(String address, Boolean useHttps, Integer p
}
}

@Deprecated /** @deprecated use bigger constructor */
private WinRmTool(String address, String domain, String username,
String password, String authenticationScheme,
boolean allowChunking, boolean disableCertificateChecks, String workingDirectory,
Map<String, String> environment, HostnameVerifier hostnameVerifier,
SSLSocketFactory sslSocketFactory, SSLContext sslContext, WinRmClientContext context,
boolean requestNewKerberosTicket) {
this.allowChunking = allowChunking;
this.disableCertificateChecks = disableCertificateChecks;
this.address = address;
this.domain = domain;
this.username = username;
this.password = password;
this.authenticationScheme = authenticationScheme;
this.workingDirectory = workingDirectory;
this.environment = environment;
this.hostnameVerifier = hostnameVerifier;
this.sslSocketFactory = sslSocketFactory;
this.sslContext = sslContext;
this.context = context;
this.requestNewKerberosTicket = requestNewKerberosTicket;
}

private WinRmTool(String address, String domain, String username,
String password, String authenticationScheme,
boolean allowChunking, boolean disableCertificateChecks, String workingDirectory,
Map<String, String> environment, HostnameVerifier hostnameVerifier,
SSLSocketFactory sslSocketFactory, SSLContext sslContext, WinRmClientContext context,
boolean requestNewKerberosTicket, PayloadEncryptionMode payloadEncryptionMode) {
boolean requestNewKerberosTicket, PayloadEncryptionMode payloadEncryptionMode,
int codePage) {
this.allowChunking = allowChunking;
this.disableCertificateChecks = disableCertificateChecks;
this.address = address;
Expand All @@ -240,6 +281,7 @@ private WinRmTool(String address, String domain, String username,
this.context = context;
this.requestNewKerberosTicket = requestNewKerberosTicket;
this.payloadEncryptionMode = payloadEncryptionMode;
this.codePage = codePage;
}

/**
Expand Down Expand Up @@ -388,6 +430,7 @@ public WinRmToolResponse executeCommand(String command, List<String> args, Boole
builder.requestNewKerberosTicket(requestNewKerberosTicket);
}
builder.payloadEncryptionMode(payloadEncryptionMode);
builder.codePage(codePage);

WinRmToolResponse winRmToolResponse;

Expand Down Expand Up @@ -421,7 +464,7 @@ public WinRmToolResponse executePs(String psCommand, Writer out, Writer err) {
}

public WinRmToolResponse executePs(String psCommand, Boolean skipCommandShell, Writer out, Writer err) {
return executeCommand("powershell", Arrays.asList("-encodedcommand", compileBase64(psCommand)), skipCommandShell, out, err);
return executeCommand("chcp " + codePage + " > NUL & powershell", Arrays.asList("-encodedcommand", compileBase64(psCommand)), skipCommandShell, out, err);
}

/**
Expand Down