ScorpioTek Solutions
07-filler-left Information about ScorpioTek Services Offered by ScorpioTek Training Courses Offered by ScorpioTek Technology Blog by ScorpioTek Contact us for more information on training/services 08-filler-right
06-message

How to Execute Remote PowerShell Commands using C#

UPDATE: The post below works when you are trying to execute simple commands.  I had issues when trying to execute full scripts.  After searching some more, I found amazing tutorials on how to carry out this procedure, check them out:


Before I start this post that I am urging to write (before I forget all I did), I must clarify that all the code here was from various sites/forums.  All I did was to try and get the combination right, which basically took all of my time yesterday.  Nonetheless, at least it’s working.

So what I am writing at this moment is a C# application that will issue SCVMM commands from any machine in my domain.  SCVMM’s API is 100% PowerShell, so anything you need to run automatically via code in SCVMM, needs to be called through PowerShell somehow.

PowerShell v2.0 includes Remoting, which allows you to issue PowerShell commands remotely on other machines by using Windows Remote Management (WinRM).  So let’s see how on Earth this is done:

Pre-reqs

Before you do any of this, you must run the following command in an admin PowerShell command prompt on the machine where you would like to run the remote command:

winrm quickconfig

The Code References

You need to use the correct version of System.Management.Automation.dll.  If you are running Windows 7 / Windows Server 2008 R2, you must include this reference in your project from the following path:

C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll

Note: When importing the aforementioned DLL, I was having all kinds of issues with Visual Studio 2008.  I tried it with Visual Studio 2010 and it worked right away.

The Namespaces

Include the following namespaces in your code:

using System.Management.Automation; // Windows PowerShell namespace
using System.Management.Automation.Runspaces; // Windows PowerShell namespace
using System.Security; // For the secure password

The Function

This is the function you need to invoke when you want to run a remote command.  The incoming string, scriptText, is the PowerShell command you would like to execute:

public static string RunScript(string scriptText)
        {

           Runspace remoteRunspace = null;
           openRunspace("http://SERVERNAME:5985/wsman",
                "http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
                @"DOMAIN\USERNAME",
                "PASSWORD",
                ref remoteRunspace);

                StringBuilder stringBuilder = new StringBuilder();
                using (PowerShell powershell = PowerShell.Create())
                {
                    powershell.Runspace = remoteRunspace;
                    powershell.AddCommand("get-process");
                    powershell.Invoke();
                    Collection<PSObject> results = powershell.Invoke();
                    remoteRunspace.Close();
                    foreach (PSObject obj in results)
                    {
                        stringBuilder.AppendLine(obj.ToString());
                    }
                }

                return stringBuilder.ToString();
         }

Note that you must replace DOMAIN\USERNAME with your domain and username.  You must also replace PASSWORD with your password.  I really don’t know how to carry this out using my logged-in credentials, so until then, I’ll have to include my password in the code, which is crappy but works.  Also note that you must also replace SERVERNAME with the machine you are trying to connect to.  The port MUST be 5985, if you try the default (80), it will fail to connect (at least, it did in my case).

The magic happens inside the static function openRunspace which is defined as follows:

        public static void  openRunspace(string uri, string schema, string username, string livePass, ref Runspace remoteRunspace)
        {
            System.Security.SecureString password = new System.Security.SecureString();
            foreach (char c in livePass.ToCharArray())
            {
                password.AppendChar(c);
            }
            PSCredential psc = new PSCredential(username, password);
            WSManConnectionInfo rri = new WSManConnectionInfo(new Uri(uri), schema, psc);
            rri.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
            rri.ProxyAuthentication = AuthenticationMechanism.Negotiate;
            remoteRunspace = RunspaceFactory.CreateRunspace(rri);
            remoteRunspace.Open();
        }

Let me know if it works for you in the comments.

Sources:

8 Responses to “How to Execute Remote PowerShell Commands using C#”

  1. How to Execute Remote PowerShell Commands using C# | ScorpioTek's Blog | Source code bank Says:

    [...] here: How to Execute Remote PowerShell Commands using C# | ScorpioTek's Blog If you enjoyed this article please consider sharing [...]

  2. Carlos Says:

    Thanks! This worked fine for me, very helpful :)

  3. zang Says:

    I have Mailbox server installed on “Server1″ in domain “Domain1″ (Win Server 2003 & Exchange2007 )

    I have one more PC running on Windows7 named “MyComputer” in domain “MyDomain”

    Now i try to run the code but it gives Exception
    ” An unhandled exception of type ‘System.Management.Automation.Remoting.PSRemotingTransportException’ occurred in System.Management.Automation.dll

    Additional information: Connecting to remote server failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.”

    and when i run http://MyServer1.domain1.com:5985/wsman in IE from MyComputer, it does not display anything with “HTTP 405 Method not allowed”

    i also tried http://IPAddressOfServer1:5985/wsman

    i also tried to run both of above on Server1 but it didn’t showed anything.

    I don’t know if this is an issue with wsman or not ? Could anyone help me!

    I have winrm Version 2 and powershell version 2 on both
    I also have applied update on server 2003
    I also have added exceptions in firewall for ports
    I also have added both ip’s in trusted list..

  4. Chris Mangiapane Says:

    Thanks this post was really helpful, especially the updated location of C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll.

    However, I am still getting the error “Connecting to remote server failed with the following error message : The server certificate on the destination computer (seexchange2.soniceaglehq.com:5985) has the following errors: Encountered an internal error in the SSL library.”

    I am trying to build a .Net 4.5, C#, ASP.NET web site, to create/remove/modify Exchange 2010 mail accounts using Power Shell.
    Akashb has a .NET 2.0 Exchange 2007 example (http://blogs.msdn.com/b/akashb/archive/2009/01/30/howto-using-powershell-in-asp-net-net-framework-2-0.aspx) that is very well done, but as Chuck Bigham pointed out, “Exchange 2010 uses Remote PowerShell” now.

    The Exchange Team’s posting at http://msexchangeteam.com/archive/2009/11/02/453016.aspx seems to be what’s needed but is missing some key components and does not compile. I cannot find the WSManConnectionInfo namespace to reference (that you provided :) )

    I am a bit at a loss of where to look next. Can you please give a bit of information about the WSManConnectionInfo(new Uri(uri), schema, psc); command, specifically the Uri. Our Exchange server is https, not http, don’t know if that could be the issue. Also I am assuming the winrm quickconfig command is run on the remore server, not my client develoment PC, right?

    Thank again, I feel like I am very close, just missing one more piece of the puzzle.

    Chris Mangiapane, MCSD

  5. Gerson Says:

    I did all you said in the article and i am having that error :
    Cannot bind parameter ‘SipAddress’ to the target. Exception setting “SipAddress”: “Active Directory error “-2147016672″ occurred while searching for domain controllers in domain
    To module Lync work’s i put that command :

    powershell.AddScript(“Import-Module Lync”);
    powershell.Invoke();
    powershell.Streams.ClearStreams();
    powershell.AddCommand(“Enable-CsUser”);
    powershell.AddParameter(“Identity”, “gcjunior”);
    powershell.AddParameter(“RegistrarPool”, “ab2k801lyncfe.dominio”);
    powershell.AddParameter(“SipDomain”, “dominio.org.br”);
    powershell.AddParameter(“SipAddress”, “sip:gcjunior@dominio”);

    Thx.

  6. Appaso Says:

    i want to run PSS to create VM on VMWare, i have created function as given by u.. but application files to authenticate even-though i have given correct credentials… plz help.

  7. Appaso Says:

    i have created on windows application for creation on Vm through PSS on VMWare. And included your functions.. given correct credentials but application fail to authenticate.. plz help.

  8. Alok Kumar Sharma Says:

    How to execute Hyper-v cmdlets Command using C#
    I am using the following code and i get the below mention Error.
    Use Code

    private string RunScriptNew()
    {
    PowerShell ps;
    ps = PowerShell.Create();
    // Add the PowerShell script to be run
    ps.AddScript(“GET-VM”);
    ps.Commands.AddCommand(“Out-String”);
    // execute the script
    Collection results = ps.Invoke();
    StringBuilder stringBuilder = new StringBuilder();
    // convert the script result into a single string
    foreach (PSObject obj in results)
    {

    stringBuilder.Append(obj.ToString());

    }

    // convert the erros into a single string

    foreach (ErrorRecord error in ps.Streams.Error)
    {
    stringBuilder.Append(error.ToString());
    }
    return (string)

    }

    Error:-The term ‘GET-VM’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.