/// <summary>
        /// See also here: https://web.archive.org/web/20090720052829/http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server
        /// </summary>
        public async Task StartServerThreadAsync()
        {
            try
            {
                // Start listening for client requests.
                try
                {
                    server.Start();
                }
                catch (HttpListenerException ex)
                {
                    if (ex.ErrorCode == 5) // Access is denied
                    {
                        string msg = string.Format("You need to reserve the URI by running the following command as an administrator: \nnetsh http add urlacl url={0} user={1}\\{2} listen=yes", baseUrl, Environment.GetEnvironmentVariable("USERDOMAIN"), Environment.GetEnvironmentVariable("USERNAME"));
                        PSScriptInvoker.logWarning(msg);
                    }
                    throw ex;
                }

                PSScriptInvoker.logInfo("HttpListener successfully started. Now waiting for requests...");

                while (!isServerStopped)
                {
                    HttpListenerContext context = await server.GetContextAsync().ConfigureAwait(false);

                    Thread handleRequestThread = new Thread(new ParameterizedThreadStart(handleRequest));
                    handleRequestThread.Start(context);
                }
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Unexpected exception:\n" + ex.ToString());
            }
        }
        private Dictionary <String, String> parseUriQuery(string query)
        {
            Dictionary <String, String> queryDict = new Dictionary <String, String>();

            if (!string.IsNullOrEmpty(query))
            {
                string[] queryParams = query.Split('&');
                foreach (string param in queryParams)
                {
                    string[] parts = param.Split('=');
                    if (parts.Length == 1)
                    {
                        string key = Uri.UnescapeDataString(parts[0].Trim(new char[] { '?', ' ' }));
                        queryDict.Add(key, null);
                    }
                    else if (parts.Length == 2)
                    {
                        string key   = Uri.UnescapeDataString(parts[0].Trim(new char[] { '?', ' ' }));
                        string value = Uri.UnescapeDataString(parts[1].Trim());
                        queryDict.Add(key, value);
                    }
                    else
                    {
                        string msg = string.Format("Unable to parse param: {0}", param);
                        PSScriptInvoker.logWarning(msg);
                    }
                }
            }
            return(queryDict);
        }
        private string getRequestBody(HttpListenerRequest request)
        {
            string body = "";

            try
            {
                StreamReader stream = new StreamReader(request.InputStream);
                body = stream.ReadToEnd();
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Exception while reading body input stream: " + ex.ToString());
            }
            return(body);
        }
示例#4
0
        /**
         * See also here: https://www.rabbitmq.com/dotnet-api-guide.html
         */
        public RabbitMqModule(PSScriptExecutor scriptExecutor, string baseUrl, string username, string password, string requestQueue, string responseExchange, string responseRoutingKey)
        {
            this.scriptExecutor     = scriptExecutor;
            this.baseUrl            = baseUrl;
            this.username           = username ?? "";
            this.password           = password ?? "";
            this.requestQueue       = requestQueue;
            this.responseExchange   = responseExchange;
            this.responseRoutingKey = responseRoutingKey;

            try
            {
                rabbitMqFactory = new ConnectionFactory()
                {
                    Uri = new Uri(baseUrl), UserName = username, Password = password, DispatchConsumersAsync = true
                };
                rabbitMqFactory.AutomaticRecoveryEnabled = true;
                rabbitMqConnection         = rabbitMqFactory.CreateConnection();
                rabbitMqChannel            = rabbitMqConnection.CreateModel();
                rabbitMqConsumer           = new AsyncEventingBasicConsumer(rabbitMqChannel);
                rabbitMqConsumer.Received += async(sender, args) =>
                {
                    await Task.Yield(); // Force async execution.

                    Thread handleRequestThread = new Thread(new ParameterizedThreadStart(handleRequest));
                    handleRequestThread.Start(args);
                };

                rabbitMqChannel.BasicConsume(queue: this.requestQueue,
                                             autoAck: false,
                                             consumer: rabbitMqConsumer);

                PSScriptInvoker.logInfo("Message consumer successfully started. Now waiting for requests in queue " + this.requestQueue + "...");
            }
            catch (Exception ex)
            {
                string msg = "Unexpected exception while setting up RabbitMQ connection:\n" + ex.ToString();
                PSScriptInvoker.logError(msg);
            }
        }
 private void writeResponse(HttpListenerResponse response, string responseText, int statusCode)
 {
     try
     {
         response.StatusCode = statusCode;
         if (!string.IsNullOrEmpty(responseText))
         {
             Stream stream = response.OutputStream;
             byte[] msg    = System.Text.Encoding.ASCII.GetBytes(responseText);
             stream.Write(msg, 0, msg.Length);
             stream.Close();
         }
     }
     catch (Exception ex)
     {
         PSScriptInvoker.logError("Exception while writing response stream: " + ex.ToString());
         response.StatusCode = 500;
     }
     finally
     {
         response.Close();
     }
 }
示例#6
0
        private void writeResponse(BasicDeliverEventArgs args, string messageText, int statusCode)
        {
            byte[] messageBytes = Encoding.UTF8.GetBytes(messageText);

            IBasicProperties props = rabbitMqChannel.CreateBasicProperties();

            props.ContentType  = "text/plain";
            props.DeliveryMode = 2;

            props.Headers = args.BasicProperties.Headers;
            props.Headers.Add("statusCode", statusCode);

            lock (rabbitMqChannel)
            {
                try
                {
                    rabbitMqChannel.BasicPublish(responseExchange, responseRoutingKey, props, messageBytes);
                }
                catch (Exception ex)
                {
                    PSScriptInvoker.logError("Unexpected exception while publishing response message:\n" + ex.ToString());
                }
            }
        }
示例#7
0
        private void handleRequest(object input)
        {
            BasicDeliverEventArgs args = (BasicDeliverEventArgs)input;

            try
            {
                IDictionary <string, object> requestHeaders = args.BasicProperties.Headers;
                string executionId     = "";
                string endpoint        = "";
                string paramJsonString = "";
                try
                {
                    requestHeaders.TryGetValue("executionId", out object executionIdBytes);
                    requestHeaders.TryGetValue("endpoint", out object endpointBytes);
                    executionId     = Encoding.UTF8.GetString((byte[])executionIdBytes);
                    endpoint        = Encoding.UTF8.GetString((byte[])endpointBytes);
                    paramJsonString = Encoding.UTF8.GetString(args.Body);
                }
                catch (Exception ex)
                {
                    PSScriptInvoker.logError("Unexpected exception while parsing request segments and query:\n" + ex.ToString());
                    writeResponse(args, "ERROR: URL not valid: " + ex.ToString(), 400);
                    return;
                }

                PSScriptInvoker.logInfo(string.Format("Received RabbitMQ message (deliveryTag: {0}, executionId: {1}, endpoint: {2}):\n{3}", args.DeliveryTag, executionId, endpoint, paramJsonString));

                // Get parameters
                Dictionary <String, String> parameters = new Dictionary <String, String>();
                if (!String.IsNullOrEmpty(paramJsonString))
                {
                    parameters = JsonConvert.DeserializeObject <Dictionary <String, String> >(paramJsonString);
                }

                // Execute the appropriate script.
                string[] segments = endpoint.Split('/');
                Dictionary <String, String> scriptOutput = scriptExecutor.executePSScriptByHttpSegments(segments, parameters);

                // Get output variables
                scriptOutput.TryGetValue("exitCode", out string exitCode);
                scriptOutput.TryGetValue("result", out string result);

                if (exitCode == "0")
                {
                    if (string.IsNullOrEmpty(result))
                    {
                        writeResponse(args, result, 204);
                    }
                    else
                    {
                        writeResponse(args, result, 200);
                    }
                }
                else
                {
                    writeResponse(args, result, 500);
                }
            }
            catch (JsonReaderException jsonEx)
            {
                PSScriptInvoker.logError("Unable to read input JSON:\n" + jsonEx.ToString());
                writeResponse(args, jsonEx.ToString(), 400);
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Unexpected exception while processing message:\n" + ex.ToString());
                writeResponse(args, ex.ToString(), 500);
            }

            // Acknowledge request if response was written successfully.
            lock (rabbitMqChannel)
            {
                try
                {
                    rabbitMqChannel.BasicAck(deliveryTag: args.DeliveryTag, multiple: false);
                }
                catch (Exception ex)
                {
                    PSScriptInvoker.logError("Unexpected exception while acknowledging request message:\n" + ex.ToString());
                }
            }
        }
        private void handleRequest(object input)
        {
            HttpListenerContext context = (HttpListenerContext)input;

            // A request was arrived. Get the object.
            HttpListenerRequest request = context.Request;

            try
            {
                string receivedAuthToken = request.Headers.Get("Authorization");
                if (!string.IsNullOrEmpty(authToken) && string.IsNullOrEmpty(receivedAuthToken))
                {
                    writeResponse(context.Response, "ERROR: Authorization header missing!", 401);
                }
                else
                {
                    if (!string.IsNullOrEmpty(authToken) && !receivedAuthToken.Equals(authToken))
                    {
                        PSScriptInvoker.logError(string.Format("Wrong auth token received: '{0}'. Do nothing and return 403 (access denied).", receivedAuthToken));
                        writeResponse(context.Response, "ERROR: Wrong auth token. Access denied!", 403);
                    }
                    else
                    {
                        // Get the URI segments
                        string[] segments = request.Url.Segments;
                        // See here for more information about URI components: https://tools.ietf.org/html/rfc3986#section-3

                        // Get parameters
                        Dictionary <String, String> parameters;
                        string body = "";
                        if (request.HasEntityBody)
                        {
                            body       = getRequestBody(request);
                            parameters = JsonConvert.DeserializeObject <Dictionary <String, String> >(body);
                        }
                        else
                        {
                            string query = request.Url.Query;
                            try
                            {
                                // Parse the query string variables into a dictionary.
                                parameters = parseUriQuery(query);
                            }
                            catch (Exception ex)
                            {
                                PSScriptInvoker.logError("Unexpected exception while parsing request segments and query:\n" + ex.ToString());
                                writeResponse(context.Response, "ERROR: URL not valid: " + request.Url.ToString(), 400);
                                return;
                            }
                        }

                        // Execute the appropriate script.
                        Dictionary <String, String> scriptOutput = scriptExecutor.executePSScriptByHttpSegments(segments, parameters);

                        // Get output variables
                        scriptOutput.TryGetValue("exitCode", out string exitCode);
                        scriptOutput.TryGetValue("result", out string result);

                        if (exitCode == "0")
                        {
                            if (string.IsNullOrEmpty(result))
                            {
                                writeResponse(context.Response, result, 204);
                            }
                            else
                            {
                                writeResponse(context.Response, result, 200);
                            }
                        }
                        else
                        {
                            writeResponse(context.Response, result, 500);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Unexpected exception while processing request:\n" + ex.ToString());
                writeResponse(context.Response, ex.ToString(), 500);
            }
        }
示例#9
0
        public PSScriptExecutor(string pathToScripts, string[] modulesToLoad, string psExecutionPolicy, string psOutputDelimiter)
        {
            this.pathToScripts     = pathToScripts;
            this.modulesToLoad     = modulesToLoad;
            this.psExecutionPolicy = psExecutionPolicy;
            this.psOutputDelimiter = psOutputDelimiter;

            // Initialise PowerShell Runspace and preload necessary modules.
            // See here: http://stackoverflow.com/a/17071164
            // See here: http://nivot.org/blog/post/2010/05/03/PowerShell20DeveloperEssentials1InitializingARunspaceWithAModule
            InitialSessionState initialSession = InitialSessionState.CreateDefault2();

            if (modulesToLoad != null && modulesToLoad.Length > 0)
            {
                initialSession.ImportPSModule(modulesToLoad);
            }

            if (psExecutionPolicy != "None")
            {
                PSScriptInvoker.logInfo("Setting custom PowerShell Execution Policy: " + psExecutionPolicy);
                switch (psExecutionPolicy)
                {
                case "AllSigned":
                    initialSession.ExecutionPolicy = ExecutionPolicy.AllSigned;
                    break;

                case "Bypass":
                    initialSession.ExecutionPolicy = ExecutionPolicy.Bypass;
                    break;

                case "RemoteSigned":
                    initialSession.ExecutionPolicy = ExecutionPolicy.RemoteSigned;
                    break;

                case "Restricted":
                    initialSession.ExecutionPolicy = ExecutionPolicy.Restricted;
                    break;

                case "Undefined":
                    initialSession.ExecutionPolicy = ExecutionPolicy.Undefined;
                    break;

                case "Unrestricted":
                    initialSession.ExecutionPolicy = ExecutionPolicy.Unrestricted;
                    break;

                default:
                    PSScriptInvoker.logWarning("Given custom PowerShell Execution Policy is unknown: " + psExecutionPolicy + ". Only one of the following custom policies is allowed: AllSigned, Bypass, RemoteSigned, Restricted, Undefined, Unrestricted. Set to policy 'Default'.");
                    initialSession.ExecutionPolicy = ExecutionPolicy.Default;
                    break;
                }
            }

            // This loads the InitialStateSession for all instances
            // Note you can set the minimum and maximum number of runspaces as well
            // Note that without setting the minimum and maximum number of runspaces, it will use 1 as default for both:
            // https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.runspaces.runspacefactory.createrunspacepool?view=powershellsdk-1.1.0
            // See here: https://stackoverflow.com/a/24358855
            runspacePool = RunspaceFactory.CreateRunspacePool(initialSession);
            runspacePool.SetMinRunspaces(MIN_RUNSPACES);
            runspacePool.SetMaxRunspaces(int.MaxValue);
            runspacePool.ThreadOptions = PSThreadOptions.UseNewThread;
            runspacePool.Open();
        }
示例#10
0
        /**
         * See also here: http://stackoverflow.com/a/527644
         */
        public Dictionary <String, String> executePSScript(string script)
        {
            string msg = "Executing PowerShell script '" + script + "'...";

            PSScriptInvoker.logInfo(msg);

            string exitCode = "";
            string result   = "";
            Dictionary <String, String> output  = new Dictionary <String, String>();
            Collection <PSObject>       results = new Collection <PSObject>();

            try
            {
                PowerShell ps = PowerShell.Create();
                ps.AddScript(script);
                ps.RunspacePool = runspacePool;
                results         = ps.Invoke();

                if (ps.HadErrors)
                {
                    exitCode = "1";
                    results.Add(new PSObject((object)ps.Streams.Error));
                }
                else
                {
                    exitCode = "0";
                }
            }
            catch (ActionPreferenceStopException ex)
            {
                Exception psEx = null;
                if (ex.ErrorRecord != null && ex.ErrorRecord.Exception != null)
                {
                    psEx = ex.ErrorRecord.Exception;
                }
                else
                {
                    psEx = ex;
                }
                PSScriptInvoker.logError("Exception occurred in PowerShell script '" + script + "':\n" + psEx.ToString());
                results.Add(new PSObject((object)psEx.Message));
                exitCode = "1";
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Unexpected exception while invoking PowerShell script '" + script + "':\n" + ex.ToString());
                results.Add(new PSObject((object)ex.Message));
                exitCode = "1";
            }

            try
            {
                for (int i = 0; i < results.Count; i++)
                {
                    result += (results[i] != null ? results[i].ToString() : "null");
                    if (i < results.Count - 1) // Avoid delimiter at the end.
                    {
                        result += psOutputDelimiter;
                    }
                }
            }
            catch (Exception ex)
            {
                PSScriptInvoker.logError("Failed to get result (" + results.Count + " items) of PowerShell script '" + script + "':\n" + ex.ToString());
            }

            PSScriptInvoker.logInfo(string.Format("Executed script was: {0}. Exit code: {1}, output:\n{2}", script, exitCode, result));

            output.Add("exitCode", exitCode);
            output.Add("result", result);
            return(output);
        }