You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CreateProcessAsUser在新场景返回C0000142,原场景正常的问题排查

问题描述

我们遇到一个仅在新增支持场景中出现的问题。

原有正常运行场景(已稳定运行多年)

  • 无管理员权限的交互用户启动wix bootstrapper,该程序启动update-service,随后以local system身份启动wix bootstrapper的第二个实例。拥有local system权限的第二个实例负责安装软件。由于需要处理数据库操作,我们在自定义操作中执行dbinit工具——该工具需访问SQL Server,因此必须以原始用户权限运行。此场景运行正常。

[原有场景流程示意图]

新增场景问题

  • 现在需要支持由Windows服务而非交互用户启动wix bootstrapper的场景,原本预期能直接运行,但实际出现问题。

[新增场景流程示意图]

在新场景中,CreateProcessAsUser执行成功,但dbinit进程随即退出,返回错误码C0000142。

我们尝试过以下操作,但均无效果:

  • 创建自定义WindowStation/Desktop,通过ProcessHacker确认权限正确,且将句柄标记为inheritable
  • 调整句柄是否为inheritable、设置lpDesktop参数

发现当Windows服务运行用户属于本地管理员组时问题解决,但生产环境无法采用此配置。

另外,很多代码示例使用LogonUser获取令牌,但我们的用户大多是MSA(托管服务账户),无密码,此方法不可行。

更新1

将lpDesktop设置为空字符串时,约50%的情况能正常运行,说明问题与WindowStation和Desktop相关,但无法理解为何运行不稳定,且创建权限正确的自定义WindowStation/Desktop无效。

更新2

相关代码片段:

internal static SafeTokenHandle GetProcessAccessToken(int processId)
{
    var process = Process.GetProcessById(processId);
    if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, out IntPtr tokenHandle))
        return new SafeTokenHandle(tokenHandle);
    else
        throw new Win32Exception();
}

internal static SafeTokenHandle DuplicateAccessToken(SafeTokenHandle token)
{
    var success = DuplicateTokenEx(token,
                                    TOKEN_ALL_ACCESS,
                                    null,
                                    IMPERSONATION_LEVEL_SecurityIdentification,
                                    TOKEN_TYPE_TokenPrimary,
                                    out IntPtr newToken);


    return success ? new SafeTokenHandle(newToken) : throw new Win32Exception();
}

private bool Start()
{
    using (var processToken = GetProcessAccessToken(StartInfo.ProcessIdToImpersonateUserContext))
    {
        using (var newToken = DuplicateAccessToken(processToken))
        {
            var si = new STARTUPINFO();
            var pi = new PROCESS_INFORMATION();

            var safeProcessHandle = new SafeProcessHandle();
            var safeThreadHandle = new SafeThreadHandle();

            SafeFileHandle redirectedStandardOutputParentHandle = null;

            try
            {
                var profileInfo = new PROFILEINFO();
                profileInfo.dwSize = Marshal.SizeOf(profileInfo);
                profileInfo.lpUserName = "LimitedUser";

                var succeeded = LoadUserProfile(newToken, ref profileInfo);
                if (!succeeded)
                    throw new Win32Exception();

                var cmdLine = $"\"{StartInfo.FileName}\" {StartInfo.Arguments}".Trim();

                if (StartInfo.RedirectStandardOutput)
                {
                    CreatePipe(out redirectedStandardOutputParentHandle, out si.hStdOutput);
                    si.dwFlags = STARTF_USESTDHANDLES;
                }

                int creationFlags = 0;
                if (StartInfo.CreateNoWindow)
                    creationFlags |= CREATE_NO_WINDOW;

                creationFlags |= CREATE_UNICODE_ENVIRONMENT;

                int logonFlags = 0;
                if (StartInfo.LoadUserProfile)
                    logonFlags |= (int)LogonFlags.LOGON_WITH_PROFILE;

                string workingDirectory = StartInfo.WorkingDirectory;
                if (string.IsNullOrEmpty(workingDirectory))
                    workingDirectory = Environment.CurrentDirectory;

                var envBlock = GetEnvironmentBlock(newToken);

                succeeded = CreateProcessAsUserW(newToken,
                                                    null,
                                                    cmdLine,
                                                    null,
                                                    null,
                                                    true,
                                                    creationFlags,
                                                    new HandleRef(null, envBlock.DangerousGetHandle()),
                                                    workingDirectory,
                                                    si,
                                                    pi);

                if (!succeeded)
                    throw new Win32Exception();
                if (pi.hProcess != (IntPtr)0 && pi.hProcess != INVALID_HANDLE_VALUE)
                    safeProcessHandle.InitialSetHandle(pi.hProcess);
                if (pi.hThread != (IntPtr)0 && pi.hThread != INVALID_HANDLE_VALUE)
                    safeThreadHandle.InitialSetHandle(pi.hThread);

                DestroyEnvironmentBlock(envBlock.DangerousGetHandle());
            }
            finally
            {
                si.Dispose();
            }

            if (StartInfo.RedirectStandardOutput)
            {
                var enc = StartInfo.StandardOutputEncoding ?? Console.OutputEncoding;
                StandardOutput = new StreamReader(new FileStream(redirectedStandardOutputParentHandle, FileAccess.Read, 4096, false), enc, true, 4096);
            }

            _processHandle = safeProcessHandle;

            safeThreadHandle.Dispose();

            return true;
        }
    }
}

内容的提问来源于stack exchange,提问作者roli09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:54:58