You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows下Python脚本如何中途取消管理员权限运行

How to Drop Admin Privileges Mid-Script in Windows Python (Automated, No User Input)

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:

  1. Grab the token of the currently logged-in interactive non-admin user (since your elevated CMD is running in the same user session).
  2. 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 (use win32ts.WTSQuerySessionInformation to list active sessions if needed).
  • Token Permissions: The WTSQueryUserToken function requires your elevated process to have the SE_TCB_NAME privilege. This is typically granted to admin processes, but if you run into issues, you can explicitly enable it using win32security.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

火山引擎 最新活动