Статья Запускаем скрипт Python от имени администратора в Windows

Иногда, для того чтобы выполнить скрипт на Python нам нужны права администратора. В противном случае, никаких предупреждений от операционной системы вы не увидите, просто будет запрещен доступ на выполнение тех или иных действий. Как пример, могу привести изменение/создание ключа реестра в статье «Изменение MAC-адреса в Linux и Windows с помощью Python». И тогда нужно будет запустить все еще раз, но уже с правами администратора или суперпользователя в Linux.

000.jpg

А как бы сделать так, чтобы скрипт сам проверял, запущена ли оболочка командной строки от имени администратора или нет, и если нет, перезапускал бы скрипт, но уже в оболочке, запущенной с правами администратора?

Вот, что произойдет, если запустить скрипт из статьи указанной выше без прав администратора в Windows:

001.png

И под Linux:

002.png

Для Windows есть довольно простое решение. Давайте рассмотрим его подробнее.

Для начала нам нужно будет импортировать несколько модулей:

Python:
import ctypes
import sys

import psutil

В том же случае, если интерпретатор заругается и скажет, что у вас не установлен модуль psutil, его надо установить с помощью команды:

pip install psutil

Теперь пишем код который выполнит проверку, запущена ли программа от имени админа или нет, как раз перед тем, как выполнять проверку на имя программы. В этом коде делается проверка, запущена ли оболочка с правами администратора. Если да, то проверка вернет True и запустить функция main(). В противном случае, перезапускается процесс с именем запускаемого файла и повышением прав до администратора. Если у вас не отключен UAC, то нужно будет подтвердить запуск.

Python:
if ctypes.windll.shell32.IsUserAnAdmin():
    if __name__ == "__main__":
        main()
else:
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)

И все будет работать. Но, тут есть небольшой нюансик. Так как скрипт перезапускается, то остается открытым то окно из которого он запускался изначально. И это не есть хорошо. Можно его закрыть вручную, но если уж автоматизировать, то нужно двигаться дальше. После запука с правами админа нужно будет закрыть окно Командной строки или PowerShell, из которой и запускался изначально скрипт на Python.

Здесь нужно «прибить» сам процесс. И логичнее всего сделать это получив его PID. Собственно PID это идентификатор процесса и является уникальным номером, который присваивается процессу на этапе выполнения. Возникает вопрос, а как этот PID получить? И вот тут на помощь нам придет модуль psutil.

Давайте напишем небольшую функцию для примера, как работает код. Запускаем цикл, в котором пробегаемся по каждому экземпляру объекта созданного psutil и отфильтрованного по значениям pid и name. Где name, это имя запущенного процесса. Не заголовок программы, а именно имя процесса. Далее, в переменную sys_app получаем значение экземпляра с именем, которое обрезаем от лишних точек, так как имя процесса будет выглядеть, к примеру, «cmd.exe». Берем первый элемент получившегося списка и приводим его, на всякий случай к нижнему регистру.

Затем делаем проверку, является ли полученное имя процесса PowerShell или Командной строкой. Так же можно добавить и проверку на то, является ли процесс Windows Terminal. И если это так, запускается процесс в котором получаем pid запущенного приложения и с помощью функции terminate() его завершаем.

Если же запущенный процесс не подходит по нужные параметры, не делаем ничего и продолжаем выполнение цикла.

Python:
def printing():
    print('Тут мы чего-то печатаем, якобы с правами админа.')
    for app in psutil.process_iter(['pid', 'name']):
        sys_app = app.info.get('name').split('.')[0].lower()
        if 'powershell' in sys_app or 'cmd' in sys_app:
            try:
                psutil.Process(app.info.get('pid')).terminate()
                break
            except:
                continue
    input()

Но, будьте внимательны. Данный код "прибьёт" первый процесс, который будет найден. То есть тот, что запущен позже всех. Если вы запустите скрипт в процессе, который был запущен ранее, то он "прибит" не будет. А если убрать прерывание break в цикле, в этом случае будут "прибиты" все процессы.

Вот полный код скрипта по перезапуску командной строки в режиме администратора. Еще раз хочу сказать, что данный скрипт работает только в Windows и его можно вставить в свою программу, в которой требуется повышение привилегий.

Python:
import ctypes
import sys

import psutil


def printing():
    print('Тут мы чего-то печатаем, якобы с правами админа.')
    for app in psutil.process_iter(['pid', 'name']):
        sys_app = app.info.get('name').split('.')[0].lower()
        if 'powershell' in sys_app or 'cmd' in sys_app:
            try:
                psutil.Process(app.info.get('pid')).terminate()
                break
            except:
                continue
    input()


def main():
    printing()


if ctypes.windll.shell32.IsUserAnAdmin():
    if __name__ == "__main__":
        main()
else:
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)

Для Linux же подобных решений я не нашел. Наткнулся не небольшой модуль elevate. Но, как по мне, он работает несколько кривовато. Слишком много нужно произвести действий для того, чтобы запустить программу с его использованием. Если интересно, то вот код для его запуска:

Python:
import os
from elevate import elevate

def is_root():
    return os.getuid() == 0

print("before ", is_root())
elevate()
print("after ", is_root())

Тут собственно проверяется, запущен ли терминал под пользователем или рутом. И если под пользователем, о чем и сообщает возвращаемый код, запускается модуль elevate. По сути, он запускает запрос пароля в графическом режиме. Впрочем, этот режим можно отключить. Но, тут есть одна проблемка. Или даже не одна. Под пользователем root нужного модуля не найдется, так как он не установлен. Дальше, даже если вы установите этот модуль, вас ждет разочарование, так как перезапустившись в терминале под рутом вы получите сообщение, что скрипт, который вы запускаете, не найдет. И да, он не будет найден, потому, что вы запускали его от другого пользователя. И он лежит в другом месте. В этом случае нужно будет запускать скрипт с указанием полного пути к скрипту. Что очень неудобно. Проще, как на мой взгляд, просто выполнить тогда повышение привилегий до рута с помощью sudo su, а дальше уж злодействовать как пожелаете.

Ну или есть еще одно решение. Можно установить terminator. Это оболочка, которая при запуске будет запрашивать у вас пароль суперпользователя. То есть, выполнять повышение привилегий. И уже в дальнейшем все команды будут от имени суперпользователя. Это, даже судя по его названию, эмулятор терминала суперпользователя.

003.png

Спасибо за внимание. Надеюсь, что данная информация была кому-нибудь полезна
 
Последнее редактирование:

Chekist_

Green Team
16.04.2017
21
4
Спасибо за статью. Новичку в этом деле, было интересно почитать. (особенно прикольное использование модуля os).
 
  • Нравится
Реакции: Johan Van
Мы в соцсетях: