public static bool TryParse(TextReader scriptText, out PowerShellScriptInfo info) { try { info = Parse(scriptText); return(true); } catch { info = null; return(false); } }
public static async Task <ExecuteScriptResult> ExecuteScriptDirectAsync(ILogSink logger, IOperationExecutionContext context, string scriptText, IReadOnlyDictionary <string, RuntimeValue> arguments, IDictionary <string, RuntimeValue> outArguments, bool collectOutput, EventHandler <PSProgressEventArgs> progressUpdateHandler, string successExitCode = null, PsExecutionMode executionMode = PsExecutionMode.Normal, string fullScriptName = null) { var variables = new Dictionary <string, RuntimeValue>(); var parameters = new Dictionary <string, RuntimeValue>(); if (PowerShellScriptInfo.TryParse(new StringReader(scriptText), out var scriptInfo)) { foreach (var var in arguments) { var value = var.Value; var param = scriptInfo.Parameters.FirstOrDefault(p => string.Equals(p.Name, var.Key, StringComparison.OrdinalIgnoreCase)); if (param != null && param.IsBooleanOrSwitch) { value = value.AsBoolean() ?? false; } if (param != null) { parameters[param.Name] = value; } else { variables[var.Key] = value; } } if (executionMode == PsExecutionMode.Collect || executionMode == PsExecutionMode.Configure) { if (scriptInfo.ConfigParameters?.Count > 0) { var uniqueConfigKeys = new HashSet <string>(StringComparer.OrdinalIgnoreCase); void setOutputVariable(string oe) { if (oe?.StartsWith("$") == true) { outArguments[oe.TrimStart('$')] = string.Empty; } } foreach (var configParam in scriptInfo.ConfigParameters) { var uniqueKey = $"{configParam.ConfigType},{configParam.ConfigKey}"; if (!uniqueConfigKeys.Add(uniqueKey)) { logger.LogWarning( "There are duplicate configuration type/key (AHCONFIGKEY, AHCONFIGTYPE) values specified in the script. " + $"Only the first set ({uniqueKey}) will be used." ); continue; } setOutputVariable(configParam.ConfigType); setOutputVariable(configParam.ConfigKey); setOutputVariable(configParam.DesiredValue); setOutputVariable(configParam.CurrentValue); setOutputVariable(configParam.ValueDrifted); } } if (!string.IsNullOrWhiteSpace(scriptInfo.ExecutionModeVariableName)) { variables[scriptInfo.ExecutionModeVariableName.TrimStart('$')] = executionMode.ToString(); } } } else { variables = arguments.ToDictionary(a => a.Key, a => a.Value); } if (executionMode == PsExecutionMode.Configure && string.IsNullOrEmpty(scriptInfo?.ExecutionModeVariableName)) { logger.LogError( ".AHEXECMODE additional help was not detected. When using PSEnsure to remediate drift, you must specify the name of " + "a variable that will capture \"Collect\" or \"Configure\" in the .AHEXECMODE help." ); return(null); } var jobRunner = context.Agent.GetService <IRemoteJobExecuter>(); var job = new ExecutePowerShellJob { ScriptText = scriptText, DebugLogging = false, VerboseLogging = true, CollectOutput = collectOutput, LogOutput = !collectOutput, Variables = variables, Parameters = parameters, OutVariables = outArguments.Keys.ToArray(), WorkingDirectory = context.WorkingDirectory }; job.MessageLogged += (s, e) => logger.Log(e.Level, e.Message); if (progressUpdateHandler != null) { job.ProgressUpdate += progressUpdateHandler; } var result = (ExecutePowerShellJob.Result) await jobRunner.ExecuteJobAsync(job, context.CancellationToken); LogExit(logger, result.ExitCode, successExitCode); foreach (var var in result.OutVariables) { outArguments[var.Key] = var.Value; } var data = new ExecuteScriptResult { ExitCode = result.ExitCode, Output = result.Output, OutVariables = result.OutVariables }; if (executionMode == PsExecutionMode.Collect || executionMode == PsExecutionMode.Configure) { var configInfos = new List <ExecuteScriptResultConfigurationInfo>(); if (scriptInfo?.ConfigParameters?.Count > 0) { var uniqueConfigKeys = new HashSet <string>(StringComparer.OrdinalIgnoreCase); var usedOutput = false; foreach (var param in scriptInfo.ConfigParameters) { var configType = getOutputExpressionValue(param.ConfigType, "PSConfig").AsString(); var configKey = getOutputExpressionValue(param.ConfigKey, new RuntimeValue(fullScriptName)).AsString(); var uniqueKey = $"{configType},{configKey}"; if (!uniqueConfigKeys.Add(uniqueKey)) { logger.LogWarning( "This script returned multiple configuration items, but each item does have a unique type/key (AHCONFIGKEY, AHCONFIGTYPE)." + $"Only the first item with the type/key ({uniqueKey}) will be recorded." ); continue; } if (string.IsNullOrEmpty(param.CurrentValue)) { if (usedOutput) { logger.LogWarning( "Another configuration item is already using the script output for the current value; when multiple types are returned, " + "a AHCURRENTVALUE help should be used." ); continue; } usedOutput = true; } configInfos.Add(new ExecuteScriptResultConfigurationInfo { ConfigType = configType, ConfigKey = configKey, DesiredConfigValue = getOutputExpressionValue(param.DesiredValue, new RuntimeValue(true)), CurrentConfigValue = getOutputExpressionValue(param.CurrentValue, result.Output.FirstOrDefault()), DriftDetected = getOutputExpressionValue(param.ValueDrifted, null).AsBoolean() }); } RuntimeValue getOutputExpressionValue(string oe, RuntimeValue defaultValue) { if (string.IsNullOrEmpty(oe)) { return(defaultValue); } if (oe.StartsWith("$") && result.OutVariables.TryGetValue(oe.Substring(1), out var oval)) { result.OutVariables.Remove(oe); return(oval); } return(new RuntimeValue(oe)); } } else { logger.LogDebug("Script did not define any additional help configuration parameters, so the default values will be used."); configInfos.Add(new ExecuteScriptResultConfigurationInfo { ConfigType = "PSConfig", ConfigKey = fullScriptName, DesiredConfigValue = new RuntimeValue(true), CurrentConfigValue = result.Output.FirstOrDefault() }); } data.Configuration = configInfos; } return(data); }