Beispiel #1
0
    def test_winrm_run_cmd_timeout(self, mock_get_command_output):
        mock_protocol = mock.MagicMock()
        mock_protocol.open_shell.return_value = 123
        mock_protocol.run_command.return_value = 456
        mock_session = mock.MagicMock(protocol=mock_protocol)
        mock_get_command_output.side_effect = WinRmRunnerTimoutError(
            Response(("", "", 5)))

        self._init_runner()
        result = self._runner._winrm_run_cmd(
            mock_session,
            "fake-command",
            args=["arg1", "arg2"],
            env={"PATH": "C:\\st2\\bin"},
            cwd="C:\\st2",
        )
        expected_response = Response(("", "", 5))
        expected_response.timeout = True

        self.assertEqual(result.__dict__, expected_response.__dict__)
        mock_protocol.open_shell.assert_called_with(
            env_vars={"PATH": "C:\\st2\\bin"}, working_directory="C:\\st2")
        mock_protocol.run_command.assert_called_with(123, "fake-command",
                                                     ["arg1", "arg2"])
        mock_protocol.cleanup_command.assert_called_with(123, 456)
        mock_protocol.close_shell.assert_called_with(123)
Beispiel #2
0
    def test_winrm_run_cmd(self):
        mock_protocol = mock.MagicMock()
        mock_protocol.open_shell.return_value = 123
        mock_protocol.run_command.return_value = 456
        mock_protocol._raw_get_command_output.return_value = (b'output',
                                                              b'error', 9,
                                                              True)
        mock_session = mock.MagicMock(protocol=mock_protocol)

        self._init_runner()
        result = self._runner._winrm_run_cmd(mock_session,
                                             "fake-command",
                                             args=['arg1', 'arg2'],
                                             env={'PATH': 'C:\\st2\\bin'},
                                             cwd='C:\\st2')
        expected_response = Response((b'output', b'error', 9))
        expected_response.timeout = False

        self.assertEquals(result.__dict__, expected_response.__dict__)
        mock_protocol.open_shell.assert_called_with(
            env_vars={'PATH': 'C:\\st2\\bin'}, working_directory='C:\\st2')
        mock_protocol.run_command.assert_called_with(123, 'fake-command',
                                                     ['arg1', 'arg2'])
        mock_protocol._raw_get_command_output.assert_called_with(123, 456)
        mock_protocol.cleanup_command.assert_called_with(123, 456)
        mock_protocol.close_shell.assert_called_with(123)
Beispiel #3
0
    def test_winrm_run_cmd(self):
        mock_protocol = mock.MagicMock()
        mock_protocol.open_shell.return_value = 123
        mock_protocol.run_command.return_value = 456
        mock_protocol._raw_get_command_output.return_value = (
            b"output",
            b"error",
            9,
            True,
        )
        mock_session = mock.MagicMock(protocol=mock_protocol)

        self._init_runner()
        result = self._runner._winrm_run_cmd(
            mock_session,
            "fake-command",
            args=["arg1", "arg2"],
            env={"PATH": "C:\\st2\\bin"},
            cwd="C:\\st2",
        )
        expected_response = Response((b"output", b"error", 9))
        expected_response.timeout = False

        self.assertEqual(result.__dict__, expected_response.__dict__)
        mock_protocol.open_shell.assert_called_with(
            env_vars={"PATH": "C:\\st2\\bin"}, working_directory="C:\\st2")
        mock_protocol.run_command.assert_called_with(123, "fake-command",
                                                     ["arg1", "arg2"])
        mock_protocol._raw_get_command_output.assert_called_with(123, 456)
        mock_protocol.cleanup_command.assert_called_with(123, 456)
        mock_protocol.close_shell.assert_called_with(123)
Beispiel #4
0
    def test_translate_response_timeout(self):
        response = Response(('output1', 'error1', 123))
        response.timeout = True

        result = self._runner._translate_response(response)
        self.assertEquals(result, ('timeout', {
            'failed': True,
            'succeeded': False,
            'return_code': -1,
            'stdout': 'output1',
            'stderr': 'error1'
        }, None))
Beispiel #5
0
    def test_translate_response_timeout(self):
        response = Response(('output1', 'error1', 123))
        response.timeout = True

        result = self._runner._translate_response(response)
        self.assertEquals(result, ('timeout',
                                   {'failed': True,
                                    'succeeded': False,
                                    'return_code': -1,
                                    'stdout': 'output1',
                                    'stderr': 'error1'},
                                   None))
