Search code examples
pythonpowershellpowershell-remoting

New-PSSession using python only (no subprocess module)


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'))

Solution

  • 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