Beispiel #1
0
        /// <summary>
        /// Creates a new process in a desktop.
        /// </summary>
        /// <param name="path">Path to application.</param>
        /// <returns>The process object for the newly created process.</returns>
        public Process CreateProcess(string path)
        {
            // make sure object isnt disposed.
            CheckDisposed();

            // make sure a desktop is open.
            if (!IsOpen)
            {
                return(null);
            }

            // set startup parameters.
            var si = new StartUpInfo();

            si.cb        = Marshal.SizeOf(si);
            si.lpDesktop = DesktopName;

            var pi = new ProcessInfo();

            // start the process.
            var result = Kernel32.CreateProcess(null, path, IntPtr.Zero, IntPtr.Zero, true, NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref si, ref pi);

            // error?
            return(!result ? null : Process.GetProcessById(pi.ProcessId));
        }
Beispiel #2
0
        public Task <Process> Launch(LaunchOptions options)
        {
            _logger.LogInformation($"Launching app: '{options.FilePath}' using credentials for: '{options.Domain}'");

            StartUpInfo startupInfo = new StartUpInfo();

            startupInfo.cb            = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle       = null;
            startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            var workingDirectory = !string.IsNullOrWhiteSpace(options.WorkingDirectory)
                ? options.WorkingDirectory
                : Path.GetDirectoryName(options.FilePath);

            var password = _cipherService.Decrypt(options.Password);

            var process = RunAs.StartProcess(
                userName: options.UserName,
                domain: options.Domain,
                password: password,
                logonFlags: RunAs.LogonFlags.NetworkCredentialsOnly,
                applicationName: null,
                commandLine: options.FilePath,
                creationFlags: RunAs.CreationFlags.NewConsole,
                environment: IntPtr.Zero,
                currentDirectory: workingDirectory,
                startupInfo: ref startupInfo,
                processInfo: out _
                );

            return(Task.FromResult(process));
        }
Beispiel #3
0
        /// <summary>
        /// Starts the process interactively.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="procInfo">The proc information.</param>
        /// <param name="logonInfo">The logon information.</param>
        /// <param name="runAsLocalSystem">if set to <c>true</c> [run asynchronous local system].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public bool StartProcessInteractively(IAutomationRequest request, out ProcessInformation procInfo, LogOnDetails?logonInfo = null, bool runAsLocalSystem = false)
        {
            var retval = false;

            procInfo = new ProcessInformation();
            var    winlogonPid = GetSessionId(WTSGetActiveConsoleSessionId());
            IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
            var    sa = new SecurityAttributes();

            sa.Length = Marshal.SizeOf(sa);
            var si = new StartUpInfo()
            {
                lpDesktop = InteractiveWindowStation
            };

            si.cb = Marshal.SizeOf(si);

            if ((hProcess = OpenProcess(MaximumAllowed, false, winlogonPid)) != IntPtr.Zero &&
                OpenProcessToken(hProcess, TokenDuplicate, ref hPToken))
            {
                if (logonInfo == null)
                {
                    if (runAsLocalSystem)
                    {
                        if (DuplicateTokenEx(hPToken, MaximumAllowed, ref sa,
                                             (int)SecurityImpersonationLevel.SecurityIdentification,
                                             (int)TokenType.TokenPrimary, ref hUserTokenDup))
                        {
                            retval = CreateProcessAsUser(hUserTokenDup, null, request.FileName, ref sa, ref sa,
                                                         false, CreationFlags, IntPtr.Zero, null, ref si, out procInfo);
                        }
                    }
                    else
                    {
                        WTSQueryUserToken(WTSGetActiveConsoleSessionId(), ref hUserTokenDup);

                        retval = CreateProcessAsUser(hUserTokenDup, null, request.FileName, ref sa, ref sa,
                                                     false, CreationFlags, IntPtr.Zero, null, ref si, out procInfo);
                    }
                }
                else
                {
                    retval = StartProcessInteractivelyAsDifferentUser(ref hProcess, ref hPToken, ref hUserTokenDup, logonInfo.Value, ref sa,
                                                                      ref si, ref procInfo, request.FileName);
                }
            }

            CloseHandle(hProcess);
            CloseHandle(hPToken);
            CloseHandle(hUserTokenDup);

            return(retval);
        }
