Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        public static Task <ExecuteScriptResult> ExecuteScriptAssetAsync(ILogSink logger, IOperationExecutionContext context, string fullScriptName, IReadOnlyDictionary <string, RuntimeValue> arguments, IDictionary <string, RuntimeValue> outArguments, bool collectOutput, EventHandler <PSProgressEventArgs> progressUpdateHandler, string successExitCode = null, PsExecutionMode executionMode = PsExecutionMode.Normal)
        {
            var scriptText = GetScriptText(logger, fullScriptName, context);

            if (scriptText == null)
            {
                return(Task.FromResult <ExecuteScriptResult>(null));
            }

            return(ExecuteScriptDirectAsync(logger, context, scriptText, arguments, outArguments, collectOutput, progressUpdateHandler, successExitCode, executionMode, fullScriptName));
        }