Как да използвате пакетния файл, за да направите PowerShell скриптове по-лесни за изпълнение
По няколко причини, най-вече свързани със сигурността, скриптовете на PowerShell не са толкова лесно преносими и могат да се използват като пакетни скриптове. Въпреки това, можем да обединим пакетния скрипт с нашите скриптове на PowerShell, за да се справим с тези проблеми. Тук ще ви покажем някои от тези проблемни области и как да изградим партиден скрипт, за да ги заобиколите.
Защо не мога просто да копирам моя .PS1 файл на друг компютър и да го стартирам?
Освен ако целевата система не е предварително конфигурирана да позволява изпълнението на произволни скриптове, с необходимите привилегии и използване на правилните настройки, има вероятност да се сблъскате с някои проблеми, когато се опитате да направите това.
- PowerShell не е свързан по подразбиране с разширение .PS1.
Направихме това първоначално в нашата серия PowerShell Geek School. Windows свързва .PS1 файловете с Notepad по подразбиране, вместо да ги изпраща на интерпретатора на командите PowerShell. Това е за предотвратяване на случайно изпълнение на злонамерени скриптове, като просто щракнете двукратно върху тях. Има начини да промените това поведение, но това вероятно не е нещо, което искате да правите на всеки компютър, на който носите скриптовете си - особено ако някои от тези компютри не са ваши. - PowerShell не позволява външно изпълнение на скриптове по подразбиране.
Настройката ExecutionPolicy в PowerShell предотвратява изпълнението на външни скриптове по подразбиране във всички версии на Windows. В някои версии на Windows по подразбиране въобще не се позволява изпълнението на скриптове. Показахме ви как да промените тази настройка в Как да разрешавате изпълнението на скриптове на PowerShell в Windows 7. Това обаче е и нещо, което не искате да правите на всеки компютър. - Някои скриптове на PowerShell няма да работят без администраторски разрешения.
Дори да работите с акаунт на ниво администратор, все още трябва да преминете през User Account Control (UAC), за да извършите определени действия. Не искаме да го изключваме, но все пак е хубаво, когато можем да се справим по-лесно. - Някои потребители могат да имат персонализирани среди на PowerShell.
Вероятно няма да се сблъскате с това често, но когато го направите, можете да направите работата и отстраняването на неизправности на вашите скриптове малко разочароващи. За щастие, можем да се справим с това, без да правим постоянни промени.
Стъпка 1: Кликнете два пъти, за да стартирате.
Да започнем с адресиране на първия проблем - .PS1 файлови асоциации. Не можете да щракнете двукратно, за да стартирате .PS1 файлове, но можете да изпълните .BAT файл по този начин. Така че, ние ще напишем команден файл, за да извикаме скрипта на PowerShell от командния ред за нас.
Така че ние не трябва да пренаписваме командния файл за всеки скрипт, или всеки път, когато преместваме скрипт наоколо, той ще използва самореферираща се променлива за изграждане на пътя на файла за скрипта PowerShell. За да направи това, партидният файл трябва да бъде поставен в същата папка като скрипта на PowerShell и да има същото име на файла. Така че, ако вашият скрипт на PowerShell се нарича “MyScript.ps1”, ще искате да назовете вашия файлов файл “MyScript.bat” и се уверете, че той е в същата папка. След това сложете тези редове в пакетния скрипт:
@ECHO OFF PowerShell.exe -Команда "&"% ~ dpn0.ps1 "" PAUSE
Ако не бяха налице другите ограничения за сигурност, това наистина е всичко, което е необходимо, за да се стартира скрипт на PowerShell от команден файл. Всъщност първият и последният ред са само въпрос на предпочитание - това е втората линия, която наистина върши работата. Ето разбивка:
@ECHO OFF изключва командата echoing. Това само запазва другите ви команди да се показват на екрана, когато се изпълнява командния файл. Самата линия е скрита от използването на символа at (@) пред него.
PowerShell.exe -Използване „&“% ~ 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, за да направите това също, ако искате сами да тествате тези скриптове. Трябва само да добавите следния ред в скрипта на потребителския си профил:
Напишете-Output 'Custom 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 -ExecutionPolicy Bypass -Command "&"% ~ dpn0.ps1 "
Параметър -ExecutionPolicy може да се използва за промяна на ExecutionPolicy, която се използва, когато създавате нова сесия на PowerShell. Това няма да продължи след тази сесия, така че можем да стартираме PowerShell по този начин, когато имаме нужда, без да отслабим общата поза на системата за сигурност. Сега, след като сме го определили, нека направим още едно:
Сега, когато скриптът е изпълнен правилно, можем да видим какво всъщност прави. Това ни уведомява, че използваме скрипта като потребител с ограничен достъп. Сценарият всъщност се управлява от акаунт с администраторски разрешения, но контролът на потребителските акаунти се затруднява. Въпреки че подробностите за това как скриптът проверява за достъп на администратор, са извън обхвата на тази статия, ето кодът, който се използва за демонстрация:
IsInRole ([Security.Principal.WindowsBuiltInRole] "Администратор")) Write-Output 'Изпълнява се като администратор!' иначе ([[Security.Principal.WindowsPrincipal]] Напишете-изход 'Изпълнение на ограничен!' Пауза
Също така ще забележите, че в изхода на скрипта вече има две операции „Пауза“ - един от скрипта на PowerShell и един от командния файл. Причината за това ще бъде по-очевидна в следващата стъпка.
Стъпка 3: Получаване на администраторски достъп.
Ако вашият скрипт не изпълнява никакви команди, които изискват височина, и сте сигурни, че няма да се налага да се притеснявате, че потребителските профили на никого не ви пречат, можете да пропуснете останалата част от това. Ако изпълнявате някои cmdlets на ниво администратор, ще ви е необходимо това парче.
За съжаление, няма начин да задействате UAC за надморска височина в рамките на партиден файл или CMD сесия. PowerShell обаче ни позволява да направим това с Start-Process. Когато се използва с “-Verb RunAs” в аргументите си, Start-Process ще се опита да стартира приложение с администраторски разрешения. Ако сесията PowerShell вече не е повишена, това ще задейства UAC ред. За да го използваме от командния файл за стартиране на нашия скрипт, ние ще завършим създаването на два процеса PowerShell - един за изстрелване на Start-Process и друг, стартиран от Start-Process, за да стартира скрипта. Вторият ред на пакетния файл трябва да бъде променен на следното:
PowerShell.exe -Command "& Start-Process PowerShell.exe -АргументЛист '-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 -АргументЛист '-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 "PAUSE
С администраторски достъп:
@ECHO OFF PowerShell.exe -NoProfile -Command "& Start-Process PowerShell.exe -АргументЛист '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "-Verb RunAs
Не забравяйте да поставите партидния файл в същата папка като скрипта на PowerShell, за който искате да го използвате, и да му дадете същото име. След това, без значение на каква система да вземете тези файлове, ще можете да стартирате скрипта на PowerShell, без да се налага да се забърквате с някоя от настройките за сигурност в системата. Със сигурност можете да правите тези промени ръчно всеки път, но това ви спестява тези проблеми и няма да се налага да се притеснявате за връщането на промените по-късно.
Препратки:
- Изпълнение на скриптове на PowerShell от команден файл - Програмен блог на Daniel Schroeder
- Проверка за администраторски разрешения в PowerShell - Хей, скрипт! Блог