/// <exception cref="InvalidOperationException"></exception>
        /// <exception cref="FileNotFoundException"></exception>
        private void StartImpl()
        {
            if (State != NonInteractiveProcessState.Ready)
            {
                throw new InvalidOperationException("NonInteractiveProcess.Start() cannot be called more than once.");
            }

            if (!File.Exists(ExePath))
            {
                throw new FileNotFoundException(string.Format("Unable to Start NonInteractiveProcess: File \"{0}\" does not exist", ExePath));
            }

            using (var process = CreateProcess())
            {
                using (var jobObject = _jobObjectManager.CreateJobObject())
                {
                    process.StartInfo.FileName  = ExePath;
                    process.StartInfo.Arguments = Arguments.ToString();
                    process.EnableRaisingEvents = true;
                    process.Exited += ProcessExitedAsync;

                    OnBeforeStart(process);

                    if (BeforeStart != null)
                    {
                        BeforeStart(this, EventArgs.Empty);
                    }

                    process.OutputDataReceived += (sender, args) => HandleStdOut(args.Data);
                    process.ErrorDataReceived  += (sender, args) => HandleStdErr(args.Data);

                    Logger.Info(FullCommand);

                    process.Start();

                    _hasStarted = true;

                    Id    = process.Id;
                    Name  = process.ProcessName;
                    State = NonInteractiveProcessState.Running;

                    if (_jobObjectManager.IsAssignedToJob(process))
                    {
                        Logger.Warn("WARNING: Child process already belongs to a Job Object.  If the parent process crashes, the child process will continue to run in the background until it finishes executing.");
                    }
                    else
                    {
                        jobObject.Assign(process);
                        jobObject.KillOnClose();
                    }

                    _stopwatch.Start();

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

                    Logger.InfoFormat("Waiting for process \"{0}\" w/ PID = {1} to exit...", ExePath, Id);

                    OnStart(process);

                    process.WaitForExit();

                    _hasExited = true;

                    Logger.InfoFormat("Process \"{0}\" w/ PID = {1} exited", ExePath, Id);

                    ExitCode = process.ExitCode;
                }
            }
        }