javaselenium-webdriverappiumwinappdriver

Java: WinAppDriver. The requested operation requires elevation


I'm trying to open the Windows Application Driver directly in my Java program, as it is, it works with every other program, but with Admin only ones it doesn't get the permission to run it. I've looked up online but any of those solutions doesn't seem to work

String wadServerPath = "C:\\Program Files\\Windows Application Driver\\WinAppDriver.exe";

ProcessBuilder builder = new ProcessBuilder(wadServerPath).inheritIO();
Process process = builder.start();

Error Message:

Caused by: org.openqa.selenium.WebDriverException: The requested operation requires elevation. (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 360 milliseconds
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'

Solution

  • Well the solution to this it's kinda of tricky, first of all we will use the JNA library. If you're using maven you could use this dependency

    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna</artifactId>
      <version>4.5.0</version>
    </dependency>
    <dependency>
        <groupId>net.java.dev.jna</groupId>
        <artifactId>jna-platform</artifactId>
        <version>4.5.0</version>
    </dependency>
    

    As for the code, we make an implementation of the "Shell32" inteface in order to get direct access to the windows' shell.

    import java.util.Arrays;
    import java.util.List;
    
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    import com.sun.jna.WString;
    import com.sun.jna.platform.win32.Shell32;
    import com.sun.jna.platform.win32.WinDef.HINSTANCE;
    import com.sun.jna.platform.win32.WinDef.HWND;
    import com.sun.jna.platform.win32.WinNT.HANDLE;
    import com.sun.jna.platform.win32.WinReg.HKEY;
    import com.sun.jna.win32.W32APIOptions;
    
    public interface Shell32X extends Shell32 {
        Shell32X INSTANCE = (Shell32X) Native.loadLibrary("shell32", Shell32X.class, W32APIOptions.UNICODE_OPTIONS);
    
        int SW_HIDE = 0;
        int SW_MAXIMIZE = 3;
        int SW_MINIMIZE = 6;
        int SW_RESTORE = 9;
        int SW_SHOW = 5;
        int SW_SHOWDEFAULT = 10;
        int SW_SHOWMAXIMIZED = 3;
        int SW_SHOWMINIMIZED = 2;
        int SW_SHOWMINNOACTIVE = 7;
        int SW_SHOWNA = 8;
        int SW_SHOWNOACTIVATE = 4;
        int SW_SHOWNORMAL = 1;
    
        /** File not found. */
        int SE_ERR_FNF = 2;
    
        /** Path not found. */
        int SE_ERR_PNF = 3;
    
        /** Access denied. */
        int SE_ERR_ACCESSDENIED = 5;
    
        /** Out of memory. */
        int SE_ERR_OOM = 8;
    
        /** DLL not found. */
        int SE_ERR_DLLNOTFOUND = 32;
    
        /** Cannot share an open file. */
        int SE_ERR_SHARE = 26;
    
        int SEE_MASK_NOCLOSEPROCESS = 0x00000040;
    
        int ShellExecute(int i, String lpVerb, String lpFile, String lpParameters, String lpDirectory, int nShow);
    
        boolean ShellExecuteEx(SHELLEXECUTEINFO lpExecInfo);
    
        public static class SHELLEXECUTEINFO extends Structure {
            /*
            * DWORD cbSize; ULONG fMask; HWND hwnd; LPCTSTR lpVerb; LPCTSTR lpFile; LPCTSTR
            * lpParameters; LPCTSTR lpDirectory; int nShow; HINSTANCE hInstApp; LPVOID
            * lpIDList; LPCTSTR lpClass; HKEY hkeyClass; DWORD dwHotKey; union { HANDLE
            * hIcon; HANDLE hMonitor; } DUMMYUNIONNAME; HANDLE hProcess;
            */
    
            public int cbSize = size();
            public int fMask;
            public HWND hwnd;
            public WString lpVerb;
            public WString lpFile;
            public WString lpParameters;
            public WString lpDirectory;
            public int nShow;
            public HINSTANCE hInstApp;
            public Pointer lpIDList;
            public WString lpClass;
            public HKEY hKeyClass;
            public int dwHotKey;
    
            /*
            * Actually: union { HANDLE hIcon; HANDLE hMonitor; } DUMMYUNIONNAME;
            */
            public HANDLE hMonitor;
            public HANDLE hProcess;
    
            protected List getFieldOrder() {
                return Arrays.asList(new String[] { "cbSize", "fMask", "hwnd", "lpVerb", "lpFile", "lpParameters",
                        "lpDirectory", "nShow", "hInstApp", "lpIDList", "lpClass", "hKeyClass", "dwHotKey", "hMonitor",
                        "hProcess", });
            }
        }
    
    }
    

    Then we implement all into a method that will allows to do what we were looking for.

    public static void executeAsAdministrator(String command, String args)
    {
        Shell32X.SHELLEXECUTEINFO execInfo = new Shell32X.SHELLEXECUTEINFO();
        execInfo.lpFile = new WString(command);
        if (args != null)
            execInfo.lpParameters = new WString(args);
        execInfo.nShow = Shell32X.SW_SHOWDEFAULT;
        execInfo.fMask = Shell32X.SEE_MASK_NOCLOSEPROCESS;
        execInfo.lpVerb = new WString("runas");
        boolean result = Shell32X.INSTANCE.ShellExecuteEx(execInfo);
    
        if (!result)
        {
            int lastError = Kernel32.INSTANCE.GetLastError();
            String errorMessage = Kernel32Util.formatMessageFromLastErrorCode(lastError);
            throw new RuntimeException("Error performing elevation: " + lastError + ": " + errorMessage + " (apperror=" + execInfo.hInstApp + ")");
        }
    }
    

    And then just call it where you need it

    String wadServerPath = "C:\\Program Files\\Windows Application Driver\\WinAppDriver.exe";
    
        //ProcessBuilder builder = new ProcessBuilder(wadServerPath).inheritIO();
        //Process process = builder.start();
        executeAsAdministrator(wadServerPath, "");