public static extern bool CreateProcessWithTokenW( SafeNativeHandle hToken, LogonFlags dwLogonFlags, [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, StringBuilder lpCommandLine, Process.NativeHelpers.ProcessCreationFlags dwCreationFlags, Process.SafeMemoryBuffer lpEnvironment, [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, Process.NativeHelpers.STARTUPINFOEX lpStartupInfo, out Process.NativeHelpers.PROCESS_INFORMATION lpProcessInformation);
/// <summary> /// Creates a process as another user account. This method will attempt to run as another user with the /// highest possible permissions available. The main privilege required is the SeDebugPrivilege, without /// this privilege you can only run as a local or domain user if the username and password is specified. /// </summary> /// <param name="username">The username of the runas user</param> /// <param name="password">The password of the runas user</param> /// <param name="logonFlags">LogonFlags to control how to logon a user when the password is specified</param> /// <param name="logonType">Controls what type of logon is used, this only applies when the password is specified</param> /// <param name="lpApplicationName">The name of the executable or batch file to executable</param> /// <param name="lpCommandLine">The command line to execute, typically this includes lpApplication as the first argument</param> /// <param name="lpCurrentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param> /// <param name="environment">A dictionary of key/value pairs to define the new process environment</param> /// <param name="stdin">Bytes sent to the stdin pipe</param> /// <returns>Ansible.Process.Result object that contains the command output and return code</returns> public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType, string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment, byte[] stdin) { // While we use STARTUPINFOEX having EXTENDED_STARTUPINFO_PRESENT causes a parameter validation error Process.NativeHelpers.ProcessCreationFlags creationFlags = Process.NativeHelpers.ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT; Process.NativeHelpers.PROCESS_INFORMATION pi = new Process.NativeHelpers.PROCESS_INFORMATION(); Process.NativeHelpers.STARTUPINFOEX si = new Process.NativeHelpers.STARTUPINFOEX(); si.startupInfo.dwFlags = Process.NativeHelpers.StartupInfoFlags.USESTDHANDLES; SafeFileHandle stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinRead, stdinWrite; ProcessUtil.CreateStdioPipes(si, out stdoutRead, out stdoutWrite, out stderrRead, out stderrWrite, out stdinRead, out stdinWrite); FileStream stdinStream = new FileStream(stdinWrite, FileAccess.Write); // $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't // make sense for these parameters if (lpApplicationName == "") { lpApplicationName = null; } if (lpCurrentDirectory == "") { lpCurrentDirectory = null; } using (SafeMemoryBuffer lpEnvironment = ProcessUtil.CreateEnvironmentPointer(environment)) { // A user may have 2 tokens, 1 limited and 1 elevated. GetUserToken will try and get both but we will // only find out if the elevated token is valid when running here. List <SafeNativeHandle> userTokens = GetUserTokens(username, password, logonType); bool launchSuccess = false; StringBuilder commandLine = new StringBuilder(lpCommandLine); foreach (SafeNativeHandle token in userTokens) { if (NativeMethods.CreateProcessWithTokenW(token, logonFlags, lpApplicationName, commandLine, creationFlags, lpEnvironment, lpCurrentDirectory, si, out pi)) { launchSuccess = true; break; } } if (!launchSuccess) { throw new Win32Exception("CreateProcessWithTokenW() failed"); } } return(ProcessUtil.WaitProcess(stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinStream, stdin, pi.hProcess)); }
/// <summary> /// Creates a process as another user account. This method will attempt to run as another user with the /// highest possible permissions available. The main privilege required is the SeDebugPrivilege, without /// this privilege you can only run as a local or domain user if the username and password is specified. /// </summary> /// <param name="username">The username of the runas user</param> /// <param name="password">The password of the runas user</param> /// <param name="logonFlags">LogonFlags to control how to logon a user when the password is specified</param> /// <param name="logonType">Controls what type of logon is used, this only applies when the password is specified</param> /// <param name="lpApplicationName">The name of the executable or batch file to executable</param> /// <param name="lpCommandLine">The command line to execute, typically this includes lpApplication as the first argument</param> /// <param name="lpCurrentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param> /// <param name="environment">A dictionary of key/value pairs to define the new process environment</param> /// <param name="stdin">Bytes sent to the stdin pipe</param> /// <returns>Ansible.Process.Result object that contains the command output and return code</returns> public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType, string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment, byte[] stdin) { // While we use STARTUPINFOEX having EXTENDED_STARTUPINFO_PRESENT causes a parameter validation error Process.NativeHelpers.ProcessCreationFlags creationFlags = Process.NativeHelpers.ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT; Process.NativeHelpers.PROCESS_INFORMATION pi = new Process.NativeHelpers.PROCESS_INFORMATION(); Process.NativeHelpers.STARTUPINFOEX si = new Process.NativeHelpers.STARTUPINFOEX(); si.startupInfo.dwFlags = Process.NativeHelpers.StartupInfoFlags.USESTDHANDLES; SafeFileHandle stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinRead, stdinWrite; ProcessUtil.CreateStdioPipes(si, out stdoutRead, out stdoutWrite, out stderrRead, out stderrWrite, out stdinRead, out stdinWrite); FileStream stdinStream = new FileStream(stdinWrite, FileAccess.Write); // $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't // make sense for these parameters if (lpApplicationName == "") { lpApplicationName = null; } if (lpCurrentDirectory == "") { lpCurrentDirectory = null; } using (Process.SafeMemoryBuffer lpEnvironment = ProcessUtil.CreateEnvironmentPointer(environment)) using (SafeNativeHandle hToken = GetUserToken(username, password, logonType)) { StringBuilder commandLine = new StringBuilder(lpCommandLine); if (!NativeMethods.CreateProcessWithTokenW(hToken, logonFlags, lpApplicationName, commandLine, creationFlags, lpEnvironment, lpCurrentDirectory, si, out pi)) { throw new Process.Win32Exception("CreateProcessWithTokenW() failed"); } } return(ProcessUtil.WaitProcess(stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinStream, stdin, pi.hProcess)); }
/// <summary> /// Creates a process as another user account. This method will attempt to run as another user with the /// highest possible permissions available. The main privilege required is the SeDebugPrivilege, without /// this privilege you can only run as a local or domain user if the username and password is specified. /// </summary> /// <param name="username">The username of the runas user</param> /// <param name="password">The password of the runas user</param> /// <param name="logonFlags">LogonFlags to control how to logon a user when the password is specified</param> /// <param name="logonType">Controls what type of logon is used, this only applies when the password is specified</param> /// <param name="lpApplicationName">The name of the executable or batch file to executable</param> /// <param name="lpCommandLine">The command line to execute, typically this includes lpApplication as the first argument</param> /// <param name="lpCurrentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param> /// <param name="environment">A dictionary of key/value pairs to define the new process environment</param> /// <param name="stdin">Bytes sent to the stdin pipe</param> /// <returns>Ansible.Process.Result object that contains the command output and return code</returns> public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType, string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment, byte[] stdin) { // While we use STARTUPINFOEX having EXTENDED_STARTUPINFO_PRESENT causes a parameter validation error Process.NativeHelpers.ProcessCreationFlags creationFlags = Process.NativeHelpers.ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT; Process.NativeHelpers.PROCESS_INFORMATION pi = new Process.NativeHelpers.PROCESS_INFORMATION(); Process.NativeHelpers.STARTUPINFOEX si = new Process.NativeHelpers.STARTUPINFOEX(); si.startupInfo.dwFlags = Process.NativeHelpers.StartupInfoFlags.USESTDHANDLES; SafeFileHandle stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinRead, stdinWrite; ProcessUtil.CreateStdioPipes(si, out stdoutRead, out stdoutWrite, out stderrRead, out stderrWrite, out stdinRead, out stdinWrite); FileStream stdinStream = new FileStream(stdinWrite, FileAccess.Write); // $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't // make sense for these parameters if (lpApplicationName == "") { lpApplicationName = null; } if (lpCurrentDirectory == "") { lpCurrentDirectory = null; } // A user may have 2 tokens, 1 limited and 1 elevated. GetUserTokens will return both token to ensure // we don't close one of the pairs while the process is still running. If the process tries to retrieve // one of the pairs and the token handle is closed then it will fail with ERROR_NO_SUCH_LOGON_SESSION. List <SafeNativeHandle> userTokens = GetUserTokens(username, password, logonType); try { using (Process.SafeMemoryBuffer lpEnvironment = ProcessUtil.CreateEnvironmentPointer(environment)) { bool launchSuccess = false; StringBuilder commandLine = new StringBuilder(lpCommandLine); foreach (SafeNativeHandle token in userTokens) { // GetUserTokens could return null if an elevated token could not be retrieved. if (token == null) { continue; } if (NativeMethods.CreateProcessWithTokenW(token, logonFlags, lpApplicationName, commandLine, creationFlags, lpEnvironment, lpCurrentDirectory, si, out pi)) { launchSuccess = true; break; } } if (!launchSuccess) { throw new Process.Win32Exception("CreateProcessWithTokenW() failed"); } } return(ProcessUtil.WaitProcess(stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinStream, stdin, pi.hProcess)); } finally { userTokens.Where(t => t != null).ToList().ForEach(t => t.Dispose()); } }