/// <summary>
        /// Runs the specified executable and returns a boolean indicating success or failure
        /// </summary>
        /// <remarks>The standard and error output will be streamed to the logger. Child processes do not inherit the env variables from the parent automatically</remarks>
        public bool Execute(ProcessScannerArguments runnerArgs)
        {
            if (runnerArgs == null)
            {
                throw new ArgumentNullException("runnerArgs");
            }
            Debug.Assert(!string.IsNullOrWhiteSpace(runnerArgs.ExeName), "Process runner exe name should not be null/empty");
            Debug.Assert(runnerArgs.Logger != null, "Process runner logger should not be null/empty");

            this.outputLogger = runnerArgs.Logger;

            if (!File.Exists(runnerArgs.ExeName))
            {
                this.outputLogger.LogError(Resources.ERROR_ProcessRunner_ExeNotFound, runnerArgs.ExeName);
                this.ExitCode = ErrorCode;
                return(false);
            }

            ProcessStartInfo psi = new ProcessStartInfo()
            {
                FileName = runnerArgs.ExeName,
                RedirectStandardError  = true,
                RedirectStandardOutput = true,
                UseShellExecute        = false, // required if we want to capture the error output
                ErrorDialog            = false,
                CreateNoWindow         = true,
                Arguments        = runnerArgs.GetEscapedArguments(),
                WorkingDirectory = runnerArgs.WorkingDirectory
            };

            SetEnvironmentVariables(psi, runnerArgs.EnvironmentVariables, runnerArgs.Logger);

            bool succeeded;

            using (var process = new Process())
            {
                process.StartInfo           = psi;
                process.ErrorDataReceived  += OnErrorDataReceived;
                process.OutputDataReceived += OnOutputDataReceived;

                process.Start();
                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                // Warning: do not log the raw command line args as they
                // may contain sensitive data
                this.outputLogger.LogDebug(Resources.MSG_ExecutingFile,
                                           runnerArgs.ExeName,
                                           runnerArgs.AsLogText(),
                                           runnerArgs.WorkingDirectory,
                                           runnerArgs.TimeoutInMilliseconds,
                                           process.Id);

                succeeded = process.WaitForExit(runnerArgs.TimeoutInMilliseconds);
                if (succeeded)
                {
                    process.WaitForExit(); // Give any asynchronous events the chance to complete
                }

                // false means we asked the process to stop but it didn't.
                // true: we might still have timed out, but the process ended when we asked it to
                if (succeeded)
                {
                    this.outputLogger.LogDebug(Resources.MSG_ExecutionExitCode, process.ExitCode);
                    this.ExitCode = process.ExitCode;
                }
                else
                {
                    this.ExitCode = ErrorCode;

                    try
                    {
                        process.Kill();
                        this.outputLogger.LogWarning(Resources.WARN_ExecutionTimedOutKilled, runnerArgs.TimeoutInMilliseconds, runnerArgs.ExeName);
                    }
                    catch
                    {
                        this.outputLogger.LogWarning(Resources.WARN_ExecutionTimedOutNotKilled, runnerArgs.TimeoutInMilliseconds, runnerArgs.ExeName);
                    }
                }

                succeeded = succeeded && (this.ExitCode == 0);
            }

            return(succeeded);
        }
 /// <summary>
 /// Returns whether the property contains any sensitive data
 /// </summary>
 public bool ContainsSensitiveData()
 {
     return(ProcessScannerArguments.ContainsSensitiveData(this.Id) || ProcessScannerArguments.ContainsSensitiveData(this.Value));
 }