/// <summary> /// Uses P/Invoke to start the process using the login token obtained for the user. /// </summary> /// <param name="token">The login token to use to create the process with.</param> private void StartWithCreateProcessAsUser(IntPtr token) { var startinfo = _process.StartInfo; var path = Path.GetFullPath(startinfo.FileName); var dir = Path.GetDirectoryName(path); bool processCreated = false; Win32NativeMethods.PROCESS_INFORMATION pi = new Win32NativeMethods.PROCESS_INFORMATION(); Win32NativeMethods.SECURITY_ATTRIBUTES saProcess = new Win32NativeMethods.SECURITY_ATTRIBUTES(); saProcess.bInheritHandle = true; saProcess.nLength = (uint)Marshal.SizeOf(saProcess); Win32NativeMethods.SECURITY_ATTRIBUTES saThread = new Win32NativeMethods.SECURITY_ATTRIBUTES(); saThread.bInheritHandle = true; saThread.nLength = (uint)Marshal.SizeOf(saThread); Win32NativeMethods.STARTUPINFO si = new Win32NativeMethods.STARTUPINFO(); si.lpDesktop = string.Empty; si.cb = (uint)Marshal.SizeOf(si); lock (createProcessLock) { _pipeServerToClient = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable); _pipeServerFromClient = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable); _pipeServerErrorFromClient = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable); try { // although these are separate if statements, in reality all standard streams must be // redirected otherwise it just won't work in SACS. if (startinfo.RedirectStandardInput) { _standardInput = new StreamWriter(_pipeServerToClient); _standardInput.AutoFlush = true; } if (startinfo.RedirectStandardOutput) { Encoding encoding = (startinfo.StandardOutputEncoding != null) ? startinfo.StandardOutputEncoding : Console.OutputEncoding; _standardOutput = new StreamReader(_pipeServerFromClient); } if (startinfo.RedirectStandardError) { Encoding encoding2 = (startinfo.StandardErrorEncoding != null) ? startinfo.StandardErrorEncoding : Console.OutputEncoding; _standardError = new StreamReader(_pipeServerErrorFromClient); } ArgumentObject["pipeIn"] = _pipeServerToClient.GetClientHandleAsString(); ArgumentObject["pipeOut"] = _pipeServerFromClient.GetClientHandleAsString(); ArgumentObject["pipeErr"] = _pipeServerErrorFromClient.GetClientHandleAsString(); processCreated = Win32NativeMethods.CreateProcessAsUser( token, path, string.Format("\"{0}\" {1}", startinfo.FileName.Replace("\"", "\"\""), JsonConvert.SerializeObject(this.ArgumentObject)), ref saProcess, ref saThread, true, 0, IntPtr.Zero, dir, ref si, out pi); if (!processCreated) { throw new Win32Exception(Marshal.GetLastWin32Error()); } // For the last step, since we're not using the in-build methods to start the process, // we need to replace the now outdated process _process = Process.GetProcessById((int)pi.dwProcessId); } finally { _pipeServerToClient.DisposeLocalCopyOfClientHandle(); _pipeServerFromClient.DisposeLocalCopyOfClientHandle(); _pipeServerErrorFromClient.DisposeLocalCopyOfClientHandle(); if (pi.hProcess != IntPtr.Zero) { Win32NativeMethods.CloseHandle(pi.hProcess); } if (pi.hThread != IntPtr.Zero) { Win32NativeMethods.CloseHandle(pi.hThread); } } } }