3

I need to run EXCEL.EXE with a user different than current one; in the past I do this without any issues, but after updating the system to Windows 10 Pro version 2004 (19041.508) this method is not working anymore.

I was using the following class (thanks to 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

}

In this way:

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);

I am getting all times the error:

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

Tried also with CreateProcessWithLogonW, same results.

Similar issue happens if I try to run it through PowerShell or through "runas".

This method was working before upgrading to Windows 10 2004 version, I've reproduced this on different computers.

What's the issue? How can I achieve what I want to do ?

-Edit-

Just discovered that using Excel v2002 build 12527.21104 it works; but with Excel v2008 build 13127.20408 it fails.

So apparently is a combination of Windows 10 v2004 + Office 2019 v2008 what causes the issue.

-Edit2-

If I make a copy of EXCEL.EXE and give it another name, like "EXCEL_COPY.EXE" it works :S

forlayo
  • 1,371
  • 2
  • 13
  • 23
  • Have you tried `Start-Process -FilePath Excel -Verb RunAs` in PowerShell? – KUTlime Sep 24 '20 at 20:08
  • Would you know what the version was *before* the upgrade? – dxiv Sep 24 '20 at 23:02
  • Is your goal to simply "run" the program or are you trying to call it from a shell. Depending on the answer we might need more details like @dxiv mentioned or if you want to run an exe just right click the executable while holding the Shift key. The context menu will show the "Run as a different user" option. – VantTech Sep 24 '20 at 23:19
  • @VantTech doing that I got same error but in a popup -> https://imgur.com/v0Ziyh0 – forlayo Sep 25 '20 at 07:23
  • @KUTlime that command is to run with administrator privileged, which is not what I wanted to do. I want to run it with other user account and profile. – forlayo Sep 25 '20 at 07:25
  • @dxiv 1909, but I've tried also with others; with same results. – forlayo Sep 25 '20 at 07:37
  • @forlayo Sorry, my fault... I meant `Start-Process -FilePath Excel -Verb RunAsUser` ? – KUTlime Sep 25 '20 at 09:30
  • 1
    @KUTlime It produces same result than doing it through contextual menu, which is same error but in a popup -> https://imgur.com/v0Ziyh0 I recently discovered that making a copy of exe file and doing the execution over this instead of original one works. Not sure on difference, as permissions of both looks same :S – forlayo Sep 25 '20 at 10:54
  • @forlayo Definitely a problem in Excel/Win32 API. You should report it to Microsoft directly. – KUTlime Sep 25 '20 at 11:16
  • @forlayo Behavior that depends on the EXE name suggests that it could be an app compatibility "shim" installed by Win 2004. You could try the [Compatibility Administrator](https://learn.microsoft.com/en-us/windows/deployment/planning/compatibility-administrator-users-guide) and look for EXCEL.EXE in the list. – dxiv Sep 25 '20 at 14:09
  • @dxiv apparently there's nothing for this version of Excel on the list. And anyway while tried with WINWORD.EXE, the trick does not work :( – forlayo Sep 25 '20 at 19:25
  • @forlayo Actually that does allow execution as a different user. Again you need to do this on the .exe itself not on the shortcuts from the Start Menu. Holding down the left Shift key while right clicking has been supported since Windows XP to do Run As and also get the option to launch CMD/Powershell if done inside a directory. Not sure where that is failing you I just reproduced it on 3 different Win10 machines. Otherwise try reinstalling your office suite. – VantTech Sep 26 '20 at 02:19
  • @VantTech doing what you suggests gives me the popup error -> https://imgur.com/v0Ziyh0 .Tested on two of my computers and 4 more of my coworkers. All of them running Windows 10 v2004 + Office 2019 v2008 , versions are important; as if yo try over Windows 10 v1909 (for example) will work. In fact it have been working before getting updated :( – forlayo Sep 26 '20 at 18:27

1 Answers1

2

I reported that issue to Microsoft and, after raising up few levels, they have worked on it and fixed. It's fixed on Windows 10 Build 19042.844

forlayo
  • 1,371
  • 2
  • 13
  • 23