Beispiel #4
0
 public static extern bool CreateProcessAsUser(
     IntPtr hToken,
     string lpApplicationName,
     string lpCommandLine,
     ref SecurityAttributes lpProcessAttributes,
     ref SecurityAttributes lpThreadAttributes,
     bool bInheritHandle,
     Int32 dwCreationFlags,
     IntPtr lpEnvrionment,
     string lpCurrentDirectory,
     ref StartUpInfo lpStartupInfo,
     ref Process_Information lpProcessInformation);
Beispiel #5
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, string commandLine)
        {
            var startupInfo = new StartUpInfo();

            startupInfo.cb            = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle       = null;
            startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return(StartProcess(userName, domain, password, LogonFlags.WithProfile,
                                null, commandLine, CreationFlags.NewConsole, IntPtr.Zero,
                                null, ref startupInfo, out ProcessInformation processInfo));
        }
Beispiel #6
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static System.Diagnostics.Process StartProcess(string userName,
                                                              string domain, string password, string commandLine)
        {
            ProcessInformation processInfo;
            StartUpInfo        startupInfo = new StartUpInfo();

            startupInfo.cb            = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle       = null;
            startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return(StartProcess(userName, domain, password, LogonFlags.NetworkCredentialsOnly,
                                null, commandLine, CreationFlags.NewConsole, IntPtr.Zero,
                                null, ref startupInfo, out processInfo));
        }
Beispiel #7
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="logonFlags">
        /// Logon option. This parameter can be zero or one value from the LogonFlags enum.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="creationFlags">
        /// Use CreationFlags and PriorityFlags enums. Controls how the process is created.
        ///  Also controls the new process's priority class, which is used to determine the
        ///  scheduling priorities of the process's threads.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, LogonFlags logonFlags, string applicationName,
                                           string commandLine, CreationFlags creationFlags, string currentDirectory)
        {
            var startupInfo = new StartUpInfo();

            startupInfo.cb            = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle       = null;
            startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;;
            startupInfo.dwYCountChars = 50;

            return(StartProcess(userName, domain, password, logonFlags, applicationName,
                                commandLine, creationFlags, IntPtr.Zero, currentDirectory, ref startupInfo,
                                out ProcessInformation processInfo));
        }
Beispiel #8
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static System.Diagnostics.Process StartProcess(string userName,
                                                              string domain, string password, string applicationName, string commandLine,
                                                              string currentDirectory)
        {
            ProcessInformation processInfo;
            StartUpInfo        startupInfo = new StartUpInfo();

            startupInfo.cb            = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle       = null;
            startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return(StartProcess(userName, domain, password, LogonFlags.WithProfile,
                                applicationName, commandLine, CreationFlags.NewConsole, IntPtr.Zero,
                                currentDirectory, ref startupInfo, out processInfo));
        }
