Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Create Process as a different user

2,416 views
Skip to first unread message

Richard Webb

unread,
May 29, 2002, 2:21:33 PM5/29/02
to
Is there a way in C# to create a process as a different user?


Nicholas Paldino [.NET/C# MVP]

unread,
May 29, 2002, 2:34:28 PM5/29/02
to
Richard,

If you want to create a process as a different user, you should use the
WindowsIdentity class to first impersonate the user account that you want to
use in the process being created. The documentation for the Impersonate
method on the WindowsIdentity method will show you how to impersonate the
user. Once you do this, then call the static Start method on the Process
class, or create a new instance of the Process class and run it. Once done,
revert to the previous user.

If you don't need to use any methods on the Process class, then you can
use the P/Invoke layer to call the CreateProcessAsUser API call to have it
run the process you want.

Hope this helps.


--
- Nicholas Paldino [.NET MVP]
- nicholas...@exisconsulting.com

"Richard Webb" <richar...@jda.com> wrote in message
news:#xU4f2zBCHA.1692@tkmsftngp05...

Greg Ewing

unread,
May 29, 2002, 2:37:40 PM5/29/02
to
Richard, you can use the WindowsIdentity.Impersonate method. (watch line
wrap)

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfSystemSecurityPrincipalWindowsIdentityClassImpersonateTopic1.asp

--
Greg
http://www.claritycon.com/

"Richard Webb" <richar...@jda.com> wrote in message
news:#xU4f2zBCHA.1692@tkmsftngp05...

Willy Denoyette [MVP]

unread,
May 29, 2002, 5:11:57 PM5/29/02
to
Use PInvoke to call CreateProcessWithLogonW, this gives you the largest possibilities regarding environment block and profile
loading.

Other options using LogonUser and impersonate have are a number of issues:
- No profile gets loaded,
- only the system environment is loaded,
- LogonUser caller needs to run in the TCB on W2K and lower
- WindowsIdentity.Impersonate can only impersonate NETWORK style logon's NOT Interactive.

Here is a sample to get you started:

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

[assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode=true)]
[SecurityPermission(SecurityAction.Demand,ControlPrincipal = true)]
public class Class1
{
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool CreateProcessWithLogonW(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonFlags, string applicationName, StringBuilder commandLine,
int creationFlags, IntPtr environment,
string currentDirectory,
ref STARTUPINFO sui,
out PROCESS_INFORMATION processInfo);

[DllImport("kernel32")]
static extern bool CloseHandle(IntPtr handle);

[StructLayout(LayoutKind.Sequential)]
internal struct STARTUPINFO {
internal int cb;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpReserved;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpDesktop;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpTitle;
internal int dwX;
internal int dwY;
internal int dwXSize;
internal int dwYSize;
internal int dwXCountChars;
internal int dwYCountChars;
internal int dwFillAttribute;
internal int dwFlags;
internal short wShowWindow;
internal short cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION {
internal IntPtr hProcess;
internal IntPtr hThread;
internal int dwProcessId;
internal int dwThreadId;
}

//dwLogonFlags Specifies the logon option
const int LOGON_WITH_PROFILE = 1;
const int LOGON_NETCREDENTIALS_ONLY = 2;

//dwCreationFlags - Specifies how the process is created
const int CREATE_SUSPENDED = 0x00000004;
const int CREATE_NEW_CONSOLE = 0x00000010;
const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
const int CREATE_SEPARATE_WOW_VDM = 0x00000800;
const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const int CREATE_DEFAULT_ERROR_MODE = 0x04000000;

//dwCreationFlags parameter controls the new process's priority class
const int NORMAL_PRIORITY_CLASS = 0x00000020;
const int IDLE_PRIORITY_CLASS = 0x00000040;
const int HIGH_PRIORITY_CLASS = 0x00000080;
const int REALTIME_PRIORITY_CLASS = 0x00000100;
const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
//dwFlags
// This is a bit field that determines whether certain STARTUPINFO
// members are used when the process creates a window.
// Any combination of the following values can be specified:
const int STARTF_USESHOWWINDOW = 0x0000000;
const int STARTF_USESIZE = 0x00000002;
const int STARTF_USEPOSITION = 0x00000004;
const int STARTF_USECOUNTCHARS = 0x00000008;
const int STARTF_USEFILLATTRIBUTE = 0x00000010;
const int STARTF_FORCEONFEEDBACK = 0x00000040;
const int STARTF_FORCEOFFFEEDBACK = 0x00000080;
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USEHOTKEY = 0x00000200;


public static void Main(string[] args)
{
// Account to run as
string _logonName = "someone"; // some user
string _domain = "."; // local machine account
string _password = "secret";
StringBuilder sb = new StringBuilder();
// command to execute
sb.Append(@"devenv.exe");

PROCESS_INFORMATION processInfo;
STARTUPINFO startInfo = new STARTUPINFO();
startInfo.cb = Marshal.SizeOf(startInfo);
startInfo.lpTitle = "This is a Command console";
startInfo.dwFlags = STARTF_USECOUNTCHARS;
startInfo.dwYCountChars = 50;
// create process similar as "runas" using the logon users profile
bool ret = CreateProcessWithLogonW(_logonName, _domain, _password,
LOGON_WITH_PROFILE, null, sb,
NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
IntPtr.Zero, "c:\\",
ref startInfo, out processInfo);
Console.WriteLine("CreateProcessWithLogonW called");
if(!ret)
// If failure ...
Console.WriteLine("Error: {0}", Marshal.GetLastWin32Error());
else
Console.WriteLine("ProcessID: {0}", processInfo.dwProcessId);
}
}

Willy.

"Richard Webb" <richar...@jda.com> wrote in message news:#xU4f2zBCHA.1692@tkmsftngp05...

Richard Webb

unread,
Jun 6, 2002, 8:24:19 PM6/6/02
to
This does not seem to work. It changes the user in the current application,
but not for the new process. I am using Environment.UserName to check.
And yes, I am using the Process class.

"Nicholas Paldino [.NET/C# MVP]" <nicholas...@exisconsulting.com> wrote
in message news:#AtDD$zBCHA.1664@tkmsftngp02...

Richard Webb

unread,
Jun 6, 2002, 8:25:58 PM6/6/02
to
Impersonate does not seem to work on a newly created process. It will
change the user for the current process from which is was called.

Richard

"Greg Ewing" <gewing@_NO_SPAM_claritycon.com> wrote in message
news:#NukX$zBCHA.1432@tkmsftngp04...

Mark Michaelis

unread,
Jun 7, 2002, 3:02:05 AM6/7/02
to
Another possibility would be to use the runas command to launch your
application.

Mark

Willy Denoyette [MVP]

unread,
Jun 7, 2002, 11:08:33 AM6/7/02
to
Sure, this doesn't work using the Process class, and it is not intended to do so.
The process created is not inheritting the launching users identity.
The only way to do this is to call CreateProcessWithLogonW or CreateProcessAS using PInvoke, or like as been suggested by starting
"runas" using the Process class.
I posted a sample of the former in this same thread.

Willy.
"Richard Webb" <richar...@jda.com> wrote in message news:eusE7mbDCHA.2004@tkmsftngp02...

Richard Webb

unread,
Jun 7, 2002, 12:05:01 PM6/7/02
to
I received an error 87? when trying your code. Any insite?

"Willy Denoyette [MVP]" <willy.d...@pandora.be> wrote in message
news:ui3kgV1BCHA.2428@tkmsftngp02...

Willy Denoyette [MVP]

unread,
Jun 7, 2002, 3:15:09 PM6/7/02
to
Richard,

If you hapen to run this on W2K, you need to specify the domain/machine name.

Following is only valid on XP and higher.
string _domain = "."; // local account

On W2K specify the local machine name or the domain name.

string _domain = Environment.MachineName; // using local account database
string _domain = Environment.UserDomainName; // using domain account database

Willy.

"Richard Webb" <richar...@jda.com> wrote in message news:uAOoJ0jDCHA.1272@tkmsftngp04...

0 new messages