MarkBlakley Posted March 5, 2018 Posted March 5, 2018 I need to be able to run some applications and commands as Administrator when running from a non-Admin command window. I realize that this is probably one of the most requested use cases for AutoIt in general, and I have been able to get a few of my specific use cases working, but I have some specific needs that I haven't been able to solve yet. I'm starting to think I'm running into a limitation of Windows, but I don't know enough to really confirm that. I'd really like to be able to start a non-Admin cmd window and run an application as Admin (using the RunAs function from an AutoIt app), and get both the console output and the exit code back. It seems like I can do one or the other, but I can't get both when running from a non-Admin console window. I've tried some UDFs, and made changes based on this process UDF (https://www.autoitscript.com/forum/files/file/356-process-udf/) to allow RunAs, but it doesn't seem to work in this case. Other notes about my setup: UAC is turned all the way down (off) I don't have the ability to manually interact with the system at any point in the process - it's part of a manual reimage install loop for CI automated testing The AutoItRunAs.exe will be called from a VBScript that's running under a non-Admin account Windows 8+ only (mainly Windows 10) Here's a simplified example of the AutoIt code that I have: #AutoIt3Wrapper_Outfile_x64=AutoItRunAs.exe #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Change2CUI=y #include <ProcessConstants.au3> #include <AutoItConstants.au3> #include <ProcessEx.au3> Local $output = "", $err = "", $cmd=CmdLine[1], $user=CmdLine[2], $pass=CmdLine[3] $PID = RunAs($user, "", $pass, 4, $cmd, "", @SW_HIDE, $STDERR_MERGED) ; Get the handle of the process Local $hProcessHandle = _Process_GetHandle($PID) While ProcessExists($PID) ; Capture the output $output &= StdoutRead($PID) ; Don't kill the CPU Sleep(100) WEnd ; Capture any remaining output $output &= StdoutRead($PID) ; Get the exit code from the process handle, so that this AutoIt executable can exit with the same exit code $exitCode = _Process_GetExitCode($hProcessHandle) ; Write the output from running the command back out, so whoever is watching for the RunAs output can consume it ConsoleWrite($output) I'd like to be able to call my AutoIt application like this: > AutoItRunAs.exe <cmd> <username> <password> Examples: (requires Admin permissions - I get the output, which meets my needs. I don't care about the exit code in this specific case) > AutoItRunAs.exe "bcdedit" Administrator AdminPass (requires Admin permissions - doesn't currently perform the copy) > AutoItRunAs.exe "xcopy D:\myfile\test.txt C:\ /Y /A /H /E" Administrator AdminPass (doesn't require Admin permissions - I still don't get the exit code) > AutoItRunAs.exe "exit /b 7777" Administrator AdminPass If I run the application from a non-Admin console window, the application either doesn't work (the xcopy example), or it doesn't provide the exit code (the exit /b example). Any help is appreciated. AutoItRunAs.au3
MarkBlakley Posted March 5, 2018 Author Posted March 5, 2018 Doh, I didn't copy quite enough for my cut down version - script should end with "Exit($exitCode)" AutoItRunAs.au3
Moderators JLogan3o13 Posted March 5, 2018 Moderators Posted March 5, 2018 Thread moved to the appropriate forum, as the DEV Forum very clearly states: Quote Do not create AutoIt-related topics here, use AutoIt General Help and Support "Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball How to get your question answered on this forum!
antmar904 Posted March 5, 2018 Posted March 5, 2018 I've used this many times to perform admin tasks when standard users are logged in:
MarkBlakley Posted March 6, 2018 Author Posted March 6, 2018 Thanks for the reference. I'm not having problems executing the commands as admin - I'm able to do that in certain scenarios. My issue is getting the console output AND exit code back to the calling vbs script. I want it all! It seems like the script that you've provided just elevates permissions, which I had previously gotten to work with a different script that didn't try to get the output and exit code. Using my code above, if I remove the $STDERR_MERGED parameter off of my RunAs call, it will actually successfully run the command as Admin - I just won't get the console output.
MarkBlakley Posted March 12, 2018 Author Posted March 12, 2018 Anyone have any insight into what's happening for my specific case? I'm assuming it's a limitation of Windows at this point, but I'd really like to know if anyone has any workarounds.
jguinch Posted March 12, 2018 Posted March 12, 2018 It works for me - I made some few changes, just to use the native WinAPIProc.au3 instead of ProcessEx.au3. The code I used : expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Change2CUI=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #NoTrayIcon #include <ProcessConstants.au3> #include <AutoItConstants.au3> #include <WinAPIProc.au3> If $CmdLine[0] <> 3 Then ConsoleWrite("Command line error") Exit 1 EndIf $iPID = RunAs($CmdLine[2], "", $CmdLine[3], 1, $CmdLine[1], "", "", $STDERR_MERGED) If @error Then ConsoleWrite("Unable to run the program. Please check the syntax and/or the credentials") Exit 1 EndIf Local $output = "", $err = "", $cmd= $CmdLine[1], $user=$CmdLine[2], $pass=$CmdLine[3] $iPID = RunAs($user, "", $pass, 4, $cmd, "", @SW_HIDE, $STDERR_MERGED) Local $output ; Get the handle of the process Local $hProcess = _WinAPI_OpenProcess($PROCESS_QUERY_LIMITED_INFORMATION, 0, $iPID) While ProcessExists($iPID) ; Capture the output $output &= StdoutRead($iPID) ; Don't kill the CPU Sleep(100) WEnd ; Capture any remaining output $output &= StdoutRead($iPID) ; Get the exit code from the process handle, so that this AutoIt executable can exit with the same exit code $exitCode = _WinAPI_GetExitCodeProcess($hProcess) ; Write the output from running the command back out, so whoever is watching for the RunAs output can consume it ConsoleWrite($output) Exit($exitCode) And the result : Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
MarkBlakley Posted March 13, 2018 Author Posted March 13, 2018 Thank you jguinch! I was not aware of the WinAPIProc and WinAPI native includes. This gets me closer, but not quite there yet. I'm able to get the exit code and the output when running commands, but I'm still seeing that certain commands are failing to run. A simple example of something that isn't working is xcopy, even when trying to copy a file to a location that doesn't require Admin privileges. > AutoItRunAs.exe "xcopy D:\myfile\test.txt D:\ /Y /A /H /E" Administrator AdminPass I get an exit code of 0, but I also don't get any console output (normally I would get the file name and "1 file copied" message), and the file doesn't actually get copied. If I run the xcopy command in a non-Admin command prompt, I get the expected console output and exit code, and the file gets copied correctly. If I try to use the AutoItRunAs tool to xcopy the file to a location that requires Admin privileges, it behaves the same way as above (no output, exit code 0, file doesn't get copied). If I run the xcopy command from command line, I get the file name and "Access Denied" written to console output, with an exit code of 4 as expected. > AutoItRunAs.exe "xcopy D:\myfile\test.txt C:\ /Y /A /H /E" Administrator AdminPass Maybe it's something different with my environment? Any chance that you can try it out and see if you get different results?
jguinch Posted March 13, 2018 Posted March 13, 2018 After some tests, I see that the xcopy command does not work with either $STDERR_MERGED, $STDERR_CHILD or STDOUT_CHILD. It works with $RUN_CREATE_NEW_CONSOLE but seems to not allow me to retrieve the output stream. Finally, it seems that there is a issue when I read the xcopy output stream. Try this : #include <AutoItConstants.au3> Local $commands = [@ComSpec & " /c echo test", @ComSpec & " /c xcopy /?"] For $i = 0 To UBound($commands) - 1 ConsoleWrite(@CRLF & "# Running command : " & $commands[$i] & @CRLF) $pid = Run($commands[$i], "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD ) ProcessWaitClose($pid) ConsoleWrite("output : " & StdoutRead($pid) & "[" & @error & "]" & @CRLF) Next The output stream cannot be retrieved with a simple Run(), so no way for RunAs. Maybe there is an option I didn't try, but it seems we cannot do that. Another way could be to use the output redirection ">". I managed to get it work with it : #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Change2CUI=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #NoTrayIcon #include <File.au3> If $CmdLine[0] <> 3 Then ConsoleWrite("Command line error") Exit 1 EndIf Local $sTempFile = _TempFile() Local $err Local $cmd = @ComSpec & ' /c ' & $CmdLine[1] & ' > "' & $sTempFile & '"' Local $user=$CmdLine[2], $pass=$CmdLine[3] $iExitCode = RunAsWait($user, "", $pass, 4, $cmd, "", @SW_HIDE) If @error Then ConsoleWrite("Unable to run the program. Please check the syntax and/or the credentials") Exit 1 EndIf Local $sOutput = FileRead($sTempFile) FileDelete($sOutput) ConsoleWrite($sOutput) Exit($iExitCode) Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
MarkBlakley Posted March 15, 2018 Author Posted March 15, 2018 Thanks for trying this, and glad that it wasn't just me! I'm planning to run some more tests to figure out if xcopy is just special, or if it has to do with write permissions when used by any tool (copy, robocopy, etc). I'll reply with more info after I've had a chance to look at those cases.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now