2

我将 Wcf 服务托管在 IIS、Windows Server 2008 R2 中,使用带有 NETWORK SERVICE 标识的 AppPool .NET 4.0。

我的 Wcf 服务有一个使用 Process.Start 调用命令 EXE 的方法。

我需要使用不同的用户作为执行命令 EXE(域用户帐户)的凭据。

我尝试执行它,但它对我不起作用:它似乎没有执行命令 EXE。

更新:进程退出,但不执行代码

我收到如下错误:

退出代码-1073741502

和 eventvwr:

            Process Information:
            Process ID:            0xc50
            Process Name:      C:\DeployTools\DeployTools.Commands.Ejecutar.exe
            Exit Status:            0xc0000142

应用程序无法正确启动 (0xC0000142)。单击确定关闭应用程序

有什么建议么?

代码:

        StreamReader sr = null;
        StreamReader serr = null;

        try
        {
            var psi = new ProcessStartInfo(MY_COMMAND_EXE);
            psi.WorkingDirectory = Path.GetDirectoryName(MY_COMMAND_EXE);
            psi.Arguments = arguments;
            psi.Domain = DOMAIN;
            psi.UserName = USER_IN_DOMAIN;
            psi.Password = SecureStringHelper.ToSecureString(pwd);

            psi.LoadUserProfile = true;
            psi.UseShellExecute = false;

            psi.ErrorDialog = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            psi.CreateNoWindow = true;
            psi.WindowStyle = ProcessWindowStyle.Minimized;

            using (Process pr = Process.Start(psi))
            {
                sr = pr.StandardOutput;
                serr = pr.StandardError;

                if (!pr.HasExited)
                {
                    pr.WaitForExit(300000);
                }
                output = pr.StandardOutput.ReadToEnd();
                errors = pr.StandardError.ReadToEnd();
                exitCode = pr.ExitCode;

                return output;
            }
        }
        catch (Exception exc)
        {
            return "EXCEPCIÓN: " + exc.Message;
        }
        finally
        {
            if (sr != null)
            {
                sr.Close();
                sr.Dispose();
                sr = null;
            }

            if (serr != null)
            {
                serr.Close();
                serr.Dispose();
                serr = null;
            }
        }
4

1 回答 1

5

我必须添加对AsproLock.dll和相关代码的引用,以允许用户帐户访问正在运行的资源。

            //The following security adjustments are necessary to give the new 
            //process sufficient permission to run in the service's window station
            //and desktop. This uses classes from the AsproLock library also from 
            //Asprosys.
            IntPtr hWinSta = NativeMethods.GetProcessWindowStation();
            WindowStationSecurity ws = new WindowStationSecurity(hWinSta,
              System.Security.AccessControl.AccessControlSections.Access);
            ws.AddAccessRule(new WindowStationAccessRule(userPassDto.Usuario,
                WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
            ws.AcceptChanges();

            IntPtr hDesk = NativeMethods.GetThreadDesktop(NativeMethods.GetCurrentThreadId());
            DesktopSecurity ds = new DesktopSecurity(hDesk,
                System.Security.AccessControl.AccessControlSections.Access);
            ds.AddAccessRule(new DesktopAccessRule(userPassDto.Usuario,
                DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
            ds.AcceptChanges();

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetThreadDesktop(int dwThreadId);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetCurrentThreadId();

Asprosys 在新证书下启动流程的风险和陷阱

这不是一个常见的需求,但也不是那么罕见,所以我认为我最好发布此分步指南,以解决在模拟凭据下启动进程的问题。这基于使用 .Net Process 类的 Start 方法,但它也适用于底层 API 调用:CreateProcessWithLogonW 和 CreateProcessWithTokenW。

访问被拒绝- 第一次尝试和访问被拒绝异常立即发生。这是最常见的初始问题,是由于服务在 LOCAL SYSTEM 帐户下运行造成的。奇怪的是,SYSTEM 帐户是计算机上最强大的帐户,但它不能做的少数事情之一是使用 CreateProcessWithLogonW 启动一个进程,它是调用 Process.Start 的基础 API。因此,将您的服务帐户更改为本地服务,无论如何它可能是更合适的帐户。

再次拒绝访问- 啊,我以为我们解决了这个问题。糟糕,请仔细检查您尝试启动的应用程序的权限。请记住,系统尝试以进程将在其下运行的用户帐户而不是服务帐户访问应用程序文件。

无效的目录错误- 什么?所有的路径都是正确的。所有目录都拼写正确,没有无效字符。这是一个令人难以置信的令人讨厌的错误,并且不是很一致。通常,当我们运行一个进程时,我们不会费心设置 WorkingDirectory 属性,而只是接受父进程的默认值。使用新凭据启动进程时,您不能这样做,您必须明确设置 WorkingDirectory 的路径,否则您将收到“目录名称无效”。Win32 异常。

失败:没有错误?- Process.Start 很好地为您处理新进程的环境块的创建。因此,仅当您使用底层 API 时,这才是一个问题。在调用其中一个 CreateProcess* API 时,将 lpEnvironment 参数保留为 NULL 并让系统使用从父进程复制块的默认设置是正常的。但是在新凭据下启动时,您必须手动或使用 CreateEnvironmentBlock 显式创建环境块。更糟糕的是,如果您忽略它,CreateProcess* 调用将失败,但 GetLastError 将返回 ERROR_SUCCESS,如果您在创建环境块时出错,则不会出现错误,但该过程可能根本无法运行。

应用程序无法正确初始化- 没有更多的例外,你已经解决了所有的问题,进程已经启动。再次糟糕,流程在哪里?检查事件日志(或者您可能收到了应用程序错误弹出窗口)。应用程序错误应该有一个条目,说明您的进程是错误的应用程序,user32.dll 或 kernel32.dll 是错误的模块,异常是:0xC0000142。这可能会有一些细微的变化,但基本上是说您的应用程序无法初始化。这样做的原因是,在初始化时,在运行任何应用程序代码之前,所有进程都附加到 Window Station,所有线程都附加到桌面,但是您正在启动的用户没有访问 Window Station 和桌面的权限您的进程正在其中启动,因此它无法初始化。必须调整 Window Station 和 Desktop 的安全描述符,以向正在启动进程的用户授予 AllAccess 权限。这是直接在 .Net 中做的事情,所以您可能会发现这里的安全包装类很有用。

没有更多错误- 真的,没有更多错误,您的流程现在应该运行顺利。根据用户是谁(例如管理员在某些情况下已经拥有正确的权限)或您要启动的会话类型,您需要执行的操作可能会有所不同。但是遵循这些步骤应该会让您的生活顺利和容易(也许不是你的一生)。

参考:

在新证书下启动流程的风险和陷阱

Aspro Lock - 访问控制

代码示例

在备用凭据下创建新进程 (createprocessasuser)

进程启动挂起

于 2013-07-11T11:46:15.940 回答