Request UAC elevation from within a Python script?
As of 2017, an easy method to achieve this is the following:
import ctypes, sys
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
# Code of your program here
else:
# Re-run the program with admin rights
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
If you are using Python 2.x, then you should replace the last line for:
ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(" ".join(sys.argv)), None, 1)
Also note that if you converted you python script into an executable file (using tools like py2exe
, cx_freeze
, pyinstaller
) then you should use sys.argv[1:]
instead of sys.argv
in the fourth parameter.
Some of the advantages here are:
- No external libraries required. It only uses
ctypes
andsys
from standard library. - Works on both Python 2 and Python 3.
- There is no need to modify the file resources nor creating a manifest file.
- If you don't add code below if/else statement, the code won't ever be executed twice.
- You can get the return value of the API call in the last line and take an action if it fails (code <= 32). Check possible return values here.
- You can change the display method of the spawned process modifying the sixth parameter.
Documentation for the underlying ShellExecute call is here.
How do I run a script with elevated UAC permissions using ctypes?
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.
How to run script with elevated privilege on windows
Thank you all for your reply. I have got my script working with the module/ script written by Preston Landers way back in 2010. After two days of browsing the internet I could find the script as it was was deeply hidden in pywin32 mailing list. With this script it is easier to check if the user is admin and if not then ask for UAC/ admin right. It does provide output in separate windows to find out what the code is doing. Example on how to use the code also included in the script. For the benefit of all who all are looking for UAC on windows have a look at this code. I hope it helps someone looking for same solution. It can be used something like this from your main script:-
import admin
if not admin.isUserAdmin():
admin.runAsAdmin()
The actual code is:-
#!/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
# (C) COPYRIGHT © Preston Landers 2010
# Released under the same license as Python 2.6.5
import sys, os, traceback, types
def isUserAdmin():
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
elif os.name == 'posix':
# Check for root on Posix
return os.getuid() == 0
else:
raise RuntimeError, "Unsupported operating system for this module: %s" % (os.name,)
def runAsAdmin(cmdLine=None, wait=True):
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
#showCmd = win32con.SW_HIDE
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():
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__":
sys.exit(test())
Ask for admin access for a Python function in Windows
The following example builds on Cyrbil's excellent work. In particular, two enumerations are introduced. The first allows for easy specification of how an elevated program is to be opened, and the second helps when errors need to be easily identified. Please note that if you want all command line arguments passed to the new process, sys.argv[0]
should probably be replaced with a function call: subprocess.list2cmdline(sys.argv)
.
#! /usr/bin/env python3
import ctypes
import enum
import sys
# Reference:
# msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx
class SW(enum.IntEnum):
HIDE = 0
MAXIMIZE = 3
MINIMIZE = 6
RESTORE = 9
SHOW = 5
SHOWDEFAULT = 10
SHOWMAXIMIZED = 3
SHOWMINIMIZED = 2
SHOWMINNOACTIVE = 7
SHOWNA = 8
SHOWNOACTIVATE = 4
SHOWNORMAL = 1
class ERROR(enum.IntEnum):
ZERO = 0
FILE_NOT_FOUND = 2
PATH_NOT_FOUND = 3
BAD_FORMAT = 11
ACCESS_DENIED = 5
ASSOC_INCOMPLETE = 27
DDE_BUSY = 30
DDE_FAIL = 29
DDE_TIMEOUT = 28
DLL_NOT_FOUND = 32
NO_ASSOC = 31
OOM = 8
SHARE = 26
def bootstrap():
if ctypes.windll.shell32.IsUserAnAdmin():
main()
else:
hinstance = ctypes.windll.shell32.ShellExecuteW(
None, 'runas', sys.executable, sys.argv[0], None, SW.SHOWNORMAL
)
if hinstance <= 32:
raise RuntimeError(ERROR(hinstance))
def main():
# Your Code Here
print(input('Echo: '))
if __name__ == '__main__':
bootstrap()
Related Topics
How to Cross Compile Python Interpreter for Windows Under Linux
Can't Start Foreman in Heroku Tutorial Using Python
Match a Whole Word in a String Using Dynamic Regex
Checking If a String Can Be Converted to Float in Python
Beyond Top Level Package Error in Relative Import
How to Include a Folder with Cx_Freeze
Http Requests and JSON Parsing in Python
Python: Changes to My Copy Variable Affect the Original Variable
How to Execute a Program from Python? Os.System Fails Due to Spaces in Path
Running a Bash Script from Python
Detect Specific Keypresses in Gui
Distributing Ruby/Python Desktop Apps
Is There a Built-In Function to Print All the Current Properties and Values of an Object
What Does the Slash Mean in Help() Output