user4520334
user4520334

Reputation:

Remote execute Powershell script on machines in a given IP range

I'm basically trying to create a console application which executes a given script on a remote machines within a given IP range and stores the results.

This is my code so far but something is going wrong when I try to create a runspace with the WSManConnectionInfo object as arg.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Security;

namespace GetSysInfo
{
    class Program
    {
        private static string outPath;

        static void Main(string[] args)
        {
            //get script path
            Console.WriteLine("Enter full path to script.");
            string path = Convert.ToString(Console.ReadLine());

            //get IP range
            Console.WriteLine("Input start IPv4.");
            IPAddress sIP = IPAddress.Parse(Console.ReadLine().ToString());

            Console.WriteLine("Input end IPv4.");
            IPAddress eIP = IPAddress.Parse(Console.ReadLine().ToString());

            //get list of IPs in range
            RangeFinder rf = new RangeFinder();
            List<string> IPrange = rf.GetIPRangeList(sIP, eIP);

            //run script
            foreach (var IP in IPrange)
            {
                try
                {
                    RunScriptRemote(LoadScript(path), IP);
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occured" +     Environment.NewLine + e.Message);
                }
            }
        }

        //script executer
        private static void RunScriptRemote(string script, string address)
        {
            Console.WriteLine("Enter username.");
            String username = Console.ReadLine();

            Console.WriteLine("Enter password.");

            ConsoleKeyInfo key;
            SecureString pass = new SecureString();

            do
            {
                key = Console.ReadKey(true);

                if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
                {
                    pass.AppendChar(key.KeyChar);
                    Console.Write("*");
                }
                else
                {
                    if (key.Key == ConsoleKey.Backspace && pass.Length > 0)
                    {
                        pass.RemoveAt(pass.Length);
                        Console.Write("\b \b");
                    }
                    else if (key.Key == ConsoleKey.Enter && pass.Length > 0)
                    {
                        Console.Write(Environment.NewLine);
                        pass.MakeReadOnly();
                    }
                }
            }
            while (key.Key != ConsoleKey.Enter);


            PSCredential credential = new PSCredential(username, pass);
            WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("http://" + address + ":5985/wsman"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential);
            connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Negotiate;
            connectionInfo.EnableNetworkAccess = true;

            Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);//point of crash
            runspace.Open();

            //set path to save results
            Console.WriteLine("Enter full path to save results. Must be a directory.\nThis can be a local path or a network path.");
            Console.WriteLine("In case of a network path the results will be merged automatically");
            outPath = Convert.ToString(Console.ReadLine());

            runspace.SessionStateProxy.SetVariable("filepath", outPath);

            using (PowerShell ps = PowerShell.Create())
            {
                ps.Runspace = runspace;
                ps.AddScript(script);
                ps.Invoke();
            } 

            //Pipeline pipeline = runspace.CreatePipeline();
            //pipeline.Commands.AddScript(script);

            //pipeline.Invoke();

            runspace.Close();
        }

        //script loader
        private static string LoadScript(string filename)
        {
            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    StringBuilder fileContents = new StringBuilder();

                    string curLine;

                    while ((curLine = sr.ReadLine()) != null)
                    {
                        fileContents.Append(curLine + Environment.NewLine);
                    }

                    return fileContents.ToString();
                }
            }
            catch (Exception e)
            {
                return e.Message;
            }

        }
    }

    public class RangeFinder
    {
        public IEnumerable<string> GetIPRange(IPAddress startIP,
            IPAddress endIP)
        {
            uint sIP = ipToUint(startIP.GetAddressBytes());
            uint eIP = ipToUint(endIP.GetAddressBytes());
            while (sIP <= eIP)
            {
                yield return new IPAddress(reverseBytesArray(sIP)).ToString();
                sIP++;
            }
        }

        public List<string> GetIPRangeList(IPAddress startIP,
             IPAddress endIP)
        {
            uint sIP = ipToUint(startIP.GetAddressBytes());
            uint eIP = ipToUint(endIP.GetAddressBytes());
            List<string> IPlist = new List<string>();
            while (sIP <= eIP)
            {
                IPlist.Add(new IPAddress(reverseBytesArray(sIP)).ToString());
                sIP++;
            }

            return IPlist;
        }


        //reverse byte order in array
        protected uint reverseBytesArray(uint ip)
        {
            byte[] bytes = BitConverter.GetBytes(ip);
            bytes = bytes.Reverse().ToArray();
            return (uint)BitConverter.ToInt32(bytes, 0);
        }


        //Convert bytes array to 32 bit long value
        protected uint ipToUint(byte[] ipBytes)
        {
            ByteConverter bConvert = new ByteConverter();
            uint ipUint = 0;

            int shift = 24;
            foreach (byte b in ipBytes)
            {
                if (ipUint == 0)
                {
                    ipUint = (uint)bConvert.ConvertTo(b, typeof(uint)) <<   shift;
                    shift -= 8;
                    continue;
                }

                if (shift >= 8)
                    ipUint += (uint)bConvert.ConvertTo(b, typeof(uint)) <<   shift;
                else
                    ipUint += (uint)bConvert.ConvertTo(b, typeof(uint));

                shift -= 8;
            }

            return ipUint;
        }
    }
}

I get the following error when trying to run: Common Language Runtime detected an invalid program.

I tried creating a new solution as Google suggested but it's obviously going wrong when creating the runspace.

I'm out of idea's and sources for help, so I'm reaching out to the Stackoverflow community.

Thanks in advance, X3ntr

EDIT: I tried cleaning my solution, manually deleting any pbd's, changed the target CPU, turned off code optimalization, allowed unsafe code, rebuilding, creating a new solution,... as suggested in this post.

Upvotes: 2

Views: 900

Answers (1)

user4520334
user4520334

Reputation:

I followed the advice from this answer: I added a reference to C:\windows\assembly\GAC_MSIL\System.Management.Automation and then ran this command in an elevated powershell: Copy ([PSObject].Assembly.Location) C:\

Upvotes: 1

Related Questions