Beispiel #6
0
 def _winrm_exec(self, command, args=(), from_exec=False):
     if from_exec:
         vvvv("WINRM EXEC %r %r" % (command, args), host=self.host)
     else:
         vvvvv("WINRM EXEC %r %r" % (command, args), host=self.host)
     if not self.protocol:
         self.protocol = self._winrm_connect()
     if not self.shell_id:
         self.shell_id = self.protocol.open_shell()
     command_id = None
     try:
         command_id = self.protocol.run_command(self.shell_id, command,
                                                args)
         response = Response(
             self.protocol.get_command_output(self.shell_id, command_id))
         if from_exec:
             vvvv('WINRM RESULT %r' % response, host=self.host)
         else:
             vvvvv('WINRM RESULT %r' % response, host=self.host)
         vvvvv('WINRM STDOUT %s' % response.std_out, host=self.host)
         vvvvv('WINRM STDERR %s' % response.std_err, host=self.host)
         return response
     finally:
         if command_id:
             self.protocol.cleanup_command(self.shell_id, command_id)
Beispiel #7
0
    def _winrm_get_command_output(self, protocol, shell_id, command_id):
        # NOTE: this is copied from pywinrm because it doesn't support
        # timeouts
        stdout_buffer, stderr_buffer = [], []
        return_code = 0
        command_done = False
        start_time = time.time()
        while not command_done:
            # check if we need to timeout (StackStorm custom)
            current_time = time.time()
            elapsed_time = current_time - start_time
            if self._timeout and (elapsed_time > self._timeout):
                raise WinRmRunnerTimoutError(
                    Response((
                        b"".join(stdout_buffer),
                        b"".join(stderr_buffer),
                        WINRM_TIMEOUT_EXIT_CODE,
                    )))
            # end stackstorm custom

            try:
                (
                    stdout,
                    stderr,
                    return_code,
                    command_done,
                ) = protocol._raw_get_command_output(shell_id, command_id)
                stdout_buffer.append(stdout)
                stderr_buffer.append(stderr)
            except WinRMOperationTimeoutError:
                # this is an expected error when waiting for a long-running process,
                # just silently retry
                pass
        return b"".join(stdout_buffer), b"".join(stderr_buffer), return_code
Beispiel #8
0
    def test_winrm_run_ps(self, mock_run_cmd):
        mock_run_cmd.return_value = Response(("output", "", 3))
        script = "Get-ADUser stanley"

        result = self._runner._winrm_run_ps("session",
                                            script,
                                            env={"PATH": "C:\\st2\\bin"},
                                            cwd="C:\\st2")

        self.assertEqual(result.__dict__, Response(("output", "", 3)).__dict__)
        expected_ps = "powershell -encodedcommand " + b64encode(
            "Get-ADUser stanley".encode("utf_16_le")).decode("ascii")
        mock_run_cmd.assert_called_with("session",
                                        expected_ps,
                                        env={"PATH": "C:\\st2\\bin"},
                                        cwd="C:\\st2")
Beispiel #9
0
    def test_winrm_run_ps(self, mock_run_cmd):
        mock_run_cmd.return_value = Response(('output', '', 3))
        script = "Get-ADUser stanley"

        result = self._runner._winrm_run_ps("session",
                                            script,
                                            env={'PATH': 'C:\\st2\\bin'},
                                            cwd='C:\\st2')

        self.assertEqual(result.__dict__, Response(('output', '', 3)).__dict__)
        expected_ps = ('powershell -encodedcommand ' + b64encode(
            "Get-ADUser stanley".encode('utf_16_le')).decode('ascii'))
        mock_run_cmd.assert_called_with("session",
                                        expected_ps,
                                        env={'PATH': 'C:\\st2\\bin'},
                                        cwd='C:\\st2')
