jborean93 / pypsrp

PowerShell Remoting Protocol for Python
MIT License
326 stars 49 forks source link

WSManFaultError: Code: 2150858843, Windows Remote Shell Shell ID #22

Open hkelley opened 5 years ago

hkelley commented 5 years ago

I have two Python scripts using pypsrp. The first script I created works fine. The second script - even when calling the same cmdlet as the first, returns a ShellID exception.

    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
      ps = PowerShell(pool)
      ps.add_cmdlet("Get-QuarantineMessage")
      output_list = ps.invoke()

I get this result:

Traceback (most recent call last):
 . ..
  File "c:\Python27\lib\site-packages\pypsrp\powershell.py", line 198, in __enter__
    self.open()
  File "c:\Python27\lib\site-packages\pypsrp\powershell.py", line 511, in open
    responses.extend(self._receive())
  File "c:\Python27\lib\site-packages\pypsrp\powershell.py", line 634, in _receive
    timeout=timeout)[2]['stdout']
  File "c:\Python27\lib\site-packages\pypsrp\shell.py", line 241, in receive
    timeout=timeout)
  File "c:\Python27\lib\site-packages\pypsrp\wsman.py", line 298, in receive
    option_set, selector_set, timeout)
  File "c:\Python27\lib\site-packages\pypsrp\wsman.py", line 379, in invoke
    raise self._parse_wsman_fault(err.response_text)
pypsrp.exceptions.WSManFaultError: Received a WSManFault message. (Code: 2150858843, Machine: outlook.office365.com, Reason: The request for the Windows Remote Shell with ShellId 2E09FEFA-93D1-4C71-B272-9349E526E5A4 failed because the shell was not found on the server. Possible causes are: the specified ShellId is incorrect or the shell no longer exists on the server. Provide the correct ShellId or create a new shell and retry the operation.)
hkelley commented 5 years ago

I've been testing some more and this seems to be a connection clean-up issue. I noticed that the script fails once every time I save it, then runs cleanly until I save the script again. Perhaps O365 cleans up the RunspacePool after my failed attempt and then lets the same command execute again and again.

I'm trying to figure out the WSMan disconnect() and delete() methods but don't know what resource_uri I should provide.

delete(self, resource_uri, resource=None, option_set=None,
               selector_set=None, timeout=None):
jborean93 commented 5 years ago

If there was an error in creating the Runspace Pool that wasn't returned back to pypsrp then it will blindly send the next message which is a receive message with the ShellID it had set. If this ShellID does not exist then you would get the message you put here. Typically on a failure scenario, the server will clean up any resources and hopefully logs the error in the event logs.

I don't have an exchange host or Office 365 account to test this against so I unfortunately can't help you too much. Every execution will generate a unique id for the shell/runspace so there should not be any collisions when it comes to the ID.

I'm trying to figure out the WSMan disconnect() and delete() methods but don't know what resource_uri I should provide.

For PSRP, the resource URI is always http://schemas.microsoft.com/powershell/<configuration_name>, in your case it would be http://schemas.microsoft.com/powershell/Microsoft.Exchange. You shouldn't need to use the WSMan methods at all for PSRP as there are analogues to these, e.g. disconnect() ==pool.disconnect()anddelete() == pool.close(). Even so, using with RunspacePool(wsman) as pool: will have Python close the pool for you, unless you want to manually close it you don't have to call this yourself.

KKomarov commented 5 years ago

Reproduced the problem, and played with it a little bit. I think I know what is the problem. Receive message is sent too fast. It helps to add a little sleep before receive. Maybe better to add retries on receiving.