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

New authentication event on each invoke call on the same ps object #166

Open
abhispra opened this issue Dec 21, 2022 · 3 comments
Open

New authentication event on each invoke call on the same ps object #166

abhispra opened this issue Dec 21, 2022 · 3 comments

Comments

@abhispra
Copy link

abhispra commented Dec 21, 2022

Hi Jordan,

I'm observing a logon event for each invoke call on the same PS object. Sample code

import logging
import psrp

logging.basicConfig(filename='out.txt', level=logging.DEBUG)
conn = psrp.WSManInfo("WIN-MLEMJVSIP4P.corp.xyz.com", auth="ntlm",
                             username='administrator', password='********')
with psrp.SyncRunspacePool(conn) as rp:
    ps = psrp.SyncPowerShell(rp)
    ps.add_command("Get-Item").add_parameter("-Path", "HKLM:\\Software\\Mozilla")
    object = ps.invoke()
    ps.add_statement()
    ps.add_command("Get-Item").add_parameter("-Path", "HKLM:\\Software\\Mozilla\\Firefox")
    object = ps.invoke()
    val = ps.invoke()
    print(object)
    print(val)

The above code generates a large number of logon events. Notably, each invocation of the invoke function call is performing a logon.

Considering that I'm using a SyncRunSpacePool and SyncPowerShell instance on the same ps object, shouldn't there be one logon and then reuse the session rather than a logon? Am I missing something here, or have you noticed similar things? Thank you for all your help.

Edited the domain and password.

@jborean93
Copy link
Owner

jborean93 commented Dec 21, 2022

This is expected and how the native Windows PowerShell client works. Each Runspace Pool and Pipeline spawn a background listener thread. These threads must be run on a new connection which means they must reauthenticate themselves so in this script example you will see:

  • 1 logon for the main thread
  • 1 logon for the runspace pool listener
  • 3 logons for the pipeline invokes (1 per .invoke())

The primary reason why this is done is the runspace pool and/or pipeline can send back events that are handled as they come in rather than through something that blocks the main thread. This enables the following

  • Responding to host events like ReadLine, Prompt, PromptForCredential etc
  • Firing UserEvents on the fly
  • Capturing output as it comes in rather than when the main thread pumps the stream

@abhispra
Copy link
Author

Thank you for the explanation.

The thing that I don't fully comprehend - aren't the above invoke running on the same pipeline?
I wrote the below C# program using dot net core to test my understanding.

namespace Samples
{
    using System;
    using System.Security;
    using System.Collections.ObjectModel;
    using System.Management.Automation;            // PowerShell namespace.
    using System.Management.Automation.Runspaces;  // PowerShell namespace.

    internal class RemoteRunspace02
    {
        private static void Main(string[] args)
        {
            Uri RemoteComputerUri = new Uri("https://WIN-MLEMJVSIP4P.corp.xyz.com:5986/WSMAN");
            WSManConnectionInfo connectionInfo = new WSManConnectionInfo(RemoteComputerUri);
            connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
            SecureString securePwd = new SecureString();
            string pwd = "*********";
            foreach (char ch in pwd)
            {
                securePwd.AppendChar(ch);
            }
            connectionInfo.Credential = new PSCredential("wstest", securePwd);
            connectionInfo.OperationTimeout = 4 * 60 * 1000; // 4 minutes.
            connectionInfo.OpenTimeout = 1 * 60 * 1000; // 1 minute.
            connectionInfo.NoMachineProfile = true;
            connectionInfo.SkipCACheck = true;
            connectionInfo.SkipRevocationCheck = true;

            using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
            {
                remoteRunspace.Open();
                using (PowerShell powershell = PowerShell.Create())
                {
                    powershell.Runspace = remoteRunspace;

                    powershell.AddCommand("Get-Item");
                    powershell.AddParameter("-Path", "HKLM:\\Software\\Mozilla");
                    Collection<PSObject> results = powershell.Invoke();
                    Console.WriteLine(results);
                    powershell.AddStatement();
                    powershell.AddCommand("Get-Item");
                    powershell.AddParameter("-Path", "HKLM:\\Software\\Mozilla\\Firefox");
                    results = powershell.Invoke();
                    Console.WriteLine(results);
                    powershell.AddStatement();
                    powershell.AddCommand("Get-Item");
                    powershell.AddParameter("-Path", "HKLM:\\Software\\Mozilla\\Mozilla Firefox");
                    results = powershell.Invoke();
                    Console.WriteLine(results);
                    powershell.AddCommand("Get-Item");
                    powershell.AddParameter("-Path", "HKLM:\\Software\\Mozilla\\Mozilla Firefox");
                    results = powershell.Invoke();
                    Console.WriteLine(results);
                    powershell.AddCommand("Get-Item");
                    powershell.AddParameter("-Path", "HKLM:\\Software\\Mozilla\\Mozilla Firefox");
                    results = powershell.Invoke();
                    Console.WriteLine(results);
                }
                remoteRunspace.Close();
            }
        }
    }
}

Here I see three logon events generated for the wstest user irrespective of the number of invoke calls. Shouldn't the behavior be similar for both programs, or is there something basic I'm missing? Thanks again for all the help!

@jborean93
Copy link
Owner

Hmm, I'll have to look into that and maybe rework it. I always assumed that each receive operation (which starts per invocation) was on the separate thread and thus separate connection.

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