Beispiel #10
0
 def _winrm_exec(self, command, args=(), from_exec=False):
     if from_exec:
         self._display.vvvvv("WINRM EXEC %r %r" % (command, args),
                             host=self._play_context.remote_addr)
     else:
         self._display.vvvvvv("WINRM EXEC %r %r" % (command, args),
                              host=self._play_context.remote_addr)
     if not self.protocol:
         self.protocol = self._winrm_connect()
     if not self.shell_id:
         self.shell_id = self.protocol.open_shell(codepage=65001)  # UTF-8
     command_id = None
     try:
         command_id = self.protocol.run_command(self.shell_id,
                                                to_bytes(command),
                                                map(to_bytes, args))
         response = Response(
             self.protocol.get_command_output(self.shell_id, command_id))
         if from_exec:
             self._display.vvvvv('WINRM RESULT %r' % to_unicode(response),
                                 host=self._play_context.remote_addr)
         else:
             self._display.vvvvv('WINRM RESULT %r' % to_unicode(response),
                                 host=self._play_context.remote_addr)
         self._display.vvvvvv('WINRM STDOUT %s' %
                              to_unicode(response.std_out),
                              host=self._play_context.remote_addr)
         self._display.vvvvvv('WINRM STDERR %s' %
                              to_unicode(response.std_err),
                              host=self._play_context.remote_addr)
         return response
     finally:
         if command_id:
             self.protocol.cleanup_command(self.shell_id, command_id)
Beispiel #11
0
 def run_cmd(self, command, args=()):
     # TODO optimize perf. Do not call open/close shell every time
     shell_id = self.protocol.open_shell(codepage=65001)
     command_id = self.protocol.run_command(shell_id, command, args)
     rs = Response(self.protocol.get_command_output(shell_id, command_id))
     self.protocol.cleanup_command(shell_id, command_id)
     self.protocol.close_shell(shell_id)
     return rs
Beispiel #12
0
 def run_cmd(self, command, args=()):
     self.protocol.DEFAULT_READ_TIMEOUT_SEC = 300
     self.protocol.DEFAULT_OPERATION_TIMEOUT_SEC = 200
     shell_id = self.protocol.open_shell(codepage=65001)
     command_id = self.protocol.run_command(shell_id, command, args)
     rs = Response(self.protocol.get_command_output(shell_id, command_id))
     self.protocol.cleanup_command(shell_id, command_id)
     self.protocol.close_shell(shell_id)
     return rs
Beispiel #13
0
    def test_winrm_run_ps_clean_stderr(self, mock_run_cmd):
        mock_run_cmd.return_value = Response(('output', 'error', 3))
        mock_session = mock.MagicMock()
        mock_session._clean_error_msg.return_value = 'e'
        script = "Get-ADUser stanley"

        result = self._runner._winrm_run_ps(mock_session, script,
                                            env={'PATH': 'C:\\st2\\bin'},
                                            cwd='C:\\st2')

        self.assertEqual(result.__dict__,
                         Response(('output', 'e', 3)).__dict__)
        expected_ps = ('powershell -encodedcommand ' +
                       b64encode("Get-ADUser stanley".encode('utf_16_le')).decode('ascii'))
        mock_run_cmd.assert_called_with(mock_session,
                                        expected_ps,
                                        env={'PATH': 'C:\\st2\\bin'},
                                        cwd='C:\\st2')
        mock_session._clean_error_msg.assert_called_with('error')
Beispiel #14
0
    def test_translate_response_timeout(self):
        response = Response(("output1", "error1", 123))
        response.timeout = True

        result = self._runner._translate_response(response)
        self.assertEqual(
            result,
            (
                "timeout",
                {
                    "failed": True,
                    "succeeded": False,
                    "return_code": -1,
                    "stdout": "output1",
                    "stderr": "error1",
                },
                None,
            ),
        )
Beispiel #15
0
    def test_winrm_run_ps_clean_stderr(self, mock_run_cmd):
        mock_run_cmd.return_value = Response(("output", "error", 3))
        mock_session = mock.MagicMock()
        mock_session._clean_error_msg.return_value = "e"
        script = "Get-ADUser stanley"

        result = self._runner._winrm_run_ps(mock_session,
                                            script,
                                            env={"PATH": "C:\\st2\\bin"},
                                            cwd="C:\\st2")

        self.assertEqual(result.__dict__,
                         Response(("output", "e", 3)).__dict__)
        expected_ps = "powershell -encodedcommand " + b64encode(
            "Get-ADUser stanley".encode("utf_16_le")).decode("ascii")
        mock_run_cmd.assert_called_with(mock_session,
                                        expected_ps,
                                        env={"PATH": "C:\\st2\\bin"},
                                        cwd="C:\\st2")
        mock_session._clean_error_msg.assert_called_with("error")
