Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Powershell invocations fail after #MaxConcurrentCommandsPerShell sequential commands #148

Open
antaln opened this issue Apr 8, 2022 · 3 comments

Comments

@antaln
Copy link

antaln commented Apr 8, 2022

Powershell invocations fail after #MaxConcurrentCommandsPerShell sequential commands.
From what I can tell, this is not really a pypsrp issue, but a Windows WSMV implementation behavior.

Example

Consider the following snippet:

with wsman, RunspacePool(wsman) as pool:
  
    for x in range(2000):
        ps = PowerShell(pool)
        ps.add_script("$PSVersionTable.Count")
        output = ps.invoke()
        print("x={}, out={}".format(x, output)) 

This fails after on my Win 2012R2 box after 1000 calls with following exception:

pypsrp.exceptions.WSManFaultError: Received a WSManFault message. (Code: w:InternalError, Reason: The WS-Management service cannot process the request. The maximum number of concurrent commands per shell has been exceeded. Retry the request later or raise the Maximum Commands per Shell quota.)

Analysis

This appears to be governed by Plugin\microsoft.powershell\Quotas\MaxConcurrentCommandsPerShell quota.

From what I can tell, this looks like it's intentional:

MS:WSMV, Product Behavior note 118 states:

Section 3.1.4.12: Windows implementations of the Shell processor do not decrement the MaxConcurrentOperationsPerUser counter when a Signal request with a Terminate code is issued to a Text-based Command Shell.

but is in violation of the protocol spec:

If the control code of the Signal request (section 2.2.4.38) is http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/Terminate, the Shell processor MUST decrement the server-side counter for MaxConcurrentOperationsPerUser.<118>

I am somewhat perplexed that a counter preventing concurrent commands would be actually used to limit sequential commands in a remote shell. Am I missing something here?

@antaln
Copy link
Author

antaln commented Apr 8, 2022

The limit applies only to MS:WSMV Text-based shells. AFAIK, PowerShell is considered a custom shell.

PSRP also requires sending terminate signal after conclusion of each command.

@jborean93
Copy link
Owner

jborean93 commented Apr 11, 2022

Hmm I thought I added the signal to the PowerShell class to do this but looking at the code that does not seem to be the case. The simplest solution seems to be to add a close() method that sends the Terminate signal that will decrement the command counter. It would be best to do it automatically but at this particular point in time I cannot as it's designed to be as efficient for tools like Ansible. Ansible gets away with it because they close the shell which also ends the counter.

As a workaround for now you can do

from pypsrp.wsman import SignalCode, WSMan
from pypsrp.powershell import PowerShell, RunspacePool

with wsman, RunspacePool(wsman) as pool:
    for x in range(2000):
        ps = PowerShell(pool)
        ps.add_script("$PSVersionTable.Count")
        output = ps.invoke()
        pool.shell.signal(SignalCode.TERMINATE, str(ps.id).upper())
        print("x={}, out={}".format(x, output)) 

Also as an FYI, the new psrp namespace that's being written right now does do this by default but this is still in development.

@antaln
Copy link
Author

antaln commented Apr 14, 2022

Cool, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants