Powershell Remoting w C##

W Powershell  2.0 mamy możliwość zdalnego wykonywania poleceń. Powershell domyślnie też umożliwia odwołania z kodu C#  do comandletów Powershellowych. Jednak połączenie remotingu Powershella oraz C# nie jest prostym zadaniem – brakuje po prostu przykładów. Nawet google jest w tym wypadku bezradny.

Po wnikliwej lekturze SDK do Powershell-a, możemy znaleźć klasę RunspaceConnectionInfo, ale niestety ta klasa ma prywatny konstruktor. Na szczęście jest klasa WSManConnection Info.

Jak więc zacząć? Zacznijmy od wymaganych klas:

using System.Collections.Generic;
using System.Management.Automation;
using System.Collections.ObjectModel;
using System.Management.Automation.Runspaces;

Przy czym odwołanie do System.Management.Automation; wymaga referencji do klasy System.Management.Automation.dll. Domyślnie klasa nie jest wrzucana do GAC, więc ręcznie musimy przeszukać katalog %WinDir% i ją sobie wyciągnąć.

Remote powershell ma ogrniczenie co do ilości sesji, więc musimy gdzieś przechowywać informacje o sesji. Tu na przykład przechowuję informację o tworzeniu sesji w globalnych zmiennych aplikacji:

  /// <summary>
        /// Opens remote runspace
        /// </summary>
        /// <param name="uri">Uri to connect to, for example https://pod51002psh.outlook.com/powershell/"</param>
        /// <param name="schema">Schema of connection, for example http://schemas.microsoft.com/powershell/Microsoft.Exchange</param>
        /// <param name="username">Username</param>
        /// <param name="password">Secure pasword</param>
        /// <returns></returns>
        public void openRunspace(string uri, string schema, string username, string livePass)
        {
            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.Basic;
            Runspace runspace = RunspaceFactory.CreateRunspace(rri);
            runspace.Open();
            Application["runspace"] = runspace;
        }
A inicjalizacja takiej funkcji by wyglądała np tak:
protected void Application_Start(object sender, EventArgs e)
        {
            string psremoteserver = "https://pod51002psh.outlook.com/powershell/";
            string liveLogin = "liveadmin@domain.fqdn";
            string livePass = "Pass";
            string schema = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
            if (Application["runspace"] == null)
                openRunspace(psremoteserver, schema, liveLogin, livePass);
        }

Nie zapomnijmy o zamykaniu sesji:

 protected void Application_End(object sender, EventArgs e)
        {
            if (Application["runspace"] != null)
            {
                Runspace rs = (Runspace)Application["runspace"];
                rs.Close();
            }
        }
protected void Application_Error(object sender, EventArgs e)
        {
            if (Application["runspace"] != null)
            {
                Runspace rs = (Runspace)Application["runspace"];
                rs.Close();
            }
        }