Beispiel #16
0
 def _winrm_run_cmd(self, session, command, args=(), env=None, cwd=None):
     # NOTE: this is copied from pywinrm because it doesn't support
     # passing env and working_directory from the Session.run_cmd.
     # It also doesn't support timeouts. All of these things have been
     # added
     shell_id = session.protocol.open_shell(env_vars=env,
                                            working_directory=cwd)
     command_id = session.protocol.run_command(shell_id, command, args)
     # try/catch is for custom timeout handing (StackStorm custom)
     try:
         rs = Response(
             self._winrm_get_command_output(session.protocol, shell_id,
                                            command_id))
         rs.timeout = False
     except WinRmRunnerTimoutError as e:
         rs = e.response
         rs.timeout = True
     # end stackstorm custom
     session.protocol.cleanup_command(shell_id, command_id)
     session.protocol.close_shell(shell_id)
     return rs
Beispiel #17
0
 def _winrm_run_cmd(self, session, command, args=(), env=None, cwd=None):
     # NOTE: this is copied from pywinrm because it doesn't support
     # passing env and working_directory from the Session.run_cmd.
     # It also doesn't support timeouts. All of these things have been
     # added
     shell_id = session.protocol.open_shell(env_vars=env,
                                            working_directory=cwd)
     command_id = session.protocol.run_command(shell_id, command, args)
     # try/catch is for custom timeout handing (StackStorm custom)
     try:
         rs = Response(self._winrm_get_command_output(session.protocol,
                                                      shell_id,
                                                      command_id))
         rs.timeout = False
     except WinRmRunnerTimoutError as e:
         rs = e.response
         rs.timeout = True
     # end stackstorm custom
     session.protocol.cleanup_command(shell_id, command_id)
     session.protocol.close_shell(shell_id)
     return rs
Beispiel #18
0
    def test_winrm_run_cmd_timeout(self, mock_get_command_output):
        mock_protocol = mock.MagicMock()
        mock_protocol.open_shell.return_value = 123
        mock_protocol.run_command.return_value = 456
        mock_session = mock.MagicMock(protocol=mock_protocol)
        mock_get_command_output.side_effect = WinRmRunnerTimoutError(Response(('', '', 5)))

        self._init_runner()
        result = self._runner._winrm_run_cmd(mock_session, "fake-command",
                                             args=['arg1', 'arg2'],
                                             env={'PATH': 'C:\\st2\\bin'},
                                             cwd='C:\\st2')
        expected_response = Response(('', '', 5))
        expected_response.timeout = True

        self.assertEquals(result.__dict__, expected_response.__dict__)
        mock_protocol.open_shell.assert_called_with(env_vars={'PATH': 'C:\\st2\\bin'},
                                                    working_directory='C:\\st2')
        mock_protocol.run_command.assert_called_with(123, 'fake-command', ['arg1', 'arg2'])
        mock_protocol.cleanup_command.assert_called_with(123, 456)
        mock_protocol.close_shell.assert_called_with(123)
