Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WinRM/PSRP: Ensure shell returns UTF-8 output #47404

Merged
merged 4 commits into from
Oct 24, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/psrp-utf8-stdio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- psrp - Fix UTF-8 output - https://github.com/ansible/ansible/pull/46998
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,23 @@ namespace Ansible
StringBuilder lpBuffer,
out IntPtr lpFilePart);

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetConsoleWindow();

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleCP(
UInt32 wCodePageID);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleOutputCP(
UInt32 wCodePageID);

[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)]
Expand Down Expand Up @@ -252,6 +269,16 @@ namespace Ansible
if (environmentString != null)
lpEnvironment = Marshal.StringToHGlobalUni(environmentString.ToString());

// Create console if needed to be inherited by child process
bool isConsole = false;
if (GetConsoleWindow() == IntPtr.Zero) {
isConsole = AllocConsole();

// Set console input/output codepage to UTF-8
SetConsoleCP(65001);
SetConsoleOutputCP(65001);
}

// Create new process and run
StringBuilder argument_string = new StringBuilder(lpCommandLine);
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
Expand All @@ -270,6 +297,11 @@ namespace Ansible
throw new Win32Exception("Failed to create new process");
}

// Destroy console if we created it
if (isConsole) {
FreeConsole();
}

// Setup the output buffers and get stdout/stderr
FileStream stdout_fs = new FileStream(stdout_read, FileAccess.Read, 4096);
StreamReader stdout = new StreamReader(stdout_fs, utf8_encoding, true, 4096);
Expand Down
24 changes: 24 additions & 0 deletions test/integration/targets/connection_psrp/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,27 @@
assert:
that:
- async_out.stdout_lines == ["abc"]

- name: Output unicode characters from Powershell using PSRP
win_command: "powershell.exe -ExecutionPolicy ByPass -Command \"Write-Host '\U0001F4A9'\""
register: command_unicode_output

- name: Assert unicode output
assert:
that:
- command_unicode_output is changed
- command_unicode_output.rc == 0
- "command_unicode_output.stdout == '\U0001F4A9\n'"
- command_unicode_output.stderr == ''

- name: Output unicode characters from Powershell using PSRP
win_shell: "Write-Host '\U0001F4A9'"
register: shell_unicode_output

- name: Assert unicode output
assert:
that:
- shell_unicode_output is changed
- shell_unicode_output.rc == 0
- "shell_unicode_output.stdout == '\U0001F4A9\n'"
- shell_unicode_output.stderr == ''
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Assert-Equals -actual $actual.rc -expected 0
Assert-Equals -actual $actual.stdout -expected "stdout `r`n"
Assert-Equals -actual $actual.stderr -expected "stderr `r`n"

$test_name = "Test UTF8 output from stdout stream"
$actual = Run-Command -command "powershell.exe -ExecutionPolicy ByPass -Command `"Write-Host '💩'`""
Assert-Equals -actual $actual.rc -expected 0
Assert-Equals -actual $actual.stdout -expected "💩`n"
Assert-Equals -actual $actual.stderr -expected ""

$test_name = "test default environment variable"
Set-Item -Path env:TESTENV -Value "test"
$actual = Run-Command -command "cmd.exe /c set"
Expand Down