diff --git a/winrm/protocol.py b/winrm/protocol.py
index 3ec634a1..e3699887 100644
--- a/winrm/protocol.py
+++ b/winrm/protocol.py
@@ -395,6 +395,39 @@ def cleanup_command(self, shell_id, command_id):
# TODO change assert into user-friendly exception
assert uuid.UUID(relates_to.replace('uuid:', '')) == message_id
+ def send_command_input(self, shell_id, command_id, stdin_input, end=False):
+ """
+ Send input to the given shell and command.
+ @param string shell_id: The shell id on the remote machine.
+ See #open_shell
+ @param string command_id: The command id on the remote machine.
+ See #run_command
+ @param string stdin_input: The input unicode string or byte string to be sent.
+ @param bool end: Boolean value which will close the stdin stream. If end=True then the stdin pipe to the
+ remotely running process will be closed causing the next read by the remote process to stdin to return a
+ EndOfFile error; the behavior of each process when this error is encountered is defined by the process, but most
+ processes ( like CMD and powershell for instance) will just exit. Setting this value to 'True' means that no
+ more input will be able to be sent to the process and attempting to do so should result in an error.
+ @return: None
+ """
+ if isinstance(stdin_input, text_type):
+ stdin_input = stdin_input.encode("437")
+ req = {'env:Envelope': self._get_soap_header(
+ resource_uri='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd', # NOQA
+ action='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send', # NOQA
+ shell_id=shell_id)}
+ stdin_envelope = req['env:Envelope'].setdefault('env:Body', {}).setdefault(
+ 'rsp:Send', {}).setdefault('rsp:Stream', {})
+ stdin_envelope['@CommandId'] = command_id
+ stdin_envelope['@Name'] = 'stdin'
+ if end:
+ stdin_envelope['@End'] = "true"
+ else:
+ stdin_envelope['@End'] = "false"
+ stdin_envelope['@xmlns:rsp'] = 'http://schemas.microsoft.com/wbem/wsman/1/windows/shell'
+ stdin_envelope['#text'] = base64.b64encode(stdin_input)
+ self.send_message(xmltodict.unparse(req))
+
def get_command_output(self, shell_id, command_id):
"""
Get the Output of the given shell and command
diff --git a/winrm/tests/conftest.py b/winrm/tests/conftest.py
index b7ab2781..7f406eef 100644
--- a/winrm/tests/conftest.py
+++ b/winrm/tests/conftest.py
@@ -311,6 +311,188 @@
"""
+run_cmd_req_input = """\
+
+
+
+ http://windows-host:5985/wsman
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ 153600
+ uuid:11111111-1111-1111-1111-111111111111
+
+
+ PT20S
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command
+
+ 11111111-1111-1111-1111-111111111113
+
+
+ TRUE
+ FALSE
+
+
+
+
+ cmd
+
+
+"""
+
+
+run_cmd_req_input_response = """\
+
+
+
+http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandResponse
+uuid:11111111-1111-1111-1111-111111111114
+http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+uuid:11111111-1111-1111-1111-111111111112
+
+
+
+11111111-1111-1111-1111-111111111111
+
+
+
+"""
+
+run_cmd_send_input = """\
+
+
+
+ http://windows-host:5985/wsman
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ 153600
+ uuid:11111111-1111-1111-1111-111111111111
+
+
+ PT20S
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send
+
+ 11111111-1111-1111-1111-111111111113
+
+
+
+
+ ZWNobyAiaGVsbG8gd29ybGQiICYmIGV4aXQNCg==
+
+
+
+"""
+
+run_cmd_send_input_response = """\
+
+
+
+http://schemas.microsoft.com/wbem/wsman/1/windows/shell/SendResponse
+uuid:72371E37-E073-474B-B4BA-6559D8D94632
+http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+uuid:9c3de121-c3a4-452b-8f82-36b84e25b7fe
+
+
+
+
+
+"""
+
+run_cmd_send_input_get_output = """\
+
+
+
+http://windows-host:5985/wsman
+
+http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+153600
+uuid:11111111-1111-1111-1111-111111111111
+
+
+PT20S
+http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
+http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive
+
+11111111-1111-1111-1111-111111111113
+
+
+
+
+stdout stderr
+
+
+
+"""
+
+run_cmd_send_input_get_output_response = """\
+
+
+
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/ReceiveResponse
+ uuid:6468086A-377E-4BE3-AC71-1155F0F1D4E1
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ uuid:02f258b6-186f-4ac0-adc3-51550a131e64
+
+
+
+ TWljcm9zb2Z0IFdpbmRvd3MgW1ZlcnNpb24gMTAuMC4xNzc2My4xMDdd
+ DQooYykgMjAxOCBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCkM6XFVzZXJzXHJ3ZWJlcj5lY2hvIGhlbGxvIHdvcmxkICYmIGV4aXQNCmhlbGxvIHdvcmxkIA0K
+
+
+
+ 0
+
+
+
+
+"""
+
+stdin_cmd_cleanup = """\
+
+
+
+ http://windows-host:5985/wsman
+
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+ 153600
+ uuid:11111111-1111-1111-1111-111111111111
+
+
+ PT20S
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal
+
+ 11111111-1111-1111-1111-111111111113
+
+
+
+
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate
+
+
+
+"""
+
+stdin_cmd_cleanup_response = """\
+
+
+
+ http://schemas.microsoft.com/wbem/wsman/1/windows/shell/SignalResponse
+ uuid:8A875405-3494-4400-A988-B47A563922E7
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+ uuid:11111111-1111-1111-1111-111111111111
+
+
+
+
+
+"""
+
def sort_dict(ordered_dict):
items = sorted(ordered_dict.items(), key=lambda x: x[0])
ordered_dict.clear()
@@ -348,6 +530,14 @@ def send_message(self, message):
return get_cmd_output_response
elif xml_str_compare(message, get_cmd_ps_output_request % '2'):
return get_ps_output_response
+ elif xml_str_compare(message, run_cmd_req_input):
+ return run_cmd_req_input_response
+ elif xml_str_compare(message, run_cmd_send_input):
+ return run_cmd_send_input_response
+ elif xml_str_compare(message, run_cmd_send_input_get_output):
+ return run_cmd_send_input_get_output_response
+ elif xml_str_compare(message, stdin_cmd_cleanup):
+ return stdin_cmd_cleanup_response
else:
raise Exception('Message was not expected\n\n%s' % message)
diff --git a/winrm/tests/test_protocol.py b/winrm/tests/test_protocol.py
index bcea47ea..ee5a2aa7 100644
--- a/winrm/tests/test_protocol.py
+++ b/winrm/tests/test_protocol.py
@@ -41,6 +41,20 @@ def test_get_command_output(protocol_fake):
protocol_fake.close_shell(shell_id)
+def test_send_command_input(protocol_fake):
+ shell_id = protocol_fake.open_shell()
+ command_id = protocol_fake.run_command(shell_id, u'cmd')
+ protocol_fake.send_command_input(shell_id, command_id, u'echo "hello world" && exit\r\n')
+ std_out, std_err, status_code = protocol_fake.get_command_output(
+ shell_id, command_id)
+ assert status_code == 0
+ assert b'hello world' in std_out
+ assert len(std_err) == 0
+
+ protocol_fake.cleanup_command(shell_id, command_id)
+ protocol_fake.close_shell(shell_id)
+
+
def test_set_timeout_as_sec():
protocol = Protocol('endpoint',
username='username',