Beispiel #19
0
    def test_winrm_run_cmd(self):
        mock_protocol = mock.MagicMock()
        mock_protocol.open_shell.return_value = 123
        mock_protocol.run_command.return_value = 456
        mock_protocol._raw_get_command_output.return_value = (b'output', b'error', 9, True)
        mock_session = mock.MagicMock(protocol=mock_protocol)

        self._init_runner()
        result = self._runner._winrm_run_cmd(mock_session, "fake-command",
                                             args=['arg1', 'arg2'],
                                             env={'PATH': 'C:\\st2\\bin'},
                                             cwd='C:\\st2')
        expected_response = Response((b'output', b'error', 9))
        expected_response.timeout = False

        self.assertEquals(result.__dict__, expected_response.__dict__)
        mock_protocol.open_shell.assert_called_with(env_vars={'PATH': 'C:\\st2\\bin'},
                                                    working_directory='C:\\st2')
        mock_protocol.run_command.assert_called_with(123, 'fake-command', ['arg1', 'arg2'])
        mock_protocol._raw_get_command_output.assert_called_with(123, 456)
        mock_protocol.cleanup_command.assert_called_with(123, 456)
        mock_protocol.close_shell.assert_called_with(123)
    def _winrm_exec(self, command, args=(), from_exec=False, stdin_iterator=None):
        if not self.protocol:
            self.protocol = self._winrm_connect()
            self._connected = True
        if from_exec:
            display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        else:
            display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        command_id = None
        try:
            stdin_push_failed = False
            command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator is None))

            # TODO: try/except around this, so we can get/return the command result on a broken pipe or other failure (probably more useful than the 500 that
            # comes from this)
            try:
                if stdin_iterator:
                    for (data, is_last) in stdin_iterator:
                        self._winrm_send_input(self.protocol, self.shell_id, command_id, data, eof=is_last)

            except Exception as ex:
                from traceback import format_exc
                display.warning("FATAL ERROR DURING FILE TRANSFER: %s" % format_exc(ex))
                stdin_push_failed = True

            if stdin_push_failed:
                raise AnsibleError('winrm send_input failed')

            # NB: this can hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
            # FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
            resptuple = self.protocol.get_command_output(self.shell_id, command_id)
            # ensure stdout/stderr are text for py3
            # FUTURE: this should probably be done internally by pywinrm
            response = Response(tuple(to_text(v) if isinstance(v, binary_type) else v for v in resptuple))

            # TODO: check result from response and set stdin_push_failed if we have nonzero
            if from_exec:
                display.vvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)
            else:
                display.vvvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)

            display.vvvvvv('WINRM STDOUT %s' % to_text(response.std_out), host=self._winrm_host)
            display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)

            if stdin_push_failed:
                raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, response.std_err))

            return response
        finally:
            if command_id:
                self.protocol.cleanup_command(self.shell_id, command_id)
Beispiel #21
0
    def _winrm_exec(self, command, args=(), from_exec=False, stdin_iterator=None):
        if not self.protocol:
            self.protocol = self._winrm_connect()
            self._connected = True
        if from_exec:
            display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        else:
            display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        command_id = None
        try:
            stdin_push_failed = False
            command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator is None))

            try:
                if stdin_iterator:
                    for (data, is_last) in stdin_iterator:
                        self._winrm_send_input(self.protocol, self.shell_id, command_id, data, eof=is_last)

            except Exception as ex:
                display.warning("FATAL ERROR DURING FILE TRANSFER: %s" % to_text(ex))
                stdin_push_failed = True

            # NB: this can hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
            # FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
            resptuple = self.protocol.get_command_output(self.shell_id, command_id)
            # ensure stdout/stderr are text for py3
            # FUTURE: this should probably be done internally by pywinrm
            response = Response(tuple(to_text(v) if isinstance(v, binary_type) else v for v in resptuple))

            # TODO: check result from response and set stdin_push_failed if we have nonzero
            if from_exec:
                display.vvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)
            else:
                display.vvvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)

            display.vvvvvv('WINRM STDOUT %s' % to_text(response.std_out), host=self._winrm_host)
            display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)

            if stdin_push_failed:
                stderr = to_bytes(response.std_err, encoding='utf-8')
                if self.is_clixml(stderr):
                    stderr = self.parse_clixml_stream(stderr)

                raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (to_native(response.std_out), to_native(stderr)))

            return response
        except requests.exceptions.ConnectionError as exc:
            raise AnsibleConnectionFailure('winrm connection error: %s' % to_native(exc))
        finally:
            if command_id:
                self.protocol.cleanup_command(self.shell_id, command_id)
Beispiel #22
0
def run_cmd(cmd, proto):
    """
    Run batch script on target machine

    Args:
        cmd (str): batch script to run
        proto (Protocol): Protocol containing target machine

    Returns:
        Response: Object containing stderr, stdout and exit_status
    """
    shell_id = proto.open_shell()
    command_id = proto.run_command(shell_id, cmd)
    rs = Response(proto.get_command_output(shell_id, command_id))
    proto.cleanup_command(shell_id, command_id)
    proto.close_shell(shell_id)
    return rs
