1

I need to invoke a script (or several scripts) on multiple remote hosts. Consider this as environment installation on several hosts that should be done in parallel to improve performance. The application that instructs these scripts to be invoked is written in C#. I'm using PowerShell C# Host to invoke scripts on remote target machines.

Example (I am trying to achieve parallel script invocation on remote machines):

Parallel.ForEach(allActions.GroupBy(a=>a.TargetHostname), hostActions => { foreach (var action in hostActions) { action.Execute(); // Implementation of "execute" will contain remote PowerShell call } }); 

The implementation in each "Execute" method will subsequently call the following:

 public ICollection<string> InvokeCommandOnRemoteHost(string targetHost, string command, string arguments) { var runspaceConfiguration = RunspaceConfiguration.Create(); using (var runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration)) { runspace.Open(); using (var pipeline = runspace.CreatePipeline()) { var psCommand = new Command(@"..\Remote-CommandInvocation.ps1"); psCommand.Parameters.Add("targetHost", targetHost); psCommand.Parameters.Add("application", command); psCommand.Parameters.Add("arguments", arguments); pipeline.Commands.Add(psCommand); var result = pipeline.Invoke(); //. . . 

Note: although invoked in a local runspace, the Remote-CommandInvocation.ps1 will create a remote session and invoke commands on a remote PC (using "new-pssession" or "enter-pssession").

I have noticed however that creating runspace takes quite a bit of time, for example invocation of "RunspaceConfiguration.Create();" takes around 500ms on my box (according to VS profiling). "runspace.Open();" takes abour 1.5 seconds. All in all a cost of 2 seconds per command execution.

Obviously, this is sub-optimal, since this cost will be paid for each remote command invocation.

The next improvement was to use shared RunspacePool for the lifetime of the application and reuse runspaces from it when invoking commands in parallel:

 public RemoteCommandInvoker() // ctor, singleton class { var iss = InitialSessionState.CreateDefault2(); rsp = RunspaceFactory.CreateRunspacePool(iss); rsp.SetMinRunspaces(5); rsp.SetMaxRunspaces(25); rsp.ThreadOptions = PSThreadOptions.UseNewThread; rsp.Open(); } public ICollection<string> InvokeCommandOnRemoteHost(string targetHost, string command, string arguments) { var resultList = new List<string>(); var ps = PowerShell.Create(); ps.RunspacePool = rsp; ps.AddCommand(@"..\Remote-CommandInvocation.ps1"); ps.AddParameter("targetHost", targetHost); ps.AddParameter("application", command); ps.AddParameter("arguments", arguments); var result = ps.Invoke(); //... 

Although the cost of runspace pool initialization is roughly the same (~2 seconds), it is now executed once per application lifetime and all further command invocations happen quickly enough.

Question:

Is this a correct approach for optimizing the invocation of multiple scripts on multiple remote machines, or it should be done differently, or done better? Should constrained pools or remote pools be used in this case?

Thanks.

1 Answer 1

1

Check out the Remote Runspace Samples: https://msdn.microsoft.com/en-us/library/ee706591(v=vs.85).aspx

You're probably loosing some time by using C# to call PowerShell to initiate a new powershell session.

I think this might work a little quicker for you:

Collection<PSObject> results; WSManConnectionInfo connectionInfo = new WSManConnectionInfo() { ComputerName = "COMPUTER" }; using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo)) { runspace.Open(); using (PowerShell ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddScript("something to run"); results = ps.Invoke(); if(ps.HadErrors) { //Throw or log if you want //ps.Streams.Error.ElementAt(0).Exception; } } runspace.Close(); } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.