Re: Redirecting sdtin, stdout, stderr from an already running process

ghandi wrote:
I am trying to redirect stdin, stdout, stderr of a process I started
with the win32 call CreateProcessAsUser, since I couldn't find a way
to start a process with .net that used a user name and password and
didn't show any kind of window. The only way I can see to do redirect
the input and output now is to continue to use the win32 API (maybe a
pipe?). Is there a way to do this with .net? Can I get the process
input and output into a stream or something?

Alright, let's restart this one from the top because it's a real hornet's nest. To summarize:

The issue at hand is that we wish to start a process under another user's credentials with redirected I/O, without displaying a new window for that process. Normally, this is accomplished by calling Process.Start() with a ProcessStartInfo structure whose property "CreateNoWindow" is set to true and whose "Redirect*" properties are set to appropriate values. However, setting "CreateNoWindow" has no effect when also setting the "UserName" and "Password" properties. The reason it has no effect is that Process calls CreateProcessWithLogonW() to start the new process, and this function does not support the CREATE_NO_WINDOW flag that "CreateNoWindow" maps to.

One might be tempted to use a combination of LogonUser()/CreateProcessAsUser() instead. This has great problems of its own, however. In order to use CreateProcessAsUser() successfully, the caller must hold the SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME privileges. By default, on most systems, the only accounts that hold this privilege are the NetworkService and LocalService accounts. Not even administrators have this privilege by default. CreateProcessAsLogonW() is recommended as the successor to this combination, since it does not require additional privileges.

Moreover, using any of the unmanaged CreateProcess*() functions in combination with I/O redirection is cumbersome. The basic approach is to use inheritable handles anonymous pipes, but there are many pitfalls. The MSDN contains a sample for unmanaged code that clearly demonstrates the difficulties involved:

A much simpler approach is to use impersonation, then use Process to start the process regularly:

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);


IntPtr userToken;
if (!LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out userToken) {
throw new Win32Exception();

ProcessStartupInfo startupInfo;
startupInfo.RedirectStandardOutput = true;
startupInfo.UseShellExecute = false;
startupInfo.CreateNoWindow = true;

Process process;
using (WindowsIdentity identity = new WindowsIdentity(userToken)) {
using (WindowsImpersonationContext impersonationContext = identity.Impersonate()) {
process = Process.Start(startupInfo);

This, finally, works on my system. Is it of use to you too?