Beispiel #23
0
    def _winrm_exec(self, command, args=(), from_exec=False, stdin_iterator=None):
        if not self.protocol:
            self.protocol = self._winrm_connect()
            self._connected = True
        if not self.shell_id:
            self.shell_id = self.protocol.open_shell(codepage=65001) # UTF-8
            display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host)
        if from_exec:
            display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        else:
            display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        command_id = None
        try:
            stdin_push_failed = False
            command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator == None))

            # TODO: try/except around this, so we can get/return the command result on a broken pipe or other failure (probably more useful than the 500 that comes from this)
            try:
                if stdin_iterator:
                    for (data, is_last) in stdin_iterator:
                        self._winrm_send_input(self.protocol, self.shell_id, command_id, data, eof=is_last)
            except:
                stdin_push_failed = True

            # NB: this could hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
            # FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
            response = Response(self.protocol.get_command_output(self.shell_id, command_id))
            if from_exec:
                display.vvvvv('WINRM RESULT %r' % to_unicode(response), host=self._winrm_host)
            else:
                display.vvvvvv('WINRM RESULT %r' % to_unicode(response), host=self._winrm_host)
            display.vvvvvv('WINRM STDOUT %s' % to_unicode(response.std_out), host=self._winrm_host)
            display.vvvvvv('WINRM STDERR %s' % to_unicode(response.std_err), host=self._winrm_host)

            if stdin_push_failed:
                raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, response.std_err))

            return response
        finally:
            if command_id:
                self.protocol.cleanup_command(self.shell_id, command_id)
Beispiel #24
0
def run_cmd_winrm(cmd: str) -> Response:
    """
    Run batch script using winrm client.

    Args:
        cmd: batch script to run.
    Returns:
        Response object containing stderr, stdout and exit_status.
    """
    client = Protocol(endpoint='http://{}:5985/wsman'.format(config['host']),
                      transport='ntlm',
                      username='******'.format(config['domain'],
                                              config['user']),
                      password=config['pass'],
                      server_cert_validation='ignore')

    shell_id = client.open_shell()
    command_id = client.run_command(shell_id, cmd)
    rs = Response(client.get_command_output(shell_id, command_id))
    client.cleanup_command(shell_id, command_id)
    client.close_shell(shell_id)

    return rs
Beispiel #25
0
    def _winrm_exec(self, command, args=(), from_exec=False, stdin_iterator=None):
        if not self.protocol:
            self.protocol = self._winrm_connect()
            self._connected = True
        if from_exec:
            display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        else:
            display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._winrm_host)
        command_id = None
        try:
            stdin_push_failed = False
            command_id = self.protocol.run_command(self.shell_id, to_bytes(command), map(to_bytes, args), console_mode_stdin=(stdin_iterator is None))

            try:
                if stdin_iterator:
                    for (data, is_last) in stdin_iterator:
                        self._winrm_send_input(self.protocol, self.shell_id, command_id, data, eof=is_last)

            except Exception as ex:
                display.warning("ERROR DURING WINRM SEND INPUT - attempting to recover: %s %s"
                                % (type(ex).__name__, to_text(ex)))
                display.debug(traceback.format_exc())
                stdin_push_failed = True

            # NB: this can hang if the receiver is still running (eg, network failed a Send request but the server's still happy).
            # FUTURE: Consider adding pywinrm status check/abort operations to see if the target is still running after a failure.
            resptuple = self.protocol.get_command_output(self.shell_id, command_id)
            # ensure stdout/stderr are text for py3
            # FUTURE: this should probably be done internally by pywinrm
            response = Response(tuple(to_text(v) if isinstance(v, binary_type) else v for v in resptuple))

            # TODO: check result from response and set stdin_push_failed if we have nonzero
            if from_exec:
                display.vvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)
            else:
                display.vvvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)

            display.vvvvvv('WINRM STDOUT %s' % to_text(response.std_out), host=self._winrm_host)
            display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)

            if stdin_push_failed:
                # There are cases where the stdin input failed but the WinRM service still processed it. We attempt to
                # see if stdout contains a valid json return value so we can ignore this error
                try:
                    filtered_output, dummy = _filter_non_json_lines(response.std_out)
                    json.loads(filtered_output)
                except ValueError:
                    # stdout does not contain a return response, stdin input was a fatal error
                    stderr = to_bytes(response.std_err, encoding='utf-8')
                    if stderr.startswith(b"#< CLIXML"):
                        stderr = _parse_clixml(stderr)

                    raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s'
                                       % (to_native(response.std_out), to_native(stderr)))

            return response
        except requests.exceptions.Timeout as exc:
            raise AnsibleConnectionFailure('winrm connection error: %s' % to_native(exc))
        finally:
            if command_id:
                self.protocol.cleanup_command(self.shell_id, command_id)