none
Example how to use Remote Runspaces with delegate Credential with Powershell Constrained Endpoint RRS feed

  • Question

  • Hi everyone,

    I would like to share with you a solution if it can help someone else.

    If you want to use PowerShell Constrained Endpoint with C# you won't find any information on it because PowerShell use this command :

    Invoke-Command -ComputerName <myremoteserver> -ConfigurationName <myconstrained.endpoint> -Credential <Pscredential> -ScriptBlock { <command to run> } -ArgumentList <myargs>

    The problem is C# doesn't use ConfigurationName parameter, so it is very hard to find a way to work with it.

    In C# you will make a PowerShell instance and you will do something like this :

    PowerShell pShell = PowerShell.Create(); pShell.Commands.Clear(); pShell.AddCommand("Get-Command") .AddParameter("Name", "Get-*") .Invoke();

    But, it means :

    - You have some privileges to run it remotely

    - You run the command under your user

    - You use the default runspace which is quite unrestricted.

    - You have the cmdlet locally (e.g. for Active Directory you have to install RSAT)

    Imagine (in my case) you have to :

    - Use your account as a user, not even a minus privilege

    - Use your account to run the app and perform action without the ability to make any PowerShell connection

    - Use all the cmdlet available on any server regardless your cmdlet locally (e.g. Get-ADuser without RSAT)

    - Allow the app to only run authorized cmdlets

    How will you do that ?

    Rights and CmdLets problems are solved with only one thing : Constrained Endpoint and Dedicated User. Please refer to this post (https://blogs.technet.microsoft.com/heyscriptingguy/2014/03/31/introduction-to-powershell-endpoints)

    Yes, but in C# ???

    In C# when you open a new PowerShell instance, the instance runs in the default runspace. In most of case, it is enough to invoke command remotely. But the context I'just talk about is not appropriate.

    If you do this :

    PowerShell pShell = PowerShell.Create();
               pShell.Commands.Clear();
               pShell.AddCommand("Invoke-Command")
                     .AddParameter("ComputerName", "srv1")
                     .AddParameter("ConfigurationName", "Microsoft.Powershell")
                     .AddParameter("ScriptBlock", scriptblock)
                     .Invoke();

    Normally, everybody think it will work but... No. I tried a lot of different way and the result still the same. No exceptions, but no correct result.

    Then I dig deeper about the runspaces. Instead of using the default one, I decided to create mine. And after some days, I success. The problem is : how to specify the ConfigurationName parameter so easily found in PowerShell, in C# ??? Answer... There is no ConfigurationName.

    I didn't find anywhere someone talking about clearly how runspace shellUri works. Every body say : "...copy 'http://schemas.microsoft.com/powershell' and it will work".

    But... First,  I don't like copy/paste without understanding what I do, and second, it doesn't use my constrained endpoint but the default one.

    Someone say that to connect to Exchange cmdlet he had to use : http://schemas.microsoft.com/powershell/Microsoft.Exchange

    Then, I realise that it looks like very close to Microsoft.PowerShell which is the default one. What happens if I replace the Microsoft.Exchange with my constrained endpoint.

    So now you have some explanation, I share you a piece of code which can help you I hope.

    //Create the connectioninfo object
    WSManConnectionInfo connectionInfo = new WSManConnectionInfo
    {
         AuthenticationMechanism = AuthenticationMechanism.Kerberos,
         ComputerName = "remote.server",                
         Credential = myPSCredential,
         ShellUri = "http://schemas.microsoft.com/powershell/constrained.endpoint"
    };
    
    // Create a remote runspace using the connection information.
    using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
    {
         // Establish the connection by calling the Open() method to open the runspace.                
         try
         {
              remoteRunspace?.Open();
    
              using (PowerShell powershell = PowerShell.Create())
              {
                   powershell.Runspace = remoteRunspace;
    
                   // Create a pipeline with the Get-Command command.
                   powershell.AddCommand("Get-Command");
    
                   Collection<PSObject> results = powershell.Invoke();
    
                   // Display each result object.
                   foreach (PSObject result in results)
                   {
                        Console.WriteLine($@"{result.Members["verb"].Value} {result.Members["Noun"].Value}");
                   }
              }
         }
         catch(Exception e)
         {
              MessageBox.Show(e.Message);
         }
    
         // Close the connection.
         remoteRunspace.Close();
    }
    Enjoy


    The key of learning is practice.



    Wednesday, May 23, 2018 3:13 AM

All replies

  • Hi arnaud.helin,

    First, I am not good at PowerShell, could you check the script run well in Windows PowerShell?

    If yes, please try to download the source file from code project. There is an article on embedding and/or launching PowerShell scripts from a C# program.

    https://www.codeproject.com/Articles/18229/How-to-run-PowerShell-scripts-from-C

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, May 24, 2018 8:19 AM
    Moderator
  • Hi Wendy,

    What do you expect from me exactly ? I do not understand precisely.

    Regards,

    Arnaud


    The key of learning is practice.


    Friday, May 25, 2018 2:52 AM