如何使用C#作为Windows服务中的另一个用户运行非交互式进程?

时间:2016-06-01 00:47:37

标签: c# .net windows winapi windows-services

编辑:我已经创建了一个问题的工作概念验证。见here

我需要以非交互方式运行一个进程,作为使用C#的Windows服务中的另一个用户。我的代码如下所示:

var process = new Process
{
    EnableRaisingEvents = true,
    StartInfo =
    {
        FileName = /* process name */,
        Arguments = /* arguments */,
        Domain = /* domain */,
        UserName = /* username */,
        Password = /* password */,
        CreateNoWindow = true,
        RedirectStandardError = true,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        UseShellExecute = false
    }
};

var error = new StringBuilder();
var errorWaitHandle = new ManualResetEventSlim();
process.ErrorDataReceived += (s, e) =>
{
    if (e.Data != null)
    {
        error.AppendLine(e.Data);
    }
    else
    {
        errorWaitHandle.Set();
    }
};

var output = new StringBuilder();
var outputWaitHandle = new ManualResetEventSlim();
process.OutputDataReceived += (s, e) =>
{
    if (e.Data == /* detect that it's time to write to the input */)
    {
        process.StandardInput.Write(/* write to the input something that will give an output and exit the process */);
        process.StandardInput.Close();
    }
    else if (e.Data != null)
    {
        output.AppendLine(e.Data);
    }
    else
    {
        outputWaitHandle.Set();
    }
};

process.Exited += (s, e) =>
{
    try
    {
        errorWaitHandle.Wait();
        outputWaitHandle.Wait();

        if (error.Length == 0)
        {
            // Do something with 'output.ToString()'.
        }
        else
        {
            // Do something with 'error.ToString()'.
        }
    }
    finally
    {
        process.Dispose();
    }
};

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

当我从控制台应用程序运行它时,它运行没有任何问题。但是,当我从Windows服务运行它时:

如果Windows服务正在以LOCAL_SYSTEM

运行
  • Process.Start()方法抛出异常。

如果Windows服务作为另一个帐户运行:

  • ErrorDataReceived事件会立即收到空数据。
  • OutputDataReceived事件会立即收到空数据。
  • 这个过程并没有真正运行。

如果我删除这些行:

FileName = /* process name */,
Arguments = /* arguments */,
Domain = /* domain */,

在具有LOCAL_SYSTEM个其他帐户的Windows服务上,代码运行时没有任何问题。

经过大量的挖掘后,我学会了以下内容:

  • 从Windows Vista开始,不允许Windows服务进行交互,换句话说,他们无法创建交互式进程(例如创建窗口)。允许的唯一进程是非交互式进程(例如,不创建窗口)。
  • 在没有凭据的情况下调用Process.Start()时,将使用CreateProcess进程创建标志调用Win32 CREATE_NO_WINDOW方法。由于没有创建窗口,因此该过程可以在Windows服务下运行。
  • 使用凭据调用Process.Start()时,将调用Win32 CreateProcessWithLogonW方法。由于此方法不支持CREATE_NO_WINDOW进程创建标志,因此始终会创建一个窗口,因此该进程无法在Windows服务下运行。

理论上,有一个Win32 CreateProcessAsUser方法支持Win32 CreateProcess方法功能,并添加了以另一个用户身份运行它。

  • Win32 CreateProcessAsUser方法是否真正解决了这个问题?
  • 如何在C#中使用此方法,其功能与System.Diagnostics.Process类提供的功能相同(例如标准输入,输出,错误重定向等)。

1 个答案:

答案 0 :(得分:0)

我能够使用this solution运行流程。

(感谢Harry Johnston寻求帮助)。