Windows下Python脚本如何中途取消管理员权限运行
Got it, here's how to handle this scenario on Windows—since you can't directly drop privileges in the same running process (Windows locks in a process's security context at creation), you'll need to spawn a new subprocess using the logged-in non-admin user's token. This lets you run your restricted tasks without any user interaction.
Key Background
Windows processes inherit their security token when they're launched. To run code as a non-admin after starting as admin, you have to:
- Grab the token of the currently logged-in interactive non-admin user (since your elevated CMD is running in the same user session).
- Spawn a new Python subprocess using that token to execute your non-admin code.
Prerequisites
First, install the pywin32 package to access Windows API functions:
pip install pywin32
Full Implementation
Here's a complete example that splits your workflow into admin-only tasks, then spawns a non-admin subprocess for the restricted work:
import subprocess import win32api import win32con import win32event import win32process import win32security from win32ts import WTSGetActiveConsoleSessionId, WTSQueryUserToken def do_stuff_as_admin(): """Run tasks that require elevated privileges.""" print("🔧 Running admin-only tasks...") # Example: Execute an admin-only command subprocess.run(["net", "localgroup", "Administrators"], check=True, text=True) def get_non_admin_user_token(): """Retrieve the access token of the logged-in interactive non-admin user.""" try: # Get the active console session ID (matches the logged-in user's session) session_id = WTSGetActiveConsoleSessionId() # Fetch the user token for this session user_token = WTSQueryUserToken(session_id) return user_token except Exception as e: raise RuntimeError(f"Failed to retrieve non-admin user token: {str(e)}") from e def run_as_non_admin(command: str) -> bool: """Spawn a subprocess using the non-admin user's token.""" user_token = get_non_admin_user_token() startup_info = win32process.STARTUPINFO() proc_info = win32process.PROCESS_INFORMATION() try: # Create the subprocess with the non-admin token win32process.CreateProcessAsUser( user_token, None, # Let Windows resolve the executable path from the command command, None, # Process security attributes (inherit parent) None, # Thread security attributes (inherit parent) False, # Don't inherit handles from parent win32con.CREATE_NEW_CONSOLE | win32con.NORMAL_PRIORITY_CLASS, None, # Environment variables (use user's env) None, # Working directory (use user's default) startup_info, proc_info ) # Wait for the subprocess to finish and check exit code win32event.WaitForSingleObject(proc_info.hProcess, win32event.INFINITE) exit_code = win32process.GetExitCodeProcess(proc_info.hProcess) return exit_code == 0 finally: # Clean up handles to avoid resource leaks win32api.CloseHandle(proc_info.hProcess) win32api.CloseHandle(proc_info.hThread) win32api.CloseHandle(user_token) if __name__ == "__main__": # Step 1: Run admin tasks first do_stuff_as_admin() # Step 2: Run non-admin tasks in a separate subprocess print("\n🔄 Switching to non-admin context...") # Option 1: Run a separate script file (cleaner for complex tasks) # success = run_as_non_admin("python.exe non_admin_tasks.py") # Option 2: Run inline code (no extra file needed) non_admin_code = ''' print("✅ Running as non-admin: accessing mapped drives...") import subprocess # Example: List contents of a mapped network drive (Z:) subprocess.run(["dir", "Z:"], check=True, text=True) ''' success = run_as_non_admin(f'python.exe -c "{non_admin_code}"') if success: print("\n🎉 All tasks completed successfully!") else: print("\n❌ Non-admin tasks failed.")
Important Notes
- Session Handling: This uses
WTSGetActiveConsoleSessionId()to target the physical console user. If you're running via Remote Desktop, you might need to adjust how you fetch the session ID (usewin32ts.WTSQuerySessionInformationto list active sessions if needed). - Token Permissions: The
WTSQueryUserTokenfunction requires your elevated process to have theSE_TCB_NAMEprivilege. This is typically granted to admin processes, but if you run into issues, you can explicitly enable it usingwin32security.AdjustTokenPrivileges. - Mapped Drives: Non-admin subprocesses will have access to the user's mapped network drives because they run in the user's session context—elevated processes can't see these by default, which is why your original code failed here.
- No User Input: This method doesn't require any clicks or password entry, since we're directly using the user's existing session token.
Alternative: Split Your Script
If your non-admin tasks are complex, it's cleaner to split them into a separate script (like non_admin_tasks.py) instead of using inline code. Just pass the script path to run_as_non_admin() as shown in Option 1.
内容的提问来源于stack exchange,提问作者Aviv Cohn




