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?

11,997

Solution 1

I think you want to look at:

ProcessStartInfo

That provides a .NET only way to start a process under a different user with different credentials. No more need for the 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.

Solution 2

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.

Share:
11,997
David Archer
Author by

David Archer

Updated on June 05, 2022

Comments

  • David Archer
    David Archer almost 2 years

    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.

    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.

    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.

    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).

    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.

    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 RunProcess that 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.