-
-
Save Preston-Landers/267391562bc96959eb41 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python | |
# -*- coding: utf-8; mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- | |
# vim: fileencoding=utf-8 tabstop=4 expandtab shiftwidth=4 | |
""" | |
THIS CODE IS OUTDATED! Please use this instead: | |
https://pypi.org/project/pyuac/ | |
https://github.com/Preston-Landers/pyuac | |
-- old comments follow: | |
User Access Control for Microsoft Windows Vista and higher. This is | |
only for the Windows platform. | |
This will relaunch either the current script - with all the same command | |
line parameters - or else you can provide a different script/program to | |
run. If the current user doesn't normally have admin rights, he'll be | |
prompted for an admin password. Otherwise he just gets the UAC prompt. | |
Note that the prompt may simply shows a generic python.exe with "Publisher: | |
Unknown" if the python.exe is not signed. | |
This is meant to be used something like this:: | |
if not pyuac.isUserAdmin(): | |
return pyuac.runAsAdmin() | |
# otherwise carry on doing whatever... | |
See L{runAsAdmin} for the main interface. | |
""" | |
import sys, os, traceback, types | |
def isUserAdmin(): | |
"""@return: True if the current user is an 'Admin' whatever that | |
means (root on Unix), otherwise False. | |
Warning: The inner function fails unless you have Windows XP SP2 or | |
higher. The failure causes a traceback to be printed and this | |
function to return False. | |
""" | |
if os.name == 'nt': | |
import ctypes | |
# WARNING: requires Windows XP SP2 or higher! | |
try: | |
return ctypes.windll.shell32.IsUserAnAdmin() | |
except: | |
traceback.print_exc() | |
print "Admin check failed, assuming not an admin." | |
return False | |
else: | |
# Check for root on Posix | |
return os.getuid() == 0 | |
def runAsAdmin(cmdLine=None, wait=True): | |
"""Attempt to relaunch the current script as an admin using the same | |
command line parameters. Pass cmdLine in to override and set a new | |
command. It must be a list of [command, arg1, arg2...] format. | |
Set wait to False to avoid waiting for the sub-process to finish. You | |
will not be able to fetch the exit code of the process if wait is | |
False. | |
Returns the sub-process return code, unless wait is False in which | |
case it returns None. | |
@WARNING: this function only works on Windows. | |
""" | |
if os.name != 'nt': | |
raise RuntimeError, "This function is only implemented on Windows." | |
import win32api, win32con, win32event, win32process | |
from win32com.shell.shell import ShellExecuteEx | |
from win32com.shell import shellcon | |
python_exe = sys.executable | |
if cmdLine is None: | |
cmdLine = [python_exe] + sys.argv | |
elif type(cmdLine) not in (types.TupleType,types.ListType): | |
raise ValueError, "cmdLine is not a sequence." | |
cmd = '"%s"' % (cmdLine[0],) | |
# XXX TODO: isn't there a function or something we can call to massage command line params? | |
params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]]) | |
cmdDir = '' | |
showCmd = win32con.SW_SHOWNORMAL | |
lpVerb = 'runas' # causes UAC elevation prompt. | |
# print "Running", cmd, params | |
# ShellExecute() doesn't seem to allow us to fetch the PID or handle | |
# of the process, so we can't get anything useful from it. Therefore | |
# the more complex ShellExecuteEx() must be used. | |
# procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd) | |
procInfo = ShellExecuteEx(nShow=showCmd, | |
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, | |
lpVerb=lpVerb, | |
lpFile=cmd, | |
lpParameters=params) | |
if wait: | |
procHandle = procInfo['hProcess'] | |
obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) | |
rc = win32process.GetExitCodeProcess(procHandle) | |
#print "Process handle %s returned code %s" % (procHandle, rc) | |
else: | |
rc = None | |
return rc | |
def test(): | |
"""A simple test function; check if we're admin, and if not relaunch | |
the script as admin.""", | |
rc = 0 | |
if not isUserAdmin(): | |
print "You're not an admin.", os.getpid(), "params: ", sys.argv | |
#rc = runAsAdmin(["c:\\Windows\\notepad.exe"]) | |
rc = runAsAdmin() | |
else: | |
print "You are an admin!", os.getpid(), "params: ", sys.argv | |
rc = 0 | |
x = raw_input('Press Enter to exit.') | |
return rc | |
if __name__ == "__main__": | |
res = test() | |
sys.exit(res) |
Hi everyone! I've cleaned up this code and packaged it into a library you can install with pip install pyuac
.
It also fixes some bugs around command line handling.
https://pypi.org/project/pyuac/
https://github.com/Preston-Landers/pyuac
@Preston-Landers thanks for the work, haven't tried that yet, there could be some handling or log around failed to execute as Admin, hInstApp
hold those info.
@AndCycle I'm not sure I follow. This uses PyWin32's wrapper around ShellExecuteEx
. That way that is structured, we only get access to hInstApp
in the success case. In the failure case it raises pywintypes.error
. For instance, if you deny the UAC prompt, the script gets a catchable exception like:
pywintypes.error: (1223, 'ShellExecuteEx', 'The operation was canceled by the user.')
You're welcome to open an issue in the new Github project. Thanks.
@thewatsa - actually see @golflima version above that has been fixed for Python 3. I'm still planning to publish an updated version on PyPI at some point.