diff --git a/lib/winrm-elevated/scripts/elevated_shell.ps1 b/lib/winrm-elevated/scripts/elevated_shell.ps1 index cd95618..d297879 100644 --- a/lib/winrm-elevated/scripts/elevated_shell.ps1 +++ b/lib/winrm-elevated/scripts/elevated_shell.ps1 @@ -88,14 +88,28 @@ try { function SlurpOutput($file, $cur_line, $out_type) { if (Test-Path $file) { - get-content $file | Select-Object -skip $cur_line | ForEach-Object { - $cur_line += 1 - if ($out_type -eq 'err') { - $host.ui.WriteErrorLine("$_") - } else { - $host.ui.WriteLine("$_") + $fs = New-Object -TypeName System.IO.FileStream -ArgumentList @( + $file, + [system.io.filemode]::Open, + [System.io.FileAccess]::Read, + [System.IO.FileShare]::ReadWrite + ) + try { + $enc = [System.Text.Encoding]::GetEncoding($Host.CurrentCulture.TextInfo.OEMCodePage) + $bytes = [System.Byte[]]::CreateInstance([System.Byte], $fs.Length) + if ($fs.Read($bytes, 0, $fs.Length) -gt 0) { + $text = $enc.GetString($bytes) + $text.TrimEnd("`n").TrimEnd("`r").Split(@("`r`n", "`n"), [StringSplitOptions]::None) | Select-Object -skip $cur_line | ForEach-Object { + $cur_line += 1 + if ($out_type -eq 'err') { + $host.ui.WriteErrorLine("$_") + } else { + $host.ui.WriteLine("$_") + } + } } } + finally { $fs.Close() } } return $cur_line } diff --git a/lib/winrm/shells/elevated.rb b/lib/winrm/shells/elevated.rb index 29aa780..bac7537 100644 --- a/lib/winrm/shells/elevated.rb +++ b/lib/winrm/shells/elevated.rb @@ -73,7 +73,9 @@ def close def upload_elevated_shell_script(script_text) elevated_shell_path = 'c:/windows/temp/winrm-elevated-shell-' + SecureRandom.uuid + '.ps1' - script_text_with_exit = "#{script_text}\r\n$Host.SetShouldExit($LASTEXITCODE)" + # Prepend the content of the file with an UTF-8 BOM for Windows to read it as such instead of the default + # Windows-XXXX encoding, and convert script_text accordingly if needed. + script_text_with_exit = "\uFEFF#{script_text.encode(Encoding::UTF_8)}\r\n$Host.SetShouldExit($LASTEXITCODE)" @winrm_file_transporter.upload(StringIO.new(script_text_with_exit), elevated_shell_path) elevated_shell_path end diff --git a/spec/powershell_elevated_spec.rb b/spec/powershell_elevated_spec.rb index 85094fd..b613a2b 100644 --- a/spec/powershell_elevated_spec.rb +++ b/spec/powershell_elevated_spec.rb @@ -54,6 +54,22 @@ it { should match(/Windows IP Configuration/) } end + describe 'special characters' do + subject(:output) { elevated_shell.run("echo \"#{text}\"") } + # Sample text using more than ASCII, but still compatible with occidental OEM encodings. + let(:text) do + 'Dès Noël, où un zéphyr haï me vêt de glaçons würmiens, je dîne d’exquis rôtis de bœuf au kir, ' \ + 'à l’aÿ d’âge mûr, &cætera.' + end + + it { should have_exit_code 0 } + it 'outputs a transliterated version of the original string' do + expect(output.stdout).to eq "Dès Noël, où un zéphyr haï me vêt de glaçons würmiens, je dîne d'exquis " \ + "rôtis de bouf au kir, à l'aÿ d'âge mûr, &cætera.\r\n" + end + it { should have_no_stderr } + end + describe 'capturing output from Write-Host and Write-Error' do subject(:output) do script = <<-COMMAND