
Як використовувати командний файл для спрощення запуску сценаріїв PowerShell
З ряду причин, в основному пов'язаних з безпекою, сценарії PowerShell не так легко переносимі і зручні у використанні, як пакетні сценарії. Однак ми можемо пов'язати пакетний сценарій з нашими сценаріями PowerShell, щоб обійти ці проблеми. Тут ми покажемо вам деякі з цих проблемних областей і як створити пакетний скрипт, щоб обійти їх.
Чому я не можу просто скопіювати мій файл. PS1 на інший комп'ютер і запустити його?
Якщо цільова система не була попередньо сконфігурована так, щоб дозволяти запуск довільних сценаріїв з необхідними привілеями і з використанням правильних налаштувань, швидше за все, ви зіткнетеся з деякими проблемами при спробі зробити це.
- PowerShell не пов'язаний з суфіксом файла. Типовий PS1.
Спочатку ми обговорювали це в нашій серії PowerShell Geek School. За замовчуванням Windows асоціює файли. PS1 з Блокнотом, а не відправляє їх в інтерпретатор команд PowerShell. Це необхідно для запобігання випадкового виконання шкідливих скриптів, просто двічі клацнувши по них. Є способи, якими ви можете змінити цю поведінку, але це, ймовірно, не те, що ви хочете робити на кожному комп'ютері, на якому ви носите свої скрипти, особливо якщо деякі з цих комп'ютерів не належать вам. - PowerShell не дозволяє виконати типовий зовнішній скрипт. Параметр ExecutionPolicy в PowerShell запобігає
виконанню зовнішніх сценаріїв за замовчуванням у всіх версіях Windows. У деяких версіях Windows за замовчуванням виконання сценаріїв взагалі не дозволено. Ми показали вам, як змінити цей параметр у розділі Як дозволити виконання сценаріїв PowerShell у Windows 7. Тим не менш, це також те, що ви не хочете робити на будь-якому комп'ютері. - Деякі скрипти PowerShell не працюватимуть без прав адміністратора.
Навіть працюючи з обліковим записом рівня адміністратора, вам все одно потрібно пройти через Контроль облікових записів (UAC) для виконання певних дій. Ми не хочемо відключати це, але все-таки приємно, коли ми можемо зробити це трохи легше. - У деяких користувачів можуть бути налаштовані середовища Ймовірно
, ви не будете часто стикатися з цим, але коли ви це зробите, це може трохи засмутити запуск і усунення неполадок у ваших скриптах. На щастя, ми можемо обійти це без внесення постійних змін.
Крок 1: Двічі клацніть, щоб запустити.
Давайте почнемо з вирішення першої проблеми - асоціації файлів. PS1. Ви не можете двічі клацнути на файлі. PS1, але ви можете виконати файл. BAT таким чином. Отже, ми напишемо командний файл для виклику сценарію PowerShell з командного рядка.
Таким чином, нам не потрібно переписувати командний файл для кожного сценарію, або кожен раз, коли ми переміщуємо сценарій, він буде використовувати змінну з власним посиланням для побудови шляху до файлу для сценарію PowerShell. Щоб це працювало, пакетний файл повинен бути поміщений в ту саму теку, що і сценарій PowerShell, і мати ту саму назву файла. Тому, якщо ваш сценарій PowerShell називається «MyScript.ps1», вам потрібно присвоїти пакетному файлу ім'я «MyScript.bat» і переконатися, що він знаходиться в тій же теці. Потім помістіть ці рядки в пакетний скрипт:
@ECHO OFF
PowerShell.exe -Command ""& '% ~ dpn0.ps1'"
ПАУЗА
Якби не інші обмеження безпеки, це дійсно було б все, що потрібно для запуску сценарію PowerShell з командного файла. Насправді, перший і останній рядки в основному є питанням переваги - це другий рядок, який дійсно виконує свою роботу. Ось розбивка:
@ ECHO OFF вимикає відображення команди. Це просто не дає іншим командам показувати на екрані під час запуску командного файла. Цей рядок сховано за допомогою символу at (@) перед ним.
PowerShell.exe -Command "&"% ауд dpn0.ps1 "фактично запускає сценарій PowerShell. PowerShell.exe, звичайно, може бути викликаний з будь-якого вікна CMD або командного файлу для запуску PowerShell на чистій консолі, як зазвичай. Ви також можете використовувати його для запуску команд прямо з пакетного файла, включивши параметр -Command і відповідні аргументи. Цей спосіб використовується для націлювання на наш файл. PS1 за допомогою спеціальної змінної% ádpn0. Після запуску з пакетного файла% ádpn0 оцінює літеру диска, шлях до теки і назву файла (без розширення) пакетного файла. Оскільки командний файл і сценарій PowerShell будуть знаходитися в одній теці і мати однакові імена,% ауд dpn0.ps1 буде перетворено на повний шлях до файла сценарію PowerShell.
PAUSE просто призупиняє пакетне виконання і очікує введення даних користувачем. Зазвичай, це корисно у кінці ваших командних файлів, щоб у вас була можливість переглянути будь-який вивід команди до того, як вікно зникне. У міру проходження тестування кожного кроку, корисність цього стане більш очевидною.
Отже, основний пакетний файл налаштований. У демонстраційних цілях цей файл зберігається як "D: Script Lab\MyScript.bat ", і в тій же теці знаходиться" MyScript.ps1 ". Давайте подивимося, що станеться, коли ми двічі клацнемо MyScript.bat.
Очевидно, що скрипт PowerShell не запускався, але цього і слід було очікувати - зрештою, ми розглянули тільки першу з наших чотирьох проблем. Тим не менш, тут є кілька важливих моментів:
- Заголовок вікна показує, що пакетний скрипт успішно запустив PowerShell.
- Перший рядок виводу показує, що використовується власний профіль PowerShell. Це потенційна проблема № 4, перелічена вище.
- Повідомлення про помилку демонструє чинні обмеження ExecutionPolicy. Це наша проблема № 2.
- Підкреслена частина повідомлення про помилку (яка виконується безпосередньо за допомогою виведення помилок PowerShell) показує, що пакетний сценарій правильно націлений на передбачуваний сценарій PowerShell (D: \ Script Lab \ MyScript.ps1). Таким чином, ми принаймні знаємо, що багато працює правильно.
У даному випадку профіль - це простий одностроковий скрипт, який використовується для цієї демонстрації для генерації вихідних даних щоразу, коли профіль активний. Ви також можете налаштувати власний профіль PowerShell, якщо хочете самостійно протестувати ці скрипти. Просто додайте наступний рядок до вашого скрипту профілю:
Write-Output'Власний профіль PowerShell в дії! "
ExecutionPolicy у тестовій системі тут має значення RemoteSigned. Це дозволяє виконувати скрипти, створені локально (наприклад, сценарій профілю), при цьому блокуючи сценарії із зовнішніх джерел, якщо вони не підписані довіреним органом. У демонстраційних цілях для позначки MyScript.ps1 як зовнішнього джерела використовувалася наступна команда:
Add-Content -Path 'D: \ Script Lab \ MyScript.ps1' -Value ""[ZoneTransfer]` nZoneId = 3 ""-Stream 'Zone.Identifier'
Це встановлює альтернативний потік даних Zone.Identifier на MyScript.ps1, так що Windows буде думати, що файл надійшов з Інтернету. Його можна легко змінити за допомогою наступної команди:
Clear-Content -Path 'D: \ Script Lab \ MyScript.ps1' -Stream 'Zone.Identifier'
Крок 2: Обійти ExecutionPolicy.
Обійти налаштування ExecutionPolicy з CMD або пакетного скрипту насправді досить легко. Ми просто модифікуємо другий рядок скрипту, щоб додати ще один параметр в команду PowerShell.exe.
PowerShell.exe -PecicyPolicy Bypass -Command ""& '% ~ dpn0.ps1'"
Параметр -ExecutionPolicy можна використовувати для зміни ExecutionPolicy, який використовується при породженні нового сеансу PowerShell. Це не триватиме після цього сеансу, тому ми можемо запускати PowerShell таким чином щоразу, коли нам потрібно, не послаблюючи загальний стан безпеки системи. Тепер, коли ми це виправили, давайте спробуємо ще раз:
Тепер, коли скрипт виконаний правильно, ми можемо побачити, що він насправді робить. Це дає нам знати, що ми запускаємо скрипт як користувач з обмеженими правами. Насправді сценарій запускається обліковим записом з правами адміністратора, але заважає контроль облікових записів. Хоча подробиці про те, як скрипт перевіряє доступ адміністратора, виходять за рамки цієї статті, ось код, який використовується для демонстрації:
if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]:: GetCurrent ()). IsInRole ([Security.Principal.Windo^ BuiltInRole] «Адміністратор»)) {
Write-Output'Запуск від імені адміністратора!'}
ще {
Write-Output'Running Limited!'}
Пауза
Ви також зауважите, що тепер у виводі скрипту є дві операції «Пауза» - одна зі скриптів PowerShell і одна з пакетного файлу. Причина цього буде більш очевидною на наступному етапі.
Крок 3: Отримання доступу адміністратора.
Якщо ваш сценарій не виконує жодних команд, які потребують підвищення прав, і ви впевнені, що вам не доведеться турбуватися про чиїсь власні профілі, що заважають, ви можете пропустити іншу частину цього. Якщо ви використовуєте деякі командлети рівня адміністратора, вам знадобиться ця частина.
На жаль, немає способу запустити UAC для підвищення прав з пакетного файла або сеансу CMD. Тим не менш, PowerShell дозволяє нам робити це за допомогою Start-Process. При використанні з аргументами «-Verb RunAs» Start-Process намагатиметься запустити програму з правами адміністратора. Якщо сеанс PowerShell ще не підвищено, це викличе запрошення UAC. Щоб використовувати це з командного файлу для запуску нашого сценарію, ми в кінцевому підсумку створимо два процеси PowerShell - один для запуску Start-Process і інший, запущений Start-Process, для запуску сценарію. Другий рядок командного файла повинен бути змінений на це:
PowerShell.exe -Команда ""& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File"" ""% ~ dpn0.ps1"" ""' -Verb RunAs}"
Після запуску пакетного файла перший рядок виводу, який ми побачимо, - зі скрипту профілю PowerShell. Потім буде запрошення UAC, коли Start-Process спробує запустити MyScript.ps1.
Після натискання на запрошення UAC з'явиться новий екземпляр PowerShell. Оскільки це новий екземпляр, звичайно, ми знову побачимо повідомлення скрипту профілю. Потім MyScript.ps1 запускається, і ми бачимо, що ми дійсно знаходимося на підвищеному рівні.
І є причина, через яку у нас тут теж дві паузи. Якби не той, який у скрипті PowerShell, ми б ніколи не побачили висновок скрипту - вікно PowerShell просто спливло б і зникло, як тільки скрипт закінчив працювати. І без паузи в командному файлі ми не змогли б побачити, чи були якісь помилки при запуску PowerShell.
Крок 4. Обхід профілів користувача PowerShell.
Давайте позбудемося цього неприємного повідомлення про профіль, чи не так? Тут це навіть не неприємно, але якщо профіль PowerShell користувача змінює параметри, змінні або функції за замовчуванням так, як ви цього не очікували, це може бути дуже неприємно. Набагато простіше запустити ваш скрипт без профілю повністю, так що вам не потрібно про це турбуватися. Для цього нам просто потрібно змінити другий рядок командного файла ще раз:
PowerShell.exe -NoProfile -Command ""& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File"" ""% ~ dpn0.ps1"" ""' -Verb RunAs}"
Додавання параметра -NoProfile до обох примірників PowerShell, що запускається сценарієм, означає, що сценарій профілю користувача буде повністю обійдено на обох етапах, а наш сценарій PowerShell буде працювати в досить передбачуваному середовищі за замовчуванням. Тут ви можете бачити, що в жодній з породжених оболонок немає профілів користувача.
Якщо вам не потрібні права адміністратора в скрипті PowerShell, і ви пропустили крок 3, ви можете обійтися без другого екземпляра PowerShell, і другий рядок вашого пакетного файла має виглядати наступним чином:
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command ""& '% ~ dpn0.ps1'"
Результат виглядатиме наступним чином:
(Звичайно, для скриптів без прав адміністратора ви можете обійтися без паузи кінця сценарію в сценарії PowerShell і на цьому етапі, оскільки все записується в одне і те ж консольне вікно і буде утримуватися там в кінці паузи. пакетний файл у будь-якому випадку.)
Завершені командні файли.
Залежно від того, чи потрібні вам права адміністратора для вашого скрипту PowerShell (і вам дійсно не слід запитувати їх, якщо ви цього не робите), кінцевий пакетний файл повинен виглядати так, як показано нижче.
Без доступу адміністратора:
@ECHO OFF
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command ""& '% ~ dpn0.ps1'"
ПАУЗА
З правами адміністратора:
@ECHO OFF
PowerShell.exe -NoProfile -Command ""& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File"" ""% ~ dpn0.ps1"" ""' -Verb RunAs}"
ПАУЗА
Не забудьте помістити пакетний файл в ту саму теку, що і сценарій PowerShell, для якого ви хочете його використовувати, і присвойте йому те саме ім'я. Потім, незалежно від того, в яку систему ви берете ці файли, ви зможете запускати сценарій PowerShell без необхідності обмінюватися будь-якими налаштуваннями безпеки в системі. Звичайно, ви можете щоразу вносити ці зміни вручну, але це позбавить вас від цієї проблеми, і вам не доведеться турбуватися про те, щоб скасувати зміни пізніше.
Посилання:
- Запуск сценаріїв PowerShell з командного файла - Блог програміста Деніела Шредера
- Перевірка прав адміністратора в PowerShell - Привіт, сценарист! Блог