C# 和 .NET 3.5 - 如何使用不同的凭据、隐藏的窗口并能够捕获标准输出和退出代码来启动进程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/643723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# and .NET 3.5 - How to launch a process using different credentials, with a hidden window, and being able to capture standard output and exit code?
提问by David Archer
I have a Windows Service developed in C# and .NET 3.5 to perform various administrative tasks throughout our 3 domains. I've got an admin account in each domain that has the necessary rights/permissions for what this service is doing.
我有一个用 C# 和 .NET 3.5 开发的 Windows 服务,用于在我们的 3 个域中执行各种管理任务。我在每个域中都有一个管理员帐户,该帐户具有此服务正在执行的操作所需的权利/权限。
For all the AD interactions, I can bind to AD using the correct username/password for the domain and all is good. However, I have a need now to launch an external process (robocopy) to perform some work and I cannot find any code examples anywhere for doing this in .NET 3.5.
对于所有 AD 交互,我可以使用域的正确用户名/密码绑定到 AD,一切都很好。但是,我现在需要启动一个外部进程 (robocopy) 来执行一些工作,而且我在 .NET 3.5 中找不到任何用于执行此操作的代码示例。
What I need to do is launch robocopy using alternate credentials in a hidden window, capture the standard output so I have a log of what was actually done, and capture the exit code so I can tell if it was successful.
我需要做的是在隐藏窗口中使用备用凭据启动 robocopy,捕获标准输出以便我记录实际完成的操作,并捕获退出代码以便我可以判断它是否成功。
I found some old .NET 1.1 code from K. Scott Allen's blog(see the last few comments for a good code listing) that extends the System.Diagnostics.Process object and calls the Win32 API function CreateProcessAsUserW. However, the code doesn't work due to some API changes in .NET 2.0. Using the code snippet from the last comment on the referenced blog where it is using reflection to call the private SetProcessHandle function of the Process object causes Access Denied errors when I try to interact with the process (to kill it or get exit code).
我从K. Scott Allen 的博客中找到了一些旧的 .NET 1.1 代码(请参阅最后几条评论以获得一个好的代码清单),它扩展了 System.Diagnostics.Process 对象并调用了 Win32 API 函数 CreateProcessAsUserW。但是,由于 .NET 2.0 中的某些 API 更改,该代码不起作用。使用引用博客上最后一条评论中的代码片段,其中使用反射调用 Process 对象的私有 SetProcessHandle 函数,当我尝试与进程交互时(杀死它或获取退出代码)会导致拒绝访问错误。
Does anyone have a good example of how to accomplish this?
有没有人有一个很好的例子来说明如何做到这一点?
EDIT: The built-in .NET Process and ProcessStartInfo API does allow you to specify alternate credentials but when you do, it wants to create a visible window (even if you specify CreateNoWindow or WindowStyle Hidden) which fails when running as a Windows Service. So those are not an option for this application. Impersonation doesn't work either since when the external process is launched, it uses the credentials of the parent process, not the impersonated credentials.
编辑:内置的 .NET Process 和 ProcessStartInfo API 确实允许您指定备用凭据,但是当您这样做时,它想要创建一个可见窗口(即使您指定 CreateNoWindow 或 WindowStyle Hidden),该窗口在作为 Windows 服务运行时会失败。因此,这些不是此应用程序的选项。模拟也不起作用,因为在启动外部进程时,它使用父进程的凭据,而不是模拟的凭据。
SOLUTION: As Reed pointed out below, P/Invoke using one of the Win32 API functions should allow you to make this happen. I ended up going a slightly different route using an old freeware NT4 utility called RunProcessthat allows you to specify a username/password on the command line. It worked on Vista and 2k3 and also worked correctly when launched by a windows service running as Local System.
解决方案:正如 Reed 在下面指出的,使用 Win32 API 函数之一的 P/Invoke 应该允许您实现这一点。我最终使用了一个名为 RunProcess的旧免费软件 NT4 实用程序,该实用程序允许您在命令行上指定用户名/密码。它适用于 Vista 和 2k3,并且在由作为本地系统运行的 Windows 服务启动时也能正常工作。
采纳答案by Reed Copsey
I think you want to look at:
我想你想看看:
That provides a .NET only way to start a process under a different user with different credentials. No more need for the Win32 API.
这提供了一种在具有不同凭据的不同用户下启动进程的唯一方法。不再需要 Win32 API。
--- EDIT ---
- - 编辑 - -
Other alternatives might be to use the P/Invoke as specified here(look at the note at the bottom first) or more likely, using P/Invoke with CreateProcessWithLogonW.
其他替代方法可能是使用此处指定的 P/Invoke (首先查看底部的注释),或者更有可能使用 P/Invoke 和CreateProcessWithLogonW。
回答by Matthias Meid
This should work well with the Process
class and ProcessStartInfo
.
这应该适用于Process
类和ProcessStartInfo
.
Different credentials:
不同的凭证:
Redirect standard output:
重定向标准输出:
Exit code:
退出代码:
回答by Chris Holmes
StartInfo has a property called CreateNoWindow that may make Reed's suggestion work for you.
StartInfo 有一个名为 CreateNoWindow 的属性,它可以使 Reed 的建议对您有用。
回答by Oskar Duveborn
Just an unverified thought, but isn't using dynamic Impersonate valid for the entire code block in .net 2+? So Impersonate the required user and then do whatever you need within the impersonated context/scope, like starting a process the normal way? Think we did something like that to integrate mstsc.exe launching using already supplied credentials.
只是一个未经证实的想法,但对 .net 2+ 中的整个代码块使用动态模拟是否有效?那么模拟所需的用户,然后在模拟的上下文/范围内执行您需要的任何操作,例如以正常方式启动流程?认为我们做了类似的事情来集成 mstsc.exe 使用已经提供的凭据启动。
回答by user1254219
If you want to see those exit codes actually used, have a look at www.robocopyplus.com. it acts like a wrapper around robocopy to add swicthes for email notification and report filtering. This may already do some of the stuff you are trying to achieve.
如果您想查看实际使用的退出代码,请查看 www.robocopyplus.com。它就像 robocopy 的包装器一样,为电子邮件通知和报告过滤添加开关。这可能已经完成了您想要实现的一些事情。