web-dev-qa-db-ja.com

Pythonスクリプト?

PythonスクリプトでVistaにファイルをコピーします。通常のcmd.exeウィンドウから実行すると、エラーは生成されませんが、ファイルはコピーされません。cmd.exeを「管理者として」実行するとその後、スクリプトを実行すると、正常に動作します。

これは、ユーザーアカウント制御(UAC)が多くのファイルシステムアクションを通常防止するためです。

Pythonスクリプトから、UACの昇格要求を呼び出すことができる方法はありますか(「このようなアプリには管理者アクセスが必要です。これでいいですか?」)

それが不可能な場合、スクリプトが昇格していないことを少なくとも検出できるため、正常に失敗する方法はありますか?

78
jwfearn

2017年現在、これを実現する簡単な方法は次のとおりです。

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, __file__, None, 1)

Python 2.xを使用している場合、最後の行を次のように置き換える必要があります。

ctypes.windll.Shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

また、変換した場合pythonスクリプトを実行可能ファイルに(py2execx_freezepyinstaller)次に、4番目のパラメーターを空の文字列("")。

ここでの利点のいくつかは次のとおりです。

  • 外部ライブラリは必要ありません(Windows拡張機能の場合はPython)。標準ライブラリのctypesのみを使用します。
  • Python 2とPython 3。
  • ファイルリソースを変更したり、マニフェストファイルを作成したりする必要はありません。
  • If/elseステートメントの下にコードを追加しない場合、コードが2回実行されることはありません。
  • ユーザーがUACプロンプトを拒否した場合、特別な動作を行うように簡単に変更できます。
  • 4番目のパラメーターを変更する引数を指定できます。
  • 6番目のパラメーターを変更する表示方法を指定できます。

基礎となるShellExecute呼び出しのドキュメントは here です。

72

Dguaragliaの回答を機能させるには少し時間がかかりました。他の人の時間を節約するために、このアイデアを実装するために以下のことを行いました。

import os
import sys
import win32com.Shell.shell as Shell
ASADMIN = 'asadmin'

if sys.argv[-1] != ASADMIN:
    script = os.path.abspath(sys.argv[0])
    params = ' '.join([script] + sys.argv[1:] + [ASADMIN])
    Shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params)
    sys.exit(0)
64
Jorenko

特定のタスクを実行するために、しばらくの間アプリケーション権限を昇格させる方法はないようです。 Windowsは、アプリケーションが特定の特権を必要とするかどうかをプログラムの開始時に知る必要があり、アプリケーションがneedのタスクを実行するタイミングを確認するようユーザーに求めますそれらの特権。これを行うには2つの方法があります。

  1. アプリケーションにいくつかの特権が必要な場合があることをWindowsに通知するマニフェストファイルを作成する
  2. 別のプログラム内から昇格した特権でアプリケーションを実行する

この twoarticles は、これがどのように機能するかをより詳細に説明しています。

CreateElevatedProcess APIの厄介なctypesラッパーを作成したくない場合は、コードプロジェクトの記事で説明されているShellExecuteExトリックを使用します(Pywin32にはShellExecuteのラッパーが付属しています)。どうやって?このようなもの:

プログラムは、起動時に管理者権限があるかどうかを確認し、実行されていない場合はShellExecuteトリックを使用して実行され、すぐに終了します。実行されている場合は、タスクを実行します。

あなたのプログラムを「スクリプト」として説明するとき、私はそれであなたのニーズに十分だと思います。

乾杯。

29
dguaraglia

この質問は数年前に尋ねられたことを認識しており、よりエレガントなソリューションが github でモジュールpyminutilsを使用してfrmdstryrによって提供されていると思います:

抜粋:

import pythoncom
from win32com.Shell import Shell,shellcon

def copy(src,dst,flags=shellcon.FOF_NOCONFIRMATION):
    """ Copy files using the built in Windows File copy dialog

    Requires absolute paths. Does NOT create root destination folder if it doesn't exist.
    Overwrites and is recursive by default 
    @see http://msdn.Microsoft.com/en-us/library/bb775799(v=vs.85).aspx for flags available
    """
    # @see IFileOperation
    pfo = pythoncom.CoCreateInstance(Shell.CLSID_FileOperation,None,pythoncom.CLSCTX_ALL,Shell.IID_IFileOperation)

    # Respond with Yes to All for any dialog
    # @see http://msdn.Microsoft.com/en-us/library/bb775799(v=vs.85).aspx
    pfo.SetOperationFlags(flags)

    # Set the destionation folder
    dst = Shell.SHCreateItemFromParsingName(dst,None,Shell.IID_IShellItem)

    if type(src) not in (Tuple,list):
        src = (src,)

    for f in src:
        item = Shell.SHCreateItemFromParsingName(f,None,Shell.IID_IShellItem)
        pfo.CopyItem(item,dst) # Schedule an operation to be performed

    # @see http://msdn.Microsoft.com/en-us/library/bb775780(v=vs.85).aspx
    success = pfo.PerformOperations()

    # @see sdn.Microsoft.com/en-us/library/bb775769(v=vs.85).aspx
    aborted = pfo.GetAnyOperationsAborted()
    return success is None and not aborted    

