Introduction
We often find ourselves needing to automate tasks on Windows machine, Although there are many Python libraries out there that supports some common Windows operations and even cross-platforms. It is really hard to substitute Window’s Command Prompt and PowerShell, as they are extremely useful in cases where we need to access different Windows components, configure settings and troubleshooting.
User Account Control (UAC)
Standard user accounts are for day-to-day activities with less permission, while the administrator account has elevated access for all features.
For my personal machine, I’m operating on admin account all time (as the sole user). But Windows, for security reasons, still treats most of my actions as standard account. It only elevates to admin privilege when my operations want to make internal changes to Windows settings and my machine.
The UAC feature when enabled, prompts the user when such action occurred and request for admin access. Additionally, for standard user, it means they need to ask for administrator account login.
When the sign in is an administrator type account |
When the sign in is a standard type account |
Now, in terms of task automation in Python, we’ll also want to figure out how to run certain operations with Admin privilege.
Using subprocess
Like most of us, I have been using subprocess
to evoke cmd.exe
or powershell.exe
as desired
by passing arguments as list into the function.
- Command Prompt:
command = ['cmd.exe', '/c', <argument>]
- PowerShell:
command = ['powershell.exe', '-command', <argument>]
1 | import subprocess |
But this doesn’t grant the process with admin privilege, and won’t notify us with UAC.
How to achieve this? here are some ways to do it.
Using ShellExecute runas
1 | import ctypes |
runas
from the Windows API
launches an application as Administrator.
User Account Control (UAC) will prompt the user for consent to run the application
elevated or enter the credentials of an administrator account used to run the application.
What about a more pythonic approach?
Using runas
in Command Prompt
runas
application runs command
as a different user; it is most commonly used but not limited to perform operation
with administrator account for granting admin access.
Note: the password is handled outside UAC, which may not be the desired behavior
1 | command = ['cmd.exe', '/c', 'runas', '/user:administrator', 'regedit'] |
Using PowerShell -Verb Runas
This is my preferred method, since it is most flexible and also evokes UAC for admin access.
-
Start-Process
1
Start-Process <executable> -argumentlist <arugments> -Verb Runas
-
Call operator (&)
by adding call operator, we are able to run commands not limited in the environment path, also not need to worry about spaces in our path.
1
& {Start-Process <executable> -argumentlist <arugments> -Verb Runas}
-
-ExecutionPolicy Bypass
Sometimes, a security setting will prevent PowerShell running a .ps1 file, and we’ll need to bypass execution policy:
1
Start-Process <executable> -ExecutionPolicy Bypass -File <file>
It is very obvious from the above example, we can basically use PowerShell to wrap around anything, including Command Prompt.
1 | Start-Process cmd.exe -argumentlist '/k "dir"' -Verb Runas |
To bundle everything together, a working example would look like this in Python:
1 | ps_command = "& {{Start-Process cmd.exe -argumentlist '/k \"dir\"' -Verb Runas}}" |
essentially using subprocess
to run PowerShell in admin using -Verb Runas
to execute command /k dir
in Command Prompt (which also has elevated access).
Redirect Output
By doing the above, we are running an executable within a process. the sacrifice is that it is difficult to pass the output, but here’s a few workarounds:
Output results to a file
1 | Start-Process cmd.exe -argumentlist '/c "dir"' -redirectStandardOutput "C:\Users\xlei\Desktop\temp.txt" |
Output result to the console
Just the exit code:
1 | output = Start-Process cmd.exe -argumentlist '/c "dir"' -PassThru -Wait |
A neat function I found here
1 | function Start-ProcessWithOutput |
Run Python as Admin
Running the whole python script in Admin, meaning that the subsequent processes will have admin access, if this is the behaviour you prefer.
References
Stack Exchange - Run .exe file via Python as Administrator
Stack Overflow - How do I capture the output into a variable from an external process in PowerShell?
Stack Overflow - Redirection of standard and error output appending to the same log file
Stack Overflow - Powershell: Capturing standard out and error with Process object
Windows Commandline - Windows runas command syntax and examples