Po stworzeniu połączenia nie pozostaje nam nic innego jak go użyć. Np tak:
   /// <summary>
        /// Opens remote runspace
        /// </summary>
        /// <param name="uri">Uri to connect to, for example https://pod51002psh.outlook.com/powershell/"</param>
        /// <param name="schema">Schema of connection, for example http://schemas.microsoft.com/powershell/Microsoft.Exchange</param>
        /// <param name="username">Username</param>
        /// <param name="password">Secure pasword</param>
        /// <returns></returns>
        public void openRunspace(string uri, string schema, string username, string livePass)
        {
            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.Basic;
            Runspace runspace = RunspaceFactory.CreateRunspace(rri);
            runspace.Open();
            Application["runspace"] = runspace;
        }
        private Runspace getRunSpace()
        {
            Runspace runspace = (Runspace)Application["runspace"];
            if (runspace.RunspaceStateInfo.State != RunspaceState.Opened)
                runspace.Open();
            return runspace;
        }
        /// <summary>
        /// Invokes any powershell script
        /// </summary>
        /// <param name="scriptText">script to invoke</param>
        /// <returns></returns>
        public Collection<PSObject> RunScript(string scriptText)
        {
            Runspace runspace = getRunSpace();
            // create a pipeline and feed it the script text
            Pipeline pipeline = runspace.CreatePipeline();
            pipeline.Commands.AddScript(scriptText);
            // execute the script
            Collection<PSObject> results = new Collection<PSObject>();
            results = pipeline.Invoke();
            return results;
        }
        /// <summary>
        /// Invoke simple command
        /// Ex.
        ///  Collection<PSObject> col = RunCommand("Get-Mailbox");
        /// </summary>
        /// <param name="command">Command Name</param>
        /// <returns></returns>
        public Collection<PSObject> RunCommand(string command)
        {
            Command myCommand = new Command(command);
            Pipeline pipeLine = getRunSpace().CreatePipeline();
            pipeLine.Commands.Add(myCommand);
            return pipeLine.Invoke();
        }
        /// <summary>
        /// Invoke command with single paramtere
        /// </summary>
        /// <param name="command">Command</param>
        /// <param name="param">Command parameter</param>
        /// <returns></returns>
        public Collection<PSObject> RunCommand(string command, string param)
        {
            Command myCommand = new Command(command);
            myCommand.Parameters.Add(param);
            Pipeline pipeLine = getRunSpace().CreatePipeline();
            pipeLine.Commands.Add(myCommand);
            return pipeLine.Invoke();
        }
        /// <summary>
        /// Invoke command with single named parameter
        /// Ex.
        ///  Collection<PSObject> col = RunCommand("Get-Mailbox","Identity","usr@iscg.eu");
        /// </summary>
        /// <param name="command">Command to invoke</param>
        /// <param name="param">Parameter Name</param>
        /// <param name="paramValue">Parameter value</param>
        /// <returns></returns>
        public Collection<PSObject> RunCommand(string command, string param, object paramValue)
        {
            Command myCommand = new Command(command);
            myCommand.Parameters.Add(new CommandParameter(param, paramValue));
            Pipeline pipeLine = getRunSpace().CreatePipeline();
            pipeLine.Commands.Add(myCommand);
            return pipeLine.Invoke();
        }
        /// <summary>
        /// Invokes command with collection of paramters
        /// Ex.
        /// Collection<CommandParameter> cpc = new Collection<CommandParameter>();
        ///        cpc.Add(new CommandParameter("Identity", "user@iscg.eu"));
        ///        Collection<PSObject> col = RunCommand("Get-Mailbox",cpc);
        /// </summary>
        /// <param name="command"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public Collection<PSObject> RunCommand(string command, Collection<CommandParameter> param)
        {
            Command myCommand = new Command(command);
            foreach (CommandParameter cp in param)
                myCommand.Parameters.Add(cp);
            Pipeline pipeLine = getRunSpace().CreatePipeline();
            pipeLine.Commands.Add(myCommand);
            return pipeLine.Invoke();
        }
        public string translatePSObject(Collection<PSObject> input)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (PSObject obj in (input))
            {
                stringBuilder.AppendLine(obj.ToString() + obj.GetType() + obj.ImmediateBaseObject.GetType());
            }
            return stringBuilder.ToString();
        }
Wednesday, April 22, 2009 9:48:22 PM (Central European Standard Time, UTC+01:00) #    Comments [0]  |  Trackback Tracked by:
"UMnieDziala.pl - Powershell Remoting w C#" (dotnetomaniak.pl) [Trackback]

 

All content © 2010, Krzysztof Pietrzak
On this page
This site
Calendar
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
Archives
Sitemap
Blogroll OPML
  Tokyo by night
blog WiTa
  W-Files
blog n€x¤Ra
 .:fotoblog:.
blog Kfaza
 \\archon\blog$
blog archona
 Czasowstrzymywacz
Blog Fookyego
 Jog Pstryka
Jog Pstryka
 Mac OS X vs. Active Directory
techniczny blog kfaza

Maps
Locations of visitors to this page