public virtual int Execute(ProcessStartInfo startInfo, CancellationToken cancellationToken, out string stdOut)
        {
            var outBuffer = new StringBuilder();

            cancellationToken.ThrowIfCancellationRequested();

            var process = Process.Start(startInfo);

            if (process == null)
            {
                throw PluginException.CreateNotStartedMessage(Path);
            }

            process.OutputDataReceived += (object o, DataReceivedEventArgs e) => { outBuffer.AppendLine(e.Data); };

            // Trace and error information may be written to standard error by the provider.
            // It should be logged at the Information level so it will appear if Verbosity >= Normal.
            process.ErrorDataReceived += (object o, DataReceivedEventArgs e) =>
            {
                if (!string.IsNullOrWhiteSpace(e?.Data))
                {
                    // This is a workaround for mono issue: https://github.com/NuGet/Home/issues/4004
                    if (!process.HasExited)
                    {
                        _logger.LogInformation($"{process.ProcessName}: {e.Data}");
                    }
                }
            };

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

            using (cancellationToken.Register(() => Kill(process)))
            {
                if (!process.WaitForExit(TimeoutSeconds * 1000))
                {
                    Kill(process);
                    throw PluginException.CreateTimeoutMessage(Path, TimeoutSeconds);
                }
                // Give time for the Async event handlers to finish by calling WaitForExit again.
                // if the first one succeeded
                // Note: Read remarks from https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx
                // for reason.
                process.WaitForExit();
            }

            process.CancelErrorRead();
            process.CancelOutputRead();
            cancellationToken.ThrowIfCancellationRequested();

            stdOut = outBuffer.ToString();
            return(process.ExitCode);
        }
        public virtual PluginCredentialResponse Execute(PluginCredentialRequest request,
                                                        CancellationToken cancellationToken)
        {
            var stdOut         = new StringBuilder();
            var stdError       = new StringBuilder();
            var argumentString =
                $"-uri {request.Uri}"
                + (request.IsRetry ? " -isRetry" : string.Empty)
                + (request.NonInteractive ? " -nonInteractive" : string.Empty);

            var startInfo = new ProcessStartInfo
            {
                FileName               = Path,
                Arguments              = argumentString,
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardOutput = true,
                RedirectStandardError  = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding  = Encoding.UTF8,
                ErrorDialog            = false
            };

            cancellationToken.ThrowIfCancellationRequested();

            var process = Process.Start(startInfo);

            if (process == null)
            {
                throw PluginException.CreateNotStartedMessage(Path);
            }

            process.OutputDataReceived += (object o, DataReceivedEventArgs e) => { stdOut.AppendLine(e.Data); };
            process.ErrorDataReceived  += (object o, DataReceivedEventArgs e) => { stdError.AppendLine(e.Data); };
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            using (cancellationToken.Register(() => Kill(process)))
            {
                if (!process.WaitForExit(TimeoutSeconds * 1000))
                {
                    Kill(process);
                    throw PluginException.CreateTimeoutMessage(Path, TimeoutSeconds);
                }
                // Give time for the Async event handlers to finish by calling WaitForExit again.
                // if the first one succeeded
                // Note: Read remarks from https://msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx
                // for reason.
                process.WaitForExit();
            }

            process.CancelErrorRead();
            process.CancelOutputRead();

            var exitCode = process.ExitCode;

            if (Enum.GetValues(typeof(PluginCredentialResponseExitCode)).Cast <int>().Contains(exitCode))
            {
                var status       = (PluginCredentialResponseExitCode)exitCode;
                var responseJson = stdOut.ToString();

                PluginCredentialResponse credentialResponse;

                try
                {
                    credentialResponse = JsonConvert.DeserializeObject <PluginCredentialResponse>(responseJson);
                }
                catch (Exception)
                {
                    throw PluginException.CreatePayloadExceptionMessage(Path, status, responseJson);
                }

                switch (status)
                {
                case PluginCredentialResponseExitCode.Success:
                    if (!credentialResponse.IsValid)
                    {
                        throw PluginException.CreatePayloadExceptionMessage(Path, status, responseJson);
                    }

                    return(credentialResponse);

                case PluginCredentialResponseExitCode.ProviderNotApplicable:
                    credentialResponse.Username = null;
                    credentialResponse.Password = null;

                    return(credentialResponse);

                case PluginCredentialResponseExitCode.Failure:
                    throw PluginException.CreateAbortMessage(Path, credentialResponse.Message);
                }
            }

            throw PluginException.CreateWrappedExceptionMessage(
                      Path,
                      exitCode,
                      stdOut.ToString(),
                      stdError.ToString());
        }