Гид по технологиям

Как запускать PowerShell-скрипты через пакетный файл (.bat)

4 min read DevOps Обновлено 02 Dec 2025
Запуск PowerShell через .bat: быстро и безопасно
Запуск PowerShell через .bat: быстро и безопасно

Быстрые ссылки

  • Почему нельзя просто копировать .PS1 и запускать?
  • Шаг 1: Запуск двойным кликом
  • Шаг 2: Обход ExecutionPolicy
  • Шаг 3: Получение прав администратора
  • Шаг 4: Отключение пользовательских профилей PowerShell
  • Готовые .bat-файлы и рекомендации

Для многих операционных задач переносимость PowerShell-скриптов ограничена по соображениям безопасности. Пакетный (.bat) файл рядом со скриптом позволяет аккуратно обойти ряд ограничений без постоянных модификаций настроек системы. Ниже — подробное руководство с примерами, объяснениями, проверками и практическими рекомендациями.

Почему нельзя просто копировать .PS1 и запускать?

Если целевая система не настроена на безопасный запуск произвольных скриптов, вы столкнётесь с комбинацией проблем:

  1. PowerShell по умолчанию не ассоциирован с расширением .PS1. Windows часто связывает .ps1 с блокнотом, чтобы избежать случайного запуска вредоносных скриптов двойным кликом.
  2. ExecutionPolicy по умолчанию запрещает выполнение внешних скриптов. В некоторых версиях Windows политика может полностью блокировать запуск скриптов.
  3. Для части команд нужны права администратора. Даже если учётная запись — член группы Administrators, UAC предотвращает автоматическое повышение прав.
  4. У пользователя может быть кастомный профиль PowerShell, который меняет среду выполнения (переменные, функции, алиасы) и нарушает поведение скрипта.

Эти ограничения важны для безопасности. Мы решаем их локально для временной сессии, не меняя глобальные настройки ОС.

Шаг 1: Запуск двойным кликом

Проблема с ассоциацией .ps1 решается просто: вы запускаете .bat файл двойным кликом. Батник вызывает PowerShell и передаёт путь к .ps1. Чтобы .bat не пересобирать под каждый скрипт, используем самоссылочную переменную %~dpn0, которая даёт диск, путь и имя файла без расширения.

Требование: .bat и .ps1 должны лежать в одном каталоге и иметь одинаковое имя (например, MyScript.bat и MyScript.ps1).

Простейший пример батника:

@ECHO OFF
PowerShell.exe -Command "& '%~dpn0.ps1'"
PAUSE

Разбор строк:

  • @ECHO OFF — отключает отображение команд в окне CMD. Символ @ скрывает саму строку.
  • PowerShell.exe -Command “& ‘%~dpn0.ps1’” — запускает PowerShell и даёт команду выполнить скрипт по пути, вычисляемому через %~dpn0.ps1.
  • PAUSE — ждёт нажатия клавиши, чтобы окно не закрывалось сразу и вы могли увидеть вывод.

Пример сценария и запуска: предположим, что батник и скрипт лежат в D:\Script Lab\MyScript.*. При двойном клике откроется окно PowerShell и будет предпринята попытка выполнить MyScript.ps1.

Обложка: пакетный файл вызывает PowerShell для запуска скрипта

Примечание: если на машине действует строгая ExecutionPolicy или файл помечен как «загруженный из Интернета», базового батника может быть недостаточно.

Демонстрация проблем при простом запуске

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

Ошибка ExecutionPolicy и профиль PowerShell в действии

Ключевые наблюдения из этого вывода:

  • Окно заголовка показывает, что батник успешно вызвал PowerShell.
  • Первая строка вывода сообщает о пользовательском профиле PowerShell — потенциальная проблема №4.
  • Появилась ошибка ExecutionPolicy — проблема №2.
  • Подчёркнутый фрагмент указывает на целевой путь D:\Script Lab\MyScript.ps1 — значит, батник правильно вычисляет путь к скрипту.

Если хотите воспроизвести поведение профиля, добавьте в свой профиль PowerShell строку:

Write-Output 'Custom PowerShell profile in effect!'

