/// <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); }
/** * 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(); } }
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()); } } }
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); } }
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(); }
/** * 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); }