Windows 2004 更新后无法以其他用户身份运行 EXCEL.EXE

Posted

技术标签:

【中文标题】Windows 2004 更新后无法以其他用户身份运行 EXCEL.EXE【英文标题】:Can not run EXCEL.EXE as other user after Windows 2004 update 【发布时间】:2021-01-11 02:45:47 【问题描述】:

我需要使用不同于当前用户的用户运行 EXCEL.EXE;过去我这样做没有任何问题,但在将系统更新到 Windows 10 Pro 版本 2004 (19041.508) 后,此方法不再有效。

我正在使用以下课程(感谢Impersonate user in Windows Service):

public class CreateProcess


    #region Constants

    const UInt32 INFINITE = 0xFFFFFFFF;
    const UInt32 WAIT_FAILED = 0xFFFFFFFF;

    #endregion


    #region ENUMS

    [Flags]
    public enum LogonType
    
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK = 3,
        LOGON32_LOGON_BATCH = 4,
        LOGON32_LOGON_SERVICE = 5,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
        LOGON32_LOGON_NEW_CREDENTIALS = 9
    


    [Flags]
    public enum LogonProvider
    
        LOGON32_PROVIDER_DEFAULT = 0,
        LOGON32_PROVIDER_WINNT35,
        LOGON32_PROVIDER_WINNT40,
        LOGON32_PROVIDER_WINNT50
    

    #endregion


    #region Structs

    [StructLayout(LayoutKind.Sequential)]
    public struct STARTUPINFO
    
        public Int32 cb;
        public String lpReserved;
        public String lpDesktop;
        public String lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    


    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    
        public IntPtr hProcess;
        public IntPtr hThread;
        public Int32 dwProcessId;
        public Int32 dwThreadId;
    

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    
        public int nLength;
        public unsafe byte* lpSecurityDescriptor;
        public int bInheritHandle;
    

    public enum TOKEN_TYPE
    
        TokenPrimary = 1,
        TokenImpersonation
    

    public enum SECURITY_IMPERSONATION_LEVEL
    
        SecurityAnonymous,
        SecurityIdentification,
        SecurityImpersonation,
        SecurityDelegation
    

    #endregion


    #region FUNCTIONS (P/INVOKE)

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool RevertToSelf();

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);


    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern Boolean LogonUser
    (
        String UserName,
        String Domain,
        String Password,
        LogonType dwLogonType,
        LogonProvider dwLogonProvider,
        out IntPtr phToken
    );


    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Boolean CreateProcessAsUser
    (
        IntPtr hToken,
        String lpApplicationName,
        String lpCommandLine,
        IntPtr lpProcessAttributes,
        IntPtr lpThreadAttributes,
        Boolean bInheritHandles,
        Int32 dwCreationFlags,
        IntPtr lpEnvironment,
        String lpCurrentDirectory,
        ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation
    );





    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern UInt32 WaitForSingleObject
    (
        IntPtr hHandle,
        UInt32 dwMilliseconds
    );

    [DllImport("kernel32", SetLastError = true)]
    public static extern Boolean CloseHandle(IntPtr handle);

    #endregion

    #region Functions

    public static int LaunchCommand(string command, string domain, string account, string password)
    
        int ProcessId = -1;
        PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
        STARTUPINFO startInfo = new STARTUPINFO();
        Boolean bResult = false;

        UInt32 uiResultWait = WAIT_FAILED;

        var token = ValidateParametersAndGetFirstLoginToken(domain, account, password);

        var duplicateToken = IntPtr.Zero;
        try
        

            startInfo.cb = Marshal.SizeOf(startInfo);
            startInfo.lpDesktop = "winsta0\\default";

            bResult = CreateProcessAsUser(
                token,
                null,
                command,
                IntPtr.Zero,
                IntPtr.Zero,
                false,
                0,
                IntPtr.Zero,
                null,
                ref startInfo,
                out processInfo
            );

            if (!bResult)  throw new Exception("CreateProcessAsUser error #" + Marshal.GetLastWin32Error()); 

            // Wait for process to end
            uiResultWait = WaitForSingleObject(processInfo.hProcess, INFINITE);

            ProcessId = processInfo.dwProcessId;

            if (uiResultWait == WAIT_FAILED)  throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); 

        
        finally
        
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (duplicateToken != IntPtr.Zero)
                CloseHandle(duplicateToken);
            CloseHandle(processInfo.hProcess);
            CloseHandle(processInfo.hThread);
        

        return ProcessId;
    


    private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password)
    


        if (!RevertToSelf())
        
            Console.WriteLine("RevertToSelf call to remove any prior impersonations failed");
            throw new Exception("RevertToSelf call to remove any prior impersonations failed");
        

        IntPtr token;

        var result = LogonUser(username,
                               domain,
                               password,
                               LogonType.LOGON32_LOGON_INTERACTIVE,
                               LogonProvider.LOGON32_PROVIDER_DEFAULT,
                               out token);
        if (!result)
        
            var errorCode = Marshal.GetLastWin32Error();

            Console.WriteLine(string.Format("Could not impersonate the elevated user.  LogonUser: 2\\1 returned error code: 0.", errorCode, username, domain));
            throw new Exception("Logon for user " + username + " failed.");
        
        return token;
    

    #endregion