Чтобы пометить файл как пришедший извне (для теста ExecutionPolicy), можно добавить Alternate Data Stream Zone.Identifier:

Add-Content -Path 'D:\Script Lab\MyScript.ps1' -Value "[ZoneTransfer]`nZoneId=3" -Stream 'Zone.Identifier'

И удалить метку так:

Clear-Content -Path 'D:\Script Lab\MyScript.ps1' -Stream 'Zone.Identifier'

Шаг 2: Обход ExecutionPolicy

ExecutionPolicy можно изменить только для текущего запуска PowerShell. Это безопасно: вы не меняете глобальные настройки системы, а лишь указываете параметр для новой сессии.

Обновлённая строка в батнике:

PowerShell.exe -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
  • -ExecutionPolicy Bypass позволяет запустить скрипт в новой сессии, игнорируя политику для этого запуска. Изменение действует только для этой запуска.

После этого вы должны получить выполнение скрипта и увидеть его вывод (но возможно всё ещё без повышения привилегий):

Ограниченный пользователь: скрипт выполнился, но без повышения прав

На изображении видно, что скрипт работает, но сообщает, что выполняется в ограниченной сессии. В демонстрационном примере проверка прав делается так:

if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{Write-Output 'Running as Administrator!'} else {Write-Output 'Running Limited!'}
Pause

Обратите внимание: теперь на выводе иногда может быть две паузы — одна из PowerShell-скрипта и одна из батника. Это важно при следующем шаге.

Шаг 3: Получение прав администратора

Если ваш скрипт использует команды, требующие elevation (например, управление службами, редактирование реестра в HKLM, установка программ), нужно запустить PowerShell с правами администратора. Batch/ CMD не умеют инициировать UAC. Но PowerShell умеет через Start-Process с -Verb RunAs.

Идея: первый PowerShell, запущенный батником, вызывает Start-Process для запуска второго PowerShell с -Verb RunAs. Второй экземпляр выполняет .ps1. Получается две сессии: первая инициирует UAC, вторая — исполняет скрипт уже с повышенными правами.

Строка для батника с запуском через UAC:

PowerShell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"

Пояснения:

  • Start-Process PowerShell.exe — запускает новый процесс PowerShell.
  • -ArgumentList содержит параметры для нового процесса: запускаем с -ExecutionPolicy Bypass и указываем -File “%~dpn0.ps1” (двойные кавычки экранированы для корректной передачи).
  • -Verb RunAs инициирует UAC. Если текущая сессия не elevated, появится запрос на повышение.

Поведение при запуске:

  1. Откроется окно PowerShell (первое). Его профиль выполнится.
  2. Появится UAC-подтверждение. После одобрения запустится новый экземпляр PowerShell — второй процесс.
  3. Во втором окне тоже выполняется профиль (если вы не отключили профиль) и затем сам скрипт.

Запрос UAC перед запуском второго PowerShell

После подтверждения вы увидите повышенный сеанс и вывод скрипта:

Запущен с правами администратора: второй процесс PowerShell выполняет скрипт

Почему две паузы? Первая пауза — в теле .ps1 (чтобы пользователь увидел вывод скрипта, пока второй seance открыт). Вторая — в батнике — чтобы вы могли увидеть, что первый запуск PowerShell вообще стартовал, и если запуск второго процесса не удался, увидеть сообщение об ошибке.

Важно: подтверждение UAC запрашивается в контексте текущего пользователя. Если требуется запуск под другой учётной записью, потребуются другие подходы (например, запуск через планировщик задач с сохранёнными учётными данными или использование PSExec/RunAs с учётной записью администратора). Эти методы имеют свои риски и требования безопасности.

Шаг 4: Отключение пользовательских профилей PowerShell

Пользовательские профили PowerShell (файлы profile.ps1) могут менять среду выполнения: создавать алиасы, определять функции, переопределять команды. Чтобы скрипт работал предсказуемо, удобнее запускать PowerShell с ключом -NoProfile.

Измените строку батника так, чтобы оба процесса PowerShell запускались с -NoProfile:

PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"

Если вам не нужен запрос на повышение прав (шаг 3 пропущен), тогда достаточно одной инстанции PowerShell, и строка будет проще:

PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"

Пример вывода для случая без профиля:

Запуск без профиля в ограниченной сессии

Теперь кастомные скрипты профиля не мешают работе, среда более предсказуема, и вы видите только вывод вашего .ps1.

Готовые .bat-файлы

Без повышения прав (подходит для скриптов, не требующих администратора):

@ECHO OFF
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
PAUSE

С повышением прав через UAC:

@ECHO OFF
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
PAUSE

Советы по использованию:

  • Держите .bat и .ps1 вместе и давайте им одно имя. Так %~dpn0 всегда будет указывать на корректный скрипт.
  • Не запрашивайте права администратора, если они не нужны. Минимизируйте поверхность атаки.
  • Для распространения скриптов в организации используйте подписанные скрипты и централизованное управление (GPO, Intune), а не постоянные обходы ExecutionPolicy.

Контрпримеры и ситуации, когда этот подход не работает

  • ExecutionPolicy на уровне Group Policy может запрещать локальные обходы. Политики, установленные через GPO, могут игнорировать ключи запуска.
  • На защищённых системах с ограничёнными правами на запуск исполняемых файлов администрация может блокировать вызов PowerShell.exe вообще.
  • Если политика безопасности запрещает интерактивный UAC (например, автоматизированные контейнерные среды), метод с -Verb RunAs не сработает.
  • Если файл .ps1 защищён цифровой подписью и организация требует подпись для запуска, временный Bypass может быть запрещён.

Альтернативные подходы

  • Создать ярлык (.lnk) с целевой командой: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File “C:\Path\MyScript.ps1”. Ярлык можно запускать двойным кликом и задать запуск от имени администратора в свойствах ярлыка.
  • Подписывать скрипты и настроить доверенные издатели — безопасный корпоративный подход.
  • Использовать менеджеры конфигурации (SCCM, Intune) для централизованного развертывания и запуска скриптов с требуемыми привилегиями.
  • Упаковать утилиту как исполняемый файл с помощью инструментов вроде PS2EXE — это упрощает запуск конечными пользователями, но меняет модель распространения и может вызвать дополнительные сигнатуры AV.

Ментальные модели и эвристики

  • Think in layers (слои безопасности): батник лишь временно меняет поведение на уровень сессии. Он не «ломает» глобальную безопасность.
  • Principle of least privilege: запрашивайте права администратора только если действительно нужно.
  • Predictability first: отключение профилей делает среду выполнения предсказуемой.

Чек-лист ролей

Для разработчика-скриптописателя:

  • Назвать .bat и .ps1 одинаково и положить в одну папку.
  • Добавить PAUSE для отладки, убрать в релизе, если нужно.
  • Использовать -NoProfile и -ExecutionPolicy Bypass по необходимости.
  • Документировать, зачем требуются права администратора.

Для администратора:

  • Проверить GPO, запрещающие локальные обходы ExecutionPolicy.
  • Рассмотреть альтернативы: подпись скриптов, централизованный запуск.
  • Обучить сотрудников безопасному использованию.

Для конечного пользователя:

  • Двойной клик по .bat запускает скрипт безопасно.
  • Подтвердить UAC, если требуется.
  • Сообщать разработчику об ошибках и о странном поведении после запуска.

Шпаргалка (cheat sheet) — часто используемые флаги

  • -NoProfile — не загружать пользовательские профили PowerShell.
  • -ExecutionPolicy Bypass — обойти политику исполнения для текущего запуска.
  • -Command “& ‘.ps1’” — выполнить команду/скрипт в PowerShell.
  • -File “.ps1” — передать файл для выполнения.
  • Start-Process -Verb RunAs — вызвать запуск с запросом UAC.
  • %~dpn0 — диск, путь и имя текущего батника без расширения.

