Jake Steffen
Jake Steffen

Reputation: 415

Run a list of PowerShell scripts on multiple machines all at once

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.

Upvotes: 0

Views: 867

Answers (1)

JQluv
JQluv

Reputation: 242

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);
                    }

                };
            });
        }

Upvotes: 2

Related Questions