これはCOMインターフェースを利用し、管理者権限が必要なディレクトリにコピーしていた場合に表示されるよく知られたダイアログプロンプトで管理者権限が必要であることを自動的に示し、コピー操作中の典型的なファイル進行ダイアログも提供します。

4
KenV99

次の例は、MARTIN DE LA FUENTE SAAVEDRA's優れた作業と受け入れられた回答に基づいています。特に、2つの列挙が導入されています。 1つ目は、昇格されたプログラムをどのように開くかを簡単に指定できるようにし、2つ目はエラーを簡単に特定する必要があるときに役立ちます。すべてのコマンドライン引数を新しいプロセスに渡す場合は、_sys.argv[0]_を関数呼び出しsubprocess.list2cmdline(sys.argv)で置き換える必要があることに注意してください。

_#! /usr/bin/env python3
import ctypes
import enum
import subprocess
import sys

# Reference:
# msdn.Microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx


# noinspection SpellCheckingInspection
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:
       # noinspection SpellCheckingInspection
        hinstance = ctypes.windll.Shell32.ShellExecuteW(
            None,
            'runas',
            sys.executable,
            subprocess.list2cmdline(sys.argv),
            None,
            SW.SHOWNORMAL
        )
        if hinstance <= 32:
            raise RuntimeError(ERROR(hinstance))


def main():
    # Your Code Here
    print(input('Echo: '))


if __== '__main__':
    bootstrap()
_
3
Noctis Skytower

これはあなたの質問に完全には答えないかもしれませんが、昇格したUAC特権でスクリプトを実行するために、Elevate Command Powertoyを使用してみることもできます。

http://technet.Microsoft.com/en-us/magazine/2008.06.elevation.aspx

それを使用すると、「elevate python yourscript.py」のように見えると思います

2
TinyGrasshopper

上記のJorenkoの作業のバリエーションにより、昇格したプロセスで同じコンソールを使用できます(ただし、以下のコメントを参照してください)。

def spawn_as_administrator():
    """ Spawn ourself with administrator rights and wait for new process to exit
        Make the new process use the same console as the old one.
          Raise Exception() if we could not get a handle for the new re-run the process
          Raise pywintypes.error() if we could not re-spawn
        Return the exit code of the new process,
          or return None if already running the second admin process. """
    #pylint: disable=no-name-in-module,import-error
    import win32event, win32api, win32process
    import win32com.Shell.shell as Shell
    if '--admin' in sys.argv:
        return None
    script = os.path.abspath(sys.argv[0])
    params = ' '.join([script] + sys.argv[1:] + ['--admin'])
    SEE_MASK_NO_CONSOLE = 0x00008000
    SEE_MASK_NOCLOSE_PROCESS = 0x00000040
    process = Shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params, fMask=SEE_MASK_NO_CONSOLE|SEE_MASK_NOCLOSE_PROCESS)
    hProcess = process['hProcess']
    if not hProcess:
        raise Exception("Could not identify administrator process to install drivers")
    # It is necessary to wait for the elevated process or else
    #  stdin lines are shared between 2 processes: they get one line each
    INFINITE = -1
    win32event.WaitForSingleObject(hProcess, INFINITE)
    exitcode = win32process.GetExitCodeProcess(hProcess)
    win32api.CloseHandle(hProcess)
    return exitcode
1
Berwyn

どこかでショートカットを作成し、ターゲットとして使用することができます:python yourscript.pyその後、プロパティと高度な選択で管理者として実行します。

ユーザーがショートカットを実行すると、アプリケーションを昇格するように求められます。

1
officialhopsof

これは主にJorenkoの回答のアップグレードであり、Windowsでスペースを使用してパラメーターを使用できますが、Linuxでもかなりうまく機能するはずです:)また、__file__しかしsys.argv[0]実行可能ファイルとして

import sys,ctypes,platform

def is_admin():
    try:
        return ctypes.windll.Shell32.IsUserAnAdmin()
    except:
        raise False

if __== '__main__':

    if platform.system() == "Windows":
        if is_admin():
            main(sys.argv[1:])
        else:
            # Re-run the program with admin rights, don't use __file__ since py2exe won't know about it
            # Use sys.argv[0] as script path and sys.argv[1:] as arguments, join them as lpstr, quoting each parameter or spaces will divide parameters
            lpParameters = ""
            # Litteraly quote all parameters which get unquoted when passed to python
            for i, item in enumerate(sys.argv[0:]):
                lpParameters += '"' + item + '" '
            try:
                ctypes.windll.Shell32.ShellExecuteW(None, "runas", sys.executable, lpParameters , None, 1)
            except:
                sys.exit(1)
    else:
        main(sys.argv[1:])
1
Orsiris de Jong

スクリプトに常に管理者権限が必要な場合:

runas /user:Administrator "python your_script.py"
1
jfs