0

I have what I believe to be a unique situation. I have about 15 PowerShell scripts that I want to run against a list of computers and have the scripts return back the output from each script on each host.

What I have works, however it does not appear run the scripts on each host simultaneously and is quite slow. Any help is appreciated.

 for (int i = 0; i < hosts.Length; i++) { var remoteComputer = new Uri(String.Format("{0}://{1}:5985/wsman", "http", hosts[i])); var connection = new WSManConnectionInfo(remoteComputer); var runspace = RunspaceFactory.CreateRunspace(connection); runspace.Open(); for (int ii = 0; ii < powerShellfiles.ToArray().Length; ii++) { using (PowerShell ps = PowerShell.Create()) { ps.Runspace = runspace; //ps.AddScript(powerShellfiles[ii]); ps.AddScript(powerShellfiles[ii]); IAsyncResult async = ps.BeginInvoke(); List<string> aa = ps.EndInvoke(async).SelectMany(x => x.Properties.Where(y => y.Name == "rec_num").Select(z => z.Value.ToString())).ToList(); keysFromhost.AddRange(aa); } }; }; 

Each item within powerShellfiles is the text from the .ps1 file itself.

1 Answer 1

2

All you need to do is use the Parallel.ForEach Async framework/Class and method. This is a pretty simple solution Parallel will spawn individual threads for each item in the array that you provide and won't return until all threads has finished their execution you may also check the return value and see if all tasks completed successfully.

Now for your results you will need a thread safe collection, this one has been part of the .net framework since 3.0 I would use the one I specified below:

System.Collections.Generic.SynchronizedCollection<T> 

Example:

 private void RunPowerShell(string[] hosts) { Parallel.ForEach(hosts, (host) => { var remoteComputer = new Uri(String.Format("{0}://{1}:5985/wsman", "http", hosts)); var connection = new WSManConnectionInfo(remoteComputer); var runspace = RunspaceFactory.CreateRunspace(connection); runspace.Open(); for (int ii = 0; ii < powerShellfiles.ToArray().Length; ii++) { using (PowerShell ps = PowerShell.Create()) { ps.Runspace = runspace; //ps.AddScript(powerShellfiles[ii]); ps.AddScript(powerShellfiles[ii]); IAsyncResult async = ps.BeginInvoke(); List<string> aa = ps.EndInvoke(async).SelectMany(x => x.Properties.Where(y => y.Name == "rec_num").Select(z => z.Value.ToString())).ToList(); keysFromhost.AddRange(aa); } }; }); } 
Sign up to request clarification or add additional context in comments.

2 Comments

This works, however for each host that I add the code goes ~20s slower. I want the powershell files to be fired off all at the same time on a given machine.
Well now that I look at your code again. It's kind of wrong you should be adding a callback to your begin invoke and then in the callback you end invoke not begin invoke and end invoke in the same method executing. msdn.microsoft.com/en-us/library/dd182439(v=vs.85).aspx

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.