Issue
I'm attempting to create a utility tool via Python 3.x for the Windows 10 command-line. Since it will better format general command-line commands into more user-friendly menus, I want it to require elevated permissions through UAC when it runs.
I'm using the ctypes
method described here, and it does indeed have Python's executable request UAC elevation.
However, since a lot of the things I'll be writing menus and the like for will require (or be heavily limited without) these elevated permissions, I want the script to exit (preferably through sys.exit
) if it doesn't find any.
In the ctypes
method I mentioned, it should run as follows;
It defines a function
is_admin()
, which gets the value ofctypes.windll.shell32.IsUserAnAdmin()
, and if it's 0, returns false instead.is_admin()
is called in a conditional, and if it gets false, it attempts to execute the command-line command to re-run the script as an executable usingShellExecuteW
and some variables fromsys
;ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv[0]), None, 1)
In my code, I have the above conditional with the addition of a variable elevReq
that I set to true;
if is_admin():
success("Already running as administrator!") # "success" and "warn" are defined earlier
elevReq = True
else:
warn("Requesting administrative permissions...", False)
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv[0]), None, 1)
elevReq = True
I follow it up with another conditional that checks to see if elevReq
is true and is_admin()
is false, to see if the user selected "no" on UAC's pop-up -- if it is, it should throw an error about the lack of elevated privileges, and then quit;
if elevReq and is_admin() == False:
error("[FATAL] Elevation was not given! Stopping...", True)
sys.exit(1)
The problem I'm having is that the given method doesn't seem to actually be elevating permissions of Python. UAC does pop up, but when any option is selected, it doesn't seem to matter, as the above condition fires anyway. Manually running the script in an elevated command prompt from the start doesn't have this issue.
Is this an issue with the script not re-loading when it should? If not, why is it exiting anyway?
Solution
The ShellExecute API call will spawn a new process, it won't elevate permissions for the current process running.
Let's analyze this code snippet:
if is_admin():
main()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
When you first run this Python script without privileges, this initial process will jump to the last line of the code because is_admin
returns False
. Once there, the UAC prompt is displayed.
- If the UAC prompt is accepted, then a completely new process (with different process ID) is created and the code is executed again (from the beginning), but this time with admin privileges. Now
is_admin
should returnTrue
andmain
should be called. - If the UAC prompt is rejected, no new process is created.
Regardless of the UAC response, the initial process will get the return code back, but its privileges will remain unaltered.
If you want to try this yourself, add an input()
at the end of the file and you should be able to see two different windows after accepting the UAC prompt.
To avoid having your code being executed twice be sure to keep everything inside the main
function. If you want to take an action based on the return code, this only makes sense for failures (code <= 32). If the return code is successfull (> 32), then the process should end gracefully and let the new spawned process do its job.
Answered By - Martín De la Fuente
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.