Beispiel #9
0
 /// <summary>
 /// Initializes default values for all parameters.
 /// </summary>
 /// <remarks>
 /// The following default values are assigned:
 /// <list type="table">
 ///  <listheader>
 ///   <term>
 ///    Parameter
 ///   </term>
 ///   <description>
 ///    Default Value
 ///   </description>
 ///  </listheader>
 ///  <item>
 ///   <term>
 ///    UserName
 ///   </term>
 ///   <description>
 ///    System.Environment.UserName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Domain
 ///   </term>
 ///   <description>
 ///    System.Environment.UserDomainName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Password
 ///   </term>
 ///   <description>
 ///    Empty string ("")
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ApplicationName
 ///   </term>
 ///   <description>
 ///    CurrentProcess.StartInfo.FileName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    LogonFlagsInstance
 ///   </term>
 ///   <description>
 ///    LogonFlags.WithProfile
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CommandLine
 ///   </term>
 ///   <description>
 ///    System.Environment.CommandLine
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CreationFlagsInstance
 ///   </term>
 ///   <description>
 ///    CreationFlags.NewConsole
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CurrentDirectory
 ///   </term>
 ///   <description>
 ///    System.Environment.CurrentDirectory
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Environment
 ///   </term>
 ///   <description>
 ///    IntPtr.Zero
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    StartupInfo
 ///   </term>
 ///   <description>
 ///    New StartUpInfo instance with the following values set:
 ///    -- cb is set to the size of the instance
 ///    -- dwFlags is set to StartUpInfoFlags.UseCountChars
 ///    --dwYCountChars is set to 50
 ///    --lpTitle is set to CurrentProcess.MainWindowTitle
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ProcessInfo
 ///   </term>
 ///   <description>
 ///    New ProcessInformation instance
 ///   </description>
 ///  </item>
 /// </list>
 /// </remarks>
 public RunAs()
 {
     UserName                   = System.Environment.UserName;
     Domain                     = System.Environment.UserDomainName;
     Password                   = "";
     LogonFlagsInstance         = LogonFlags.WithProfile;
     CommandLine                = System.Environment.CommandLine;
     CreationFlagsInstance      = CreationFlags.NewConsole;
     CurrentDirectory           = System.Environment.CurrentDirectory;
     _startupInfo               = new StartUpInfo();
     _startupInfo.cb            = Marshal.SizeOf(_startupInfo);
     _startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
     _startupInfo.dwYCountChars = 50;
     using (Process cp = Process.GetCurrentProcess())
     {
         ApplicationName      = cp.StartInfo.FileName;
         _startupInfo.lpTitle = cp.MainWindowTitle;
     }
     _processInfo = new ProcessInformation();
     Environment  = IntPtr.Zero;
 }
Beispiel #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ProcessRunner"/> class.
 /// </summary>
 public ProcessRunner()
 {
     _userName                  = System.Environment.UserName;
     _domain                    = System.Environment.UserDomainName;
     _password                  = "";
     _logonFlags                = LogonFlags.WithProfile;
     _commandLine               = System.Environment.CommandLine;
     _creationFlags             = CreationFlags.NewConsole;
     _currentDirectory          = System.Environment.CurrentDirectory;
     _startupInfo               = new StartUpInfo();
     _startupInfo.cb            = Marshal.SizeOf(_startupInfo);
     _startupInfo.dwFlags       = (int)StartUpInfoFlags.UseCountChars;
     _startupInfo.dwYCountChars = 50;
     using (System.Diagnostics.Process cp = System.Diagnostics.Process.GetCurrentProcess())
     {
         _applicationName     = cp.StartInfo.FileName;
         _startupInfo.lpTitle = cp.MainWindowTitle;
     }
     _processInfo = new ProcessInformation();
     Environment  = IntPtr.Zero;
 }
Beispiel #11
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="logonFlags">
        /// Logon option. This parameter can be zero or one value from the LogonFlags enum.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="creationFlags">
        /// Use CreationFlags and PriorityFlags enums. Controls how the process is created.
        ///  Also controls the new process's priority class, which is used to determine the
        ///  scheduling priorities of the process's threads.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <param name="environment">
        /// Pointer to an environment block for the new process. If this parameter is NULL,
        ///  the new process uses the environment of the specified user instead of the
        ///  environment of the calling process.
        /// </param>
        /// <param name="startupInfo">
        /// Specifies the window station, desktop, standard handles, and appearance of the
        ///  main window for the new process.
        /// </param>
        /// <param name="processInfo">
        /// ProcessInformation structure that receives identification information for the
        ///  new process, including a handle to the process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, LogonFlags logonFlags, string applicationName,
                                           string commandLine, CreationFlags creationFlags, IntPtr environment,
                                           string currentDirectory, ref StartUpInfo startupInfo,
                                           out ProcessInformation processInfo)
        {
            var cl = new StringBuilder(commandLine.Length);

            cl.Append(commandLine);
            var retval = CreateProcessWithLogonW(userName, domain, password,
                                                 (int)logonFlags, applicationName, cl, (uint)creationFlags, environment,
                                                 currentDirectory, ref startupInfo, out processInfo);

            if (!retval)
            {
                throw new Win32Exception();
            }

            CloseHandle(processInfo.hProcess);
            CloseHandle(processInfo.hThread);
            return(Process.GetProcessById(processInfo.dwProcessId));
        }