这样:

var otherUserInSystemName = "probanduela";
                var otherUserInSystemPassword = "chapuza";

                var regularWin32AppPath = @"C:\Program Files (x86)\WinMerge\WinMergeU.exe";
                var officeWin32AppPath = @"C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE";
    var ProcessId = CreateProcess.LaunchCommand(officeWin32AppPath, Environment.MachineName, otherUserInSystemName, otherUserInSystemPassword);

我总是收到错误:

1312: A specified logon session does not exist. It may already have been terminated.

也尝试了 CreateProcessWithLogonW,结果相同。

如果我尝试通过 PowerShell 或“runas”运行它,也会出现类似问题。

此方法在升级到 Windows 10 2004 版本之前有效,我已在不同的计算机上重现此方法。

有什么问题?我怎样才能实现我想做的事情?

-编辑-

刚刚发现使用 Excel v2002 build 12527.21104 可以工作;但使用 Excel v2008 build 13127.20408 失败。

显然是 Windows 10 v2004 + Office 2019 v2008 的组合导致了这个问题。

-编辑2-

如果我复制 EXCEL.EXE 并给它另一个名称,例如“EXCEL_COPY.EXE”,它可以工作:S

【问题讨论】:

你在 PowerShell 中尝试过Start-Process -FilePath Excel -Verb RunAs 吗? 您知道升级之前是什么版本吗? 您的目标是简单地“运行”程序还是尝试从外壳程序调用它。根据答案,我们可能需要更多详细信息,例如提到的@dxiv,或者如果您想运行 exe,只需在按住 Shift 键的同时右键单击可执行文件。上下文菜单将显示“以其他用户身份运行”选项。 @VantTech 这样做我得到了同样的错误,但在弹出窗口中 -> imgur.com/v0Ziyh0 @KUTlime 它产生与通过上下文菜单执行相同的结果,这是相同的错误但在弹出窗口中 -> imgur.com/v0Ziyh0 我最近发现制作 exe 文件的副本并在此执行而不是原创作品。不确定区别,因为两者的权限看起来相同:S 【参考方案1】:

我向微软报告了这个问题,在提升了几个级别后,他们已经着手解决并修复了。固定在Windows 10 Build 19042.844

【讨论】:

以上是关于Windows 2004 更新后无法以其他用户身份运行 EXCEL.EXE的主要内容,如果未能解决你的问题,请参考以下文章

怎么在windows上安装Atom

怎么在windows上安装Atom

无法以其他用户身份启动 Visual Studio 2015

我在 Windows 8、8.1 和 Windows 10 中的应用程序无法识别地图驱动器

win10新增用户其他用户无法访问原用户资料?

微软确认系统内置的Microsoft Defender将会阻止用户更新v2004版