WCF服务进程.在模拟为其他用户的网络服务帐户下启动

本文关键字:网络服务 启动 用户 服务进程 模拟 其他 WCF | 更新日期: 2023-09-27 18:21:22

我在IIS、Windows Server 2008 R2中托管Wcf服务,使用具有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;
            }
        }

WCF服务进程.在模拟为其他用户的网络服务帐户下启动

为了允许用户帐户访问正在运行的资源,我不得不添加对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的路径,否则您将得到"目录名无效"。Win32Exception。

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

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

不再有错误-实际上,不再有错误,您的进程现在应该运行顺利。根据用户的身份(例如,在某些情况下,管理员已经拥有正确的权限)或您启动的会话类型,您需要做的事情可能会有所不同。但遵循这些步骤应该会让您的生活变得平稳轻松(可能不是您的一生)。

参考文献:

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

Aspro锁-门禁

代码样本

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

processstart挂起