Beispiel #12
0
 internal static extern void GetStartupInfo(out StartUpInfo lpStartupInfo);
Beispiel #13
0
 private static extern bool CreateProcessWithLogonW(String lpszUsername, String lpszDomain, String lpszPassword,
                                                    int dwLogonFlags, string applicationName,
                                                    StringBuilder commandLine, uint creationFlags,
                                                    IntPtr environment, string currentDirectory,
                                                    ref StartUpInfo sui, out ProcessInformation processInfo);
Beispiel #14
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="logonFlags">
        /// Logon option. This parameter can be zero or one value from the LogonFlags enum.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="creationFlags">
        /// Use CreationFlags and PriorityFlags enums. Controls how the process is created.
        ///  Also controls the new process's priority class, which is used to determine the
        ///  scheduling priorities of the process's threads.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, LogonFlags logonFlags, string applicationName,
                                           string commandLine, CreationFlags creationFlags, string currentDirectory)
        {
            ProcessInformation processInfo;
            var startupInfo = new StartUpInfo();
            startupInfo.cb = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle = null;
            startupInfo.dwFlags = (int) StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return StartProcess(userName, domain, password, logonFlags, applicationName,
                                commandLine, creationFlags, IntPtr.Zero, currentDirectory, ref startupInfo,
                                out processInfo);
        }
Beispiel #15
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, string commandLine)
        {
            ProcessInformation processInfo;
            var startupInfo = new StartUpInfo();
            startupInfo.cb = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle = null;
            startupInfo.dwFlags = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return StartProcess(userName, domain, password, LogonFlags.WithProfile,
                                null, commandLine, CreationFlags.NewConsole | CreationFlags.Suspended, IntPtr.Zero,
                                null, ref startupInfo, out processInfo);
        }
Beispiel #16
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="logonFlags">
        /// Logon option. This parameter can be zero or one value from the LogonFlags enum.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="creationFlags">
        /// Use CreationFlags and PriorityFlags enums. Controls how the process is created.
        ///  Also controls the new process's priority class, which is used to determine the
        ///  scheduling priorities of the process's threads.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <param name="environment">
        /// Pointer to an environment block for the new process. If this parameter is NULL,
        ///  the new process uses the environment of the specified user instead of the
        ///  environment of the calling process.
        /// </param>
        /// <param name="startupInfo">
        /// Specifies the window station, desktop, standard handles, and appearance of the
        ///  main window for the new process.
        /// </param>
        /// <param name="processInfo">
        /// ProcessInformation structure that receives identification information for the
        ///  new process, including a handle to the process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static Process StartProcess(string userName,
                                           string domain, string password, LogonFlags logonFlags, string applicationName,
                                           string commandLine, CreationFlags creationFlags, IntPtr environment,
                                           string currentDirectory, ref StartUpInfo startupInfo,
                                           out ProcessInformation processInfo)
        {
            var cl = new StringBuilder(commandLine.Length);
            cl.Append(commandLine);
            bool retval = CreateProcessWithLogonW(userName, domain, password,
                                                  (int) logonFlags, applicationName, cl, (uint) creationFlags,
                                                  environment,
                                                  currentDirectory, ref startupInfo, out processInfo);
            if (!retval)
            {
                throw new Win32Exception();
            }

            CloseHandle(processInfo.hProcess);
            CloseHandle(processInfo.hThread);
            return Process.GetProcessById(processInfo.dwProcessId);
        }
Beispiel #17
0
 /// <summary>
 /// Initializes default values for all parameters.
 /// </summary>
 /// <remarks>
 /// The following default values are assigned:
 /// <list type="table">
 ///  <listheader>
 ///   <term>
 ///    Parameter
 ///   </term>
 ///   <description>
 ///    Default Value
 ///   </description>
 ///  </listheader>
 ///  <item>
 ///   <term>
 ///    UserName
 ///   </term>
 ///   <description>
 ///    System.Environment.UserName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Domain
 ///   </term>
 ///   <description>
 ///    System.Environment.UserDomainName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Password
 ///   </term>
 ///   <description>
 ///    Empty string ("")
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ApplicationName
 ///   </term>
 ///   <description>
 ///    CurrentProcess.StartInfo.FileName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    LogonFlagsInstance
 ///   </term>
 ///   <description>
 ///    LogonFlags.WithProfile
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CommandLine
 ///   </term>
 ///   <description>
 ///    System.Environment.CommandLine
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CreationFlagsInstance
 ///   </term>
 ///   <description>
 ///    CreationFlags.NewConsole
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CurrentDirectory
 ///   </term>
 ///   <description>
 ///    System.Environment.CurrentDirectory
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Environment
 ///   </term>
 ///   <description>
 ///    IntPtr.Zero
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    StartupInfo
 ///   </term>
 ///   <description>
 ///    New StartUpInfo instance with the following values set:
 ///    -- cb is set to the size of the instance
 ///    -- dwFlags is set to StartUpInfoFlags.UseCountChars
 ///    --dwYCountChars is set to 50
 ///    --lpTitle is set to CurrentProcess.MainWindowTitle
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ProcessInfo
 ///   </term>
 ///   <description>
 ///    New ProcessInformation instance
 ///   </description>
 ///  </item>
 /// </list>
 /// </remarks>
 public RunAs()
 {
     UserName = System.Environment.UserName;
     Domain = System.Environment.UserDomainName;
     Password = "";
     LogonFlagsInstance = LogonFlags.WithProfile;
     CommandLine = System.Environment.CommandLine;
     CreationFlagsInstance = CreationFlags.NewConsole;
     CurrentDirectory = System.Environment.CurrentDirectory;
     _startupInfo = new StartUpInfo();
     _startupInfo.cb = Marshal.SizeOf(_startupInfo);
     _startupInfo.dwFlags = (int) StartUpInfoFlags.UseCountChars;
     _startupInfo.dwYCountChars = 50;
     using (Process cp = Process.GetCurrentProcess())
     {
         ApplicationName = cp.StartInfo.FileName;
         _startupInfo.lpTitle = cp.MainWindowTitle;
     }
     _processInfo = new ProcessInformation();
     Environment = IntPtr.Zero;
 }
Beispiel #18
0
 /// <summary>
 /// Initializes default values for all parameters.
 /// </summary>
 /// <remarks>
 /// The following default values are assigned:
 /// <list type="table">
 ///  <listheader>
 ///   <term>
 ///    Parameter
 ///   </term>
 ///   <description>
 ///    Default Value
 ///   </description>
 ///  </listheader>
 ///  <item>
 ///   <term>
 ///    UserName
 ///   </term>
 ///   <description>
 ///    System.Environment.UserName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Domain
 ///   </term>
 ///   <description>
 ///    System.Environment.UserDomainName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Password
 ///   </term>
 ///   <description>
 ///    Empty string ("")
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ApplicationName
 ///   </term>
 ///   <description>
 ///    CurrentProcess.StartInfo.FileName
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    LogonFlagsInstance
 ///   </term>
 ///   <description>
 ///    LogonFlags.WithProfile
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CommandLine
 ///   </term>
 ///   <description>
 ///    System.Environment.CommandLine
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CreationFlagsInstance
 ///   </term>
 ///   <description>
 ///    CreationFlags.NewConsole
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    CurrentDirectory
 ///   </term>
 ///   <description>
 ///    System.Environment.CurrentDirectory
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    Environment
 ///   </term>
 ///   <description>
 ///    IntPtr.Zero
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    StartupInfo
 ///   </term>
 ///   <description>
 ///    New StartUpInfo instance with the following values set:
 ///    -- cb is set to the size of the instance
 ///    -- dwFlags is set to StartUpInfoFlags.UseCountChars
 ///    --dwYCountChars is set to 50
 ///    --lpTitle is set to CurrentProcess.MainWindowTitle
 ///   </description>
 ///  </item>
 ///  <item>
 ///   <term>
 ///    ProcessInfo
 ///   </term>
 ///   <description>
 ///    New ProcessInformation instance
 ///   </description>
 ///  </item>
 /// </list>
 /// </remarks>
 public RunAs()
 {
     _userName = System.Environment.UserName;
     _domain = System.Environment.UserDomainName;
     _password = "";
     _logonFlags = LogonFlags.WithProfile;
     _commandLine = System.Environment.CommandLine;
     _creationFlags = CreationFlags.NewConsole;
     _currentDirectory = System.Environment.CurrentDirectory;
     _startupInfo = new StartUpInfo();
     _startupInfo.cb = Marshal.SizeOf(_startupInfo);
     _startupInfo.dwFlags = (int)StartUpInfoFlags.UseCountChars;
     _startupInfo.dwYCountChars = 50;
     using (System.Diagnostics.Process cp = System.Diagnostics.Process.GetCurrentProcess())
     {
         _applicationName = cp.StartInfo.FileName;
         _startupInfo.lpTitle = cp.MainWindowTitle;
     }
     _processInfo = new ProcessInformation();
     _environment = IntPtr.Zero;
 }
Beispiel #19
0
        /// <summary>
        /// Creates a new process and its primary thread. The new process then runs the
        ///  specified executable file in the security context of the specified
        ///  credentials (user, domain, and password). It can optionally load the user
        ///  profile for the specified user.
        /// </summary>
        /// <remarks>
        /// This method is untested.
        /// </remarks>
        /// <param name="userName">
        /// This is the name of the user account to log on to. If you use the UPN format,
        ///  user@domain, the Domain parameter must be NULL. The user account must have
        ///  the Log On Locally permission on the local computer.
        /// </param>
        /// <param name="domain">
        /// Specifies the name of the domain or server whose account database contains the
        ///  user account. If this parameter is NULL, the user name must be specified in
        ///  UPN format.
        /// </param>
        /// <param name="password">
        /// Specifies the clear-text password for the user account.
        /// </param>
        /// <param name="applicationName">
        /// Specifies the module to execute. The specified module can be a Windows-based
        ///  application. It can be some other type of module (for example, MS-DOS or OS/2)
        ///  if the appropriate subsystem is available on the local computer. The string
        ///  can specify the full path and file name of the module to execute or it can
        ///  specify a partial name. In the case of a partial name, the function uses the
        ///  current drive and current directory to complete the specification. The function
        ///  will not use the search path. If the file name does not contain an extension,
        ///  .exe is assumed. Therefore, if the file name extension is .com, this parameter
        ///  must include the .com extension. The appname parameter can be NULL. In that
        ///  case, the module name must be the first white space-delimited token in the
        ///  commandline string. If the executable module is a 16-bit application, appname
        ///  should be NULL, and the string pointed to by commandline should specify the
        ///  executable module as well as its arguments.
        /// </param>
        /// <param name="commandLine">
        /// Specifies the command line to execute. The maximum length of this string is
        ///  32,000 characters. The commandline parameter can be NULL. In that case, the
        ///  function uses the string pointed to by appname as the command line. If the
        ///  file name does not contain an extension, .exe is appended. Therefore, if the
        ///  file name extension is .com, this parameter must include the .com extension.
        ///  If the file name ends in a period with no extension, or if the file name
        ///  contains a path, .exe is not appended. If the file name does not contain a
        ///  directory path, the system searches for the executable file.
        /// </param>
        /// <param name="currentDirectory">
        /// Specifies the full path to the current directory for the process. The string
        ///  can also specify a UNC path. If this parameter is NULL, the new process will
        ///  have the same current drive and directory as the calling process.
        /// </param>
        /// <returns>
        /// Returns a System.Diagnostic.Process which will be null if the call failed.
        /// </returns>
        /// <exception cref="System.ComponentModel.Win32Exception">
        /// Throws a System.ComponentModel.Win32Exception containing the last error if the
        ///  call failed.
        /// </exception>
        public static System.Diagnostics.Process StartProcess(string userName,
			string domain, string password, string applicationName, string commandLine,
			string currentDirectory)
        {
            ProcessInformation processInfo;
            StartUpInfo startupInfo = new StartUpInfo();
            startupInfo.cb = Marshal.SizeOf(startupInfo);
            startupInfo.lpTitle = null;
            startupInfo.dwFlags = (int)StartUpInfoFlags.UseCountChars;
            startupInfo.dwYCountChars = 50;

            return StartProcess(userName, domain, password, LogonFlags.WithProfile,
                applicationName, commandLine, CreationFlags.NewConsole, IntPtr.Zero,
                currentDirectory, ref startupInfo, out processInfo);
        }
Beispiel #20
0
 private static extern bool CreateProcessWithLogonW(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonFlags, string applicationName, StringBuilder commandLine, uint creationFlags, IntPtr environment, string currentDirectory, ref StartUpInfo sui, out ProcessInformation processInfo);
Beispiel #21
0
        /// <summary>
        /// Starts the process interactively asynchronous different user.
        /// </summary>
        /// <param name="hProcess">The authentication process.</param>
        /// <param name="hPToken">The authentication application token.</param>
        /// <param name="hUserTokenDup">The authentication user token dup.</param>
        /// <param name="logonInfo">The logon information.</param>
        /// <param name="sa">The sa.</param>
        /// <param name="si">The si.</param>
        /// <param name="procInfo">The proc information.</param>
        /// <param name="imageName">Name of the image.</param>
        /// <returns></returns>
        private bool StartProcessInteractivelyAsDifferentUser(ref IntPtr hProcess, ref IntPtr hPToken, ref IntPtr hUserTokenDup,
                                                              LogOnDetails logonInfo, ref SecurityAttributes sa, ref StartUpInfo si, ref ProcessInformation procInfo, string imageName)
        {
            //TODO: This method needs to be revised because WDM is killing the process
            var retval = false;

            if (LogonUser(logonInfo.UserName, logonInfo.Domain, logonInfo.Password, Logon32LogonInteractive, Logon32ProviderDefault, ref hUserTokenDup))
            {
                var luid      = new Luid();
                var sessionId = WTSGetActiveConsoleSessionId();
                if (LookupPrivilegeValue(IntPtr.Zero, SeDebugName, ref luid))
                {
                    if (SetTokenInformation(hUserTokenDup, TokenInformationClass.TokenSessionId, ref sessionId, (UInt32)IntPtr.Size))
                    {
                        var tp = new TokenPrivileges()
                        {
                            PrivilegeCount = 1,
                            Privileges     = new int[] { luid.LowPart, luid.HighPart, SePrivilegeEnabled }
                        };

                        if (AdjustTokenPrivileges(hUserTokenDup, false, ref tp, Marshal.SizeOf(tp), IntPtr.Zero, IntPtr.Zero))
                        {
                            retval = CreateProcessAsUser(hUserTokenDup, null, imageName, ref sa, ref sa,
                                                         false, CreationFlags, IntPtr.Zero, null, ref si, out procInfo);
                        }
                    }
                }
            }

            return(retval);
        }