From b773ae429113fb41a44219634838d208d094859b Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Mon, 16 Jan 2017 11:21:48 -0800 Subject: [PATCH] Preserve exit code in winrm exec (#20166) Raw winrm exec discards the exit code from external processes- this change preserves the exit code if present. --- lib/ansible/plugins/connection/winrm.py | 4 ++-- lib/ansible/plugins/shell/powershell.py | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/ansible/plugins/connection/winrm.py b/lib/ansible/plugins/connection/winrm.py index fbc31ae4ed..5116f41be0 100644 --- a/lib/ansible/plugins/connection/winrm.py +++ b/lib/ansible/plugins/connection/winrm.py @@ -352,7 +352,7 @@ class Connection(ConnectionBase): ''' script = script_template.format(self._shell._escape(out_path)) - cmd_parts = self._shell._encode_script(script, as_list=True, strict_mode=False) + cmd_parts = self._shell._encode_script(script, as_list=True, strict_mode=False, preserve_rc=False) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], stdin_iterator=self._put_file_stdin_iterator(in_path, out_path)) # TODO: improve error handling @@ -404,7 +404,7 @@ class Connection(ConnectionBase): } ''' % dict(buffer_size=buffer_size, path=self._shell._escape(in_path), offset=offset) display.vvvvv('WINRM FETCH "%s" to "%s" (offset=%d)' % (in_path, out_path, offset), host=self._winrm_host) - cmd_parts = self._shell._encode_script(script, as_list=True) + cmd_parts = self._shell._encode_script(script, as_list=True, preserve_rc=False) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:]) if result.status_code != 0: raise IOError(to_native(result.std_err)) diff --git a/lib/ansible/plugins/shell/powershell.py b/lib/ansible/plugins/shell/powershell.py index b883dead22..6440a86608 100644 --- a/lib/ansible/plugins/shell/powershell.py +++ b/lib/ansible/plugins/shell/powershell.py @@ -216,7 +216,7 @@ class ShellModule(object): rm_tmp = self._escape(self._unquote(rm_tmp)) rm_cmd = 'Remove-Item "%s" -Force -Recurse -ErrorAction SilentlyContinue' % rm_tmp script = '%s\nFinally { %s }' % (script, rm_cmd) - return self._encode_script(script) + return self._encode_script(script, preserve_rc=False) def _unquote(self, value): '''Remove any matching quotes that wrap the given value.''' @@ -243,11 +243,15 @@ class ShellModule(object): replace = lambda m: substs[m.lastindex - 1] return re.sub(pattern, replace, value) - def _encode_script(self, script, as_list=False, strict_mode=True): + def _encode_script(self, script, as_list=False, strict_mode=True, preserve_rc=True): '''Convert a PowerShell script to a single base64-encoded command.''' script = to_text(script) if strict_mode: script = u'Set-StrictMode -Version Latest\r\n%s' % script + # try to propagate exit code if present- won't work with begin/process/end-style scripts (ala put_file) + # NB: the exit code returned may be incorrect in the case of a successful command followed by an invalid command + if preserve_rc: + script = u'%s\r\nIf (-not $?) { If (Get-Variable LASTEXITCODE -ErrorAction SilentlyContinue) { exit $LASTEXITCODE } Else { exit 1 } }\r\n' % script script = '\n'.join([x.strip() for x in script.splitlines() if x.strip()]) encoded_script = base64.b64encode(script.encode('utf-16-le')) cmd_parts = _common_args + ['-EncodedCommand', encoded_script]