Мини-методология развёртывания скриптов в организации

  1. Разработайте и протестируйте локально с -NoProfile и -ExecutionPolicy Bypass.
  2. Подпишите скрипты цифровой подписью для корпоративного распределения.
  3. Если подпись невозможна, используйте защищённые каналы и централизованный запуск (Intune, SCCM).
  4. Документируйте требования для администраторов и конечных пользователей.
  5. Логируйте выполнение и результаты команд для аудита.

Критерии приёмки

  • Скрипт запускается двойным кликом на тестовой машине без изменения глобальных настроек.
  • При необходимости запрашивается UAC и скрипт выполняется с повышенными правами.
  • Скрипт выполняется в среде без пользовательских профилей, если это необходимо.
  • Вывод виден пользователю до закрытия окна.

Тестовые случаи и приемочные сценарии

  1. Запуск на чистой машине с дефолтной ExecutionPolicy: батник должен либо корректно запустить скрипт (с Bypass), либо отобразить понятную ошибку.
  2. Файл помечен Zone.Identifier (импорт из Интернета): батник с -ExecutionPolicy Bypass должен выполнить скрипт.
  3. Скрипт, требующий администратора: батник с Start-Process и -Verb RunAs должен запросить UAC и выполнить скрипт с правами.
  4. Пользовательский профиль содержит переопределённые команды: запуск с -NoProfile должен игнорировать профиль и вернуть предсказуемый вывод.

Безопасность и соответствие требованиям конфиденциальности

Важно помнить:

  • Обход ExecutionPolicy не отменяет необходимость проверять содержимое скрипта. Всегда проверяйте скрипты на предмет нежелательных действий.
  • Не используйте обходы как «постоянное решение» для множества машин. Для организации правильнее — подписывать скрипты и управлять политиками централизованно.
  • Если скрипт обрабатывает персональные данные, обеспечьте соответствие локальным требованиям по защите данных (например, GDPR). Логируйте доступы и минимизируйте сбор данных.

Готовые шаблоны и примеры

Шаблон «для разработчика» (без повышения прав):

@ECHO OFF
:: MyScript.bat — запускает MyScript.ps1 в той же папке
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
PAUSE

Шаблон «для конечного пользователя» (с UAC):

@ECHO OFF
:: MyScript.bat — запрашивает повышение прав и запускает MyScript.ps1
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
PAUSE

Если вы хотите ярлык вместо батника, целевая команда ярлыка может быть такой:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Path\MyScript.ps1"

1-строчный глоссарий

  • ExecutionPolicy — механизм PowerShell, ограничивающий запуск скриптов по происхождению и подписи.
  • UAC — User Account Control, механизм Windows для согласования повышения прав.
  • %~dpn0 — переменная batch-файла: диск + путь + имя файла (без расширения).
  • -NoProfile — ключ PowerShell, запрещающий загрузку пользовательских profile.ps1.

Заключение

Использование простого .bat-файла рядом с .ps1 даёт удобный и контролируемый способ запускать PowerShell-скрипты на компьютерах, где вы не хотите или не можете менять глобальные настройки системы. Такой подход сохраняет безопасность системы и даёт пользователям удобный двойной щелчок для запуска. Для корпоративного распространения рассмотрите подпись скриптов и централизованное управление политиками.

Важно: всегда проверяйте скрипты перед запуском и минимизируйте запросы прав администратора.


Справочные материалы:

  • Running PowerShell scripts from a batch file — Daniel Schroeder’s Programming Blog
  • Checking for Administrator permissions in PowerShell — Hey, Scripting Guy! Blog
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Блокировать и отключать SMS на iPhone
iOS

Блокировать и отключать SMS на iPhone

Доступ к файлам Android в Проводнике Windows по Wi‑Fi
Android.

Доступ к файлам Android в Проводнике Windows по Wi‑Fi

Использовать iPhone как USB‑накопитель
Гайды

Использовать iPhone как USB‑накопитель

Как создать профиль Kids на Google TV
Руководства

Как создать профиль Kids на Google TV

Cortex: быстро делиться контентом в соцсетях
Инструменты

Cortex: быстро делиться контентом в соцсетях

Конвертировать аудио в рингтон .m4r через Terminal
Руководства

Конвертировать аудио в рингтон .m4r через Terminal