3

I wanted to know if it was possible to use New-PsSession and Invoke-Command to an exchange server using python only? I am doing testing and DON'T want to use the subprocess module but instead wanted to know if there are any python modules that can handle powershell commands to a remote server?

I usually use this to connect to the exchange server in powershell:

    $password = ConvertTo-SecureString "SOMEPASSWORD" -AsPlainText -Force
    $Cred = New-Object System.Management.Automation.PSCredential ("ENTEREMAILHERE", $password)
    $ses = New-PSSession -Name "ENTEREMAILHERE" -ConnectionUri https://exchange.intermedia.net/powershell -ConfigurationName Hosting.PowerShell -Credential $Cred -Authentication Basic

What I tried

I tried googling some modules and came across two different modules but they both didn't seem to work for me.

I tried using pypsrp but I don't think I was able to configure it correctly

from httpx import BasicAuth
from pypsrp.powershell import PowerShell, RunspacePool
from pypsrp.wsman import WSMan

wsman = WSMan("https://exchange.intermedia.net/powershell", username="enteremail",
              password="enterpassword",
              auth="basic")

with RunspacePool(wsman) as pool:
    ps = PowerShell(pool)
    ps.add_cmdlet("Get-PSDrive").add_parameter("Name", "C")
    ps.invoke()
    # we will print the first object returned back to us
    print(ps.output[0])

I get an error saying:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='https', port=443): Max retries exceeded with url: //exchange.intermedia.net/powershell:5986/wsman (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x000002449336F610>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed'))

I know the url works as I use it with powershell everyday.

Edit: After talking with @briantist I tried:

wsman = WSMan("exchange.intermedia.net", username="EMAILHERE",
    password="PASSWORHERE",
    auth="basic",
    port=443,
    path="powershell")

and it seemed like it was going to work but then it failed with:

Code: 2150858811, Machine: exchange.intermedia.net, Reason: The WS-Management service cannot process the request. The resource URI (http://schemas.microsoft.com/powershell/Microsoft.PowerShell) was not found in  the WS-Management catalog.

I assume that is because the https:// was not there so I tried with the https:// and it gave the same error as earlier saying:

requests.exceptions.ConnectionError:
HTTPSConnectionPool(host='https', port=443): Max retries exceeded
with url: //exchange.intermedia.net:443/powershell (Caused by
NewConnectionError('<urllib3.connection.HTTPSConnection object at
0x0000020759047AC0>: Failed to establish a new  connection: [Errno
11001] getaddrinfo failed'))
  • I think I need PSRP as well, you are most likely correctly. (I am double checking that currently). That is a smart idea (regarding the path) I will try that and let you know how it worked out in your answer post below momentarily. – Kiddiescripterwithnoskill Jan 29 '22 at 04:08
  • 1
    btw I wanted to say that this is an excellent first question, and contained all the information needed to research and solve it, well done and welcome to SO! – briantist Jan 29 '22 at 17:55

1 Answers1

2

My experience with pysprp is mostly through Ansible since it powers the psrp connection plugin, but I did chat briefly with the library's creator who suggested using the host name and setting the path separately, like so:

WSMan("exchange.intermedia.net", port=443, path="powershell", ...)

Update: OP confirmed it working with this code:

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

wsman = WSMan("exchange.intermedia.net", username="ENTEREMAIL",               
              password="ENTERPASSWORD",
              auth="basic", port=443, path="powershell")  

with RunspacePool(wsman, configuration_name="Hosting.PowerShell") as pool:
    print("hello")

Key points:

  • URI-based endpoints need to be split into hostname and path with pypsrp
  • If using a non-default configuration name, be sure to pass that along to the RunspacePool object as well
briantist
  • 45,546
  • 6
  • 82
  • 127
  • @Kiddiescripterwithnoskill The first error looks better than the second. I have a feeling that this is because you left out the configuration name. In your original PowerShell example, you have `-ConfigurationName Hosting.PowerShell`; without supplying that (in `pypsrp` or in PowerShell), the implicit value for that is `Microsoft.PowerShell` which is the "missing" schema in your error. So adding `configuration_name="Hosting.PowerShell"` to your connection may do the trick. – briantist Jan 29 '22 at 04:40
  • @Kiddiescripterwithnoskill actually looking at the README on `pypsrp` you might need to add that to the `RunspacePool`, so maybe keep your `WSMan` object as is, and then do `RunspacePool(wsman, configuration_name="Hosting.PowerShell")`. As I said I haven't used this much directly myself, so my syntax might be off, but I think we're on to something with the configuration name. – briantist Jan 29 '22 at 04:44
  • I think this worked! I didn't get any errors back so I assume I connected to the exchange. This specific exchange server has specific commands that I usually use `Invoke-Command`. Here is the code I used: ````from pypsrp.powershell import PowerShell, RunspacePool from pypsrp.wsman import WSMan wsman = WSMan("exchange.intermedia.net", username="ENTEREMAIL", password="ENTERPASSWORD", auth="basic", port=443,path="powershell") with RunspacePool(wsman, configuration_name="Hosting.PowerShell") as pool: print("hello") ```` – Kiddiescripterwithnoskill Jan 29 '22 at 07:44
  • 1
    @braintist this worked! I tried adding the `RunspacePool(wsman, configuration_name="Hosting.PowerShell")` and it came back with no errors. To make sure it worked, I purposely put in a wrong password on the second attempt and it gave me an error. Then I put the password back and it didn't give me any errors! Thanks for your help! – Kiddiescripterwithnoskill Jan 29 '22 at 07:50
  • Please update/post an answer with the full solution for future reference – Scepticalist Jan 29 '22 at 08:46
  • 1
    That's great @Kiddiescripterwithnoskill, I've updated the answer with your working code. Also if you want to test it more thoroughly you'll have to use a command that exists in the session, so you could try it with an Exchange-specific command, but most session configurations, even ones that are very locked down, allow `Get-Command`, so that's the one I'd try to first to confirm it working end-to-end. – briantist Jan 29 '22 at 15:04
  • 1
    For future reference, code is hard to see in the comments, and comments get deleted. You may edit your question, or even my answer if you want to update what's here for future readers. Updates to questions and answers not posted by you will be subject to community review or acceptance by the poster before going live. – briantist Jan 29 '22 at 15:06
  • This server does allow `Get-Command` so I will try that one today. Also I will update my question with edits that show my updated code. Thanks for the suggestion! – Kiddiescripterwithnoskill Jan 29 '22 at 17:50