我有一个用 C# 和 .NET 3.5 开发的 Windows 服务,用于在我们的 3 个域中执行各种管理任务。我在每个域中都有一个管理员帐户,该帐户具有此服务正在执行的必要权限/权限。
对于所有 AD 交互,我可以使用域的正确用户名/密码绑定到 AD,一切都很好。但是,我现在需要启动一个外部进程(robocopy)来执行一些工作,我在 .NET 3.5 中找不到任何代码示例来执行此操作。
我需要做的是在隐藏窗口中使用备用凭据启动 robocopy,捕获标准输出以便我记录实际完成的操作,并捕获退出代码以便判断它是否成功。
我从K. Scott Allen 的博客中找到了一些旧的 .NET 1.1 代码(请参阅最后几条评论以获得良好的代码清单),它扩展了 System.Diagnostics.Process 对象并调用 Win32 API 函数 CreateProcessAsUserW。但是,由于 .NET 2.0 中的一些 API 更改,该代码不起作用。使用引用博客上最后一条评论中的代码片段,它使用反射调用 Process 对象的私有 SetProcessHandle 函数,当我尝试与进程交互(杀死它或获取退出代码)时,会导致访问被拒绝错误。
有没有人有一个很好的例子来说明如何做到这一点?
编辑:内置的 .NET Process 和 ProcessStartInfo API 确实允许您指定备用凭据,但是当您这样做时,它希望创建一个可见窗口(即使您指定 CreateNoWindow 或 WindowStyle Hidden),该窗口在作为 Windows 服务运行时会失败。因此,这些不是此应用程序的选项。模拟也不起作用,因为在启动外部进程时,它使用父进程的凭据,而不是模拟的凭据。
解决方案:正如 Reed 在下面指出的,使用 Win32 API 函数之一的 P/Invoke 应该允许您实现这一点。我最终使用了一个名为 RunProcess 的旧的免费软件 NT4 实用程序,它允许您在命令行上指定用户名/密码,从而采用了稍微不同的路线。它在 Vista 和 2k3 上工作,并且在由作为本地系统运行的 Windows 服务启动时也能正常工作。