Jak korzystać z pliku wsadowego, aby skrypty PowerShell łatwiej działały
Z kilku powodów, głównie związane z bezpieczeństwem, skrypty PowerShell nie są tak łatwo przenośne i użyteczne, jak mogą być skrypty wsadowe. Możemy jednak łączyć skrypt wsadowy ze skryptami PowerShell, aby obejść te problemy. Poniżej pokażemy kilka z tych problematycznych obszarów i jak zbudować skrypt wsadowy, aby je ominąć.
Dlaczego nie mogę po prostu skopiować mojego pliku .PS1 na inny komputer i uruchomić go?
O ile system docelowy nie został wstępnie skonfigurowany, aby umożliwić uruchamianie dowolnych skryptów, z wymaganymi uprawnieniami i korzystaniem z odpowiednich ustawień, istnieje ryzyko, że napotkasz problemy podczas próby wykonania tego.
- PowerShell nie jest domyślnie skojarzony z rozszerzeniem .PS1.
Wprowadziliśmy to początkowo w naszej serii PowerShell Geek School. Windows domyślnie kojarzy pliki .PS1 z Notatnikiem, zamiast wysyłać je do interpretera poleceń PowerShell. Ma to zapobiec przypadkowemu uruchomieniu złośliwych skryptów, klikając je dwukrotnie. Są sposoby na zmianę tego zachowania, ale prawdopodobnie nie jest to coś, co chcesz zrobić na każdym komputerze, na którym masz swoje skrypty - zwłaszcza jeśli niektóre z tych komputerów nie są twoimi własnymi. - PowerShell domyślnie nie pozwala na zewnętrzne wykonywanie skryptów.
Ustawienie ExecutionPolicy w PowerShell zapobiega domyślnemu uruchamianiu zewnętrznych skryptów we wszystkich wersjach systemu Windows. W niektórych wersjach systemu Windows ustawienie domyślne nie pozwala na wykonanie skryptu. Pokazaliśmy, jak zmienić to ustawienie w Jak umożliwić wykonywanie skryptów PowerShell w systemie Windows 7. Jest to jednak także coś, czego nie chcesz robić na żadnym komputerze. - Niektóre skrypty PowerShell nie będą działały bez uprawnień administratora.
Nawet działając z kontem na poziomie administratora, nadal musisz przejść przez kontrolę konta użytkownika (UAC), aby wykonać określone czynności. Nie chcemy tego wyłączać, ale nadal jest przyjemnie, kiedy możemy sobie z tym poradzić. - Niektórzy użytkownicy mogą mieć dostosowane środowiska PowerShell.
Prawdopodobnie nie natkniesz się na to często, ale kiedy to zrobisz, możesz sprawić, że uruchamianie i rozwiązywanie problemów z twoimi skryptami będzie trochę frustrujące. Na szczęście możemy obejść to bez wprowadzania stałych zmian.
Krok 1: Kliknij dwukrotnie, aby uruchomić.
Zacznijmy od zaadresowania pierwszego problemu - powiązań plików .PS1. Nie można dwukrotnie kliknąć, aby uruchomić pliki .PS1, ale można w ten sposób wykonać plik .BAT. Tak więc, napiszemy plik wsadowy, aby wywołać skrypt PowerShell z linii poleceń dla nas.
Nie musimy więc ponownie pisać pliku wsadowego dla każdego skryptu, lub za każdym razem, gdy przenosimy skrypt, użyjemy zmiennej samoodnośnej do zbudowania ścieżki pliku dla skryptu PowerShell. Aby to działało, plik wsadowy musi być umieszczony w tym samym folderze, co skrypt PowerShell i mieć tę samą nazwę pliku. Więc jeśli twój skrypt PowerShell nazywa się "MyScript.ps1", będziesz chciał nazwać swój plik wsadowy "MyScript.bat" i upewnić się, że jest w tym samym folderze. Następnie umieść te linie w skrypcie wsadowym:
@ECHO OFF PowerShell.exe - Polecenie "&"% ~ dpn0.ps1 "" PAUSE
Gdyby nie inne ograniczenia zabezpieczeń, wystarczyłoby uruchomienie skryptu PowerShell z pliku wsadowego. W rzeczywistości pierwsza i ostatnia linia to głównie kwestia preferencji - to druga linia naprawdę wykonuje pracę. Oto podział:
@ECHO OFF wyłącza echo poleceń. Dzięki temu inne polecenia nie będą wyświetlane na ekranie podczas działania pliku wsadowego. Linia ta jest sama ukryta za pomocą symbolu at (@) przed nią.
PowerShell.exe - Polecenie "&"% ~ dpn0.ps1 "" faktycznie uruchamia skrypt PowerShell. PowerShell.exe można oczywiście wywołać z dowolnego okna CMD lub pliku wsadowego, aby uruchomić PowerShell na zwykłej konsoli. Można go również użyć do uruchamiania poleceń bezpośrednio z pliku wsadowego, włączając parametr -Command i odpowiednie argumenty. Sposób w jaki cel ten jest kierowany na nasz plik .PS1 jest ze specjalną zmienną% ~ dpn0. Uruchom z pliku wsadowego,% ~ dpn0 ocenia literę dysku, ścieżkę folderu i nazwę pliku (bez rozszerzenia) pliku wsadowego. Ponieważ plik wsadowy i skrypt PowerShell znajdują się w tym samym folderze i mają taką samą nazwę, plik% ~ dpn0.ps1 zostanie przetłumaczony na pełną ścieżkę do pliku skryptu PowerShell.
PAUZA po prostu przerywa wykonywanie wsadowe i czeka na wprowadzenie danych przez użytkownika. Na ogół jest to przydatne na końcu plików wsadowych, dzięki czemu masz szansę przejrzenia dowolnego polecenia, zanim okno zniknie. Kiedy będziemy testować każdy krok, użyteczność tego stanie się bardziej oczywista.
Zatem podstawowy plik wsadowy jest skonfigurowany. W celach demonstracyjnych plik ten jest zapisywany jako "D: \ Script Lab \ MyScript.bat", aw tym samym folderze znajduje się plik "MyScript.ps1". Zobaczmy, co się stanie, gdy dwukrotnie klikniemy MyScript.bat.
Oczywiście skrypt PowerShell nie działał, ale można się tego spodziewać - w końcu rozwiązaliśmy tylko pierwszy z naszych czterech problemów. Jest tu jednak kilka ważnych bitów:
- Tytuł okna pokazuje, że skrypt wsadowy pomyślnie uruchomił PowerShell.
- Pierwszy wiersz danych wyjściowych pokazuje, że niestandardowy profil PowerShell jest w użyciu. Jest to potencjalny problem nr 4, wymieniony powyżej.
- Komunikat o błędzie pokazuje obowiązujące ograniczenia ExecutionPolicy. To nasz problem # 2.
- Podkreślona część komunikatu o błędzie (wykonywana natywnie przez wynik błędu programu PowerShell) pokazuje, że skrypt wsadowy prawidłowo atakował zamierzony skrypt PowerShell (D: \ Script Lab \ MyScript.ps1). Więc przynajmniej wiemy, że wiele działa poprawnie.
Profil, w tym przypadku, jest prostym, jednokreskowym skryptem używanym do tej demonstracji do generowania danych wyjściowych za każdym razem, gdy profil jest aktywny. Możesz także dostosować swój profil PowerShell, aby to zrobić, jeśli chcesz przetestować te skrypty samemu. Po prostu dodaj następujący wiersz do swojego skryptu profilu:
"Niestandardowy profil PowerShell Write-Output"!
Opcja ExecutionPolicy w systemie testowym jest ustawiona na RemoteSigned. Pozwala to na wykonywanie skryptów tworzonych lokalnie (jak skrypt profilu), blokując skrypty ze źródeł zewnętrznych, chyba że są podpisane przez zaufane instytucje. Do celów demonstracyjnych użyto następującej komendy do oznaczenia pliku MyScript.ps1 jako pochodzącego ze źródła zewnętrznego:
Add-Content -Path 'D: \ Script Lab \ MyScript.ps1' -Value "[ZoneTransfer] 'nZoneId = 3" -Stream' Zone.Identifier "
To ustawia alternatywny strumień danych Zone.Identifier na MyScript.ps1, aby system Windows mógł myśleć, że plik pochodzi z Internetu. Można go łatwo odwrócić za pomocą następującego polecenia:
Wyczyść-treść -Path 'D: \ Script Lab \ MyScript.ps1' -Stream 'Zone.Identifier'
Krok 2: Omówienie ExecutionPolicy.
Obejście ustawienia ExecutionPolicy z CMD lub skryptu wsadowego jest w rzeczywistości dość łatwe. Po prostu modyfikujemy drugą linię skryptu, aby dodać jeszcze jeden parametr do polecenia PowerShell.exe.
PowerShell.exe - WyjątekPolicy Bypass - Komenda "&"% ~ dpn0.ps1 ""
Parametr -ExecutionPolicy może zostać użyty do modyfikacji opcji ExecutionPolicy używanej podczas tworzenia nowej sesji PowerShell. Nie będzie to trwało dłużej niż ta sesja, więc możemy uruchomić PowerShell w ten sposób, kiedy tylko zajdzie taka potrzeba, bez osłabiania ogólnej pozycji bezpieczeństwa systemu. Teraz, gdy to naprawiliśmy, spójrzmy na to:
Teraz, gdy skrypt został poprawnie wykonany, możemy zobaczyć, co on właściwie robi. Informuje nas, że uruchamiamy skrypt jako użytkownik z ograniczonym dostępem. Skrypt jest uruchamiany przez konto z uprawnieniami administratora, ale kontrola konta użytkownika staje na przeszkodzie. Chociaż szczegóły tego, w jaki sposób skrypt sprawdza dostęp administratora, są poza zakresem tego artykułu, oto kod, który jest używany do demonstracji:
if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity] :: GetCurrent ()). IsInRole ([Security.Principal.WindowsBuiltInRole] "Administrator")) Write-Output "Działa jako administrator!" else Write-Output 'Running Limited!' Wstrzymaj
Zauważysz także, że w wyjściu skryptu są teraz dwie operacje "Wstrzymaj" - jedną ze skryptu PowerShell, a drugą z pliku wsadowego. Powód tego będzie bardziej widoczny w następnym kroku.
Krok 3: Uzyskanie dostępu administratora.
Jeśli twój skrypt nie uruchamia żadnych poleceń, które wymagają podniesienia, i jesteś pewien, że nie będziesz musiał się martwić, że jakiekolwiek niestandardowe profile przeszkadzają, możesz pominąć resztę. Jeśli jednak używasz niektórych poleceń cmdlet na poziomie administratora, potrzebujesz tego fragmentu.
Niestety, nie ma sposobu na wyzwolenie UAC do podniesienia z pliku wsadowego lub sesji CMD. Jednak PowerShell pozwala nam to zrobić w Start-Process. W przypadku użycia z "-Verb RunAs" w swoich argumentach, Start-Process spróbuje uruchomić aplikację z uprawnieniami administratora. Jeśli sesja PowerShell nie jest jeszcze podniesiona, spowoduje to wyświetlenie monitu UAC. Aby użyć tego pliku wsadowego do uruchomienia naszego skryptu, skończymy z utworzeniem dwóch procesów PowerShell - jeden do uruchomienia procesu Start i innego, uruchamianego przez Start-Process, w celu uruchomienia skryptu. Druga linia pliku wsadowego musi zostać zmieniona na:
PowerShell.exe - Polecenie "& Rozpocznij przetwarzanie PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "" -Verb RunAs "
Po uruchomieniu pliku wsadowego pierwszy wiersz danych wyjściowych będzie pochodził ze skryptu profilu PowerShell. Następnie pojawi się monit UAC, gdy Start-Process spróbuje uruchomić MyScript.ps1.
Po kliknięciu w monit UAC pojawi się nowa instancja PowerShell. Ponieważ jest to nowa instancja, oczywiście, zobaczymy ponownie powiadomienie dotyczące profilu. Następnie działa MyScript.ps1 i widzimy, że rzeczywiście jesteśmy w podwyższonej sesji.
I tu jest powód, dla którego mamy tu dwie przerwy. Gdyby nie ten, który znajduje się w skrypcie PowerShell, nigdy nie zobaczylibyśmy wyjścia skryptu - okno PowerShell po prostu wyskakuje i znika, gdy skrypt zostanie uruchomiony. I bez pauzy w pliku wsadowym, nie bylibyśmy w stanie zobaczyć, czy były jakieś błędy uruchamiające PowerShell w pierwszej kolejności.
Krok 4: Poruszanie się po niestandardowych profilach PowerShell.
Pozbądźmy się teraz tego paskudnego ogłoszenia o profilu niestandardowym, dobrze? W tym przypadku nie jest to uciążliwe, ale jeśli profil PowerShell użytkownika zmienia ustawienia domyślne, zmienne lub funkcje w sposób, jakiego mógłbyś nie przewidzieć przy swoim skrypcie, mogą one być naprawdę kłopotliwe. O wiele łatwiej jest uruchomić swój skrypt bez profilu, więc nie musisz się o to martwić. Aby to zrobić, wystarczy zmienić drugi wiersz pliku wsadowego jeszcze raz:
PowerShell.exe -NoProfile -Command "& Rozpocznij przetwarzanie PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "" -Verb RunAs "
Dodanie parametru -NoProfile do obu wystąpień programu PowerShell uruchamianych przez skrypt oznacza, że skrypt profilu użytkownika zostanie całkowicie pominięty w obu krokach, a nasz skrypt PowerShell będzie działał w dość przewidywalnym, domyślnym środowisku. Tutaj możesz zauważyć, że w żadnej z zarodkowanych powłok nie ma niestandardowego powiadomienia o profilu.
Jeśli nie potrzebujesz uprawnień administratora w skrypcie PowerShell, a pominiesz krok 3, możesz obejść się bez drugiej instancji PowerShell, a druga linia pliku wsadowego powinna wyglądać tak:
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "&"% ~ dpn0.ps1 ""
Dane wyjściowe będą wyglądały następująco:
(Oczywiście, w przypadku skryptów innych niż Administrator, w tym momencie można by zrobić bez pauzy końca skryptu w skrypcie PowerShell, ponieważ wszystko jest przechwytywane w tym samym oknie konsoli i będzie utrzymywane w tym miejscu przez przerwę pod koniec plik wsadowy mimo to.)
Zakończone pliki wsadowe.
W zależności od tego, czy potrzebujesz uprawnień administratora do skryptu PowerShell (i naprawdę nie powinieneś ich żądać, jeśli tego nie robisz) ostateczny plik wsadowy powinien wyglądać jak jeden z dwóch.
Bez dostępu administratora:
@ECHO OFF PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '% ~ dpn0.ps1'" PAUSE
Z dostępem administracyjnym:
@ECHO OFF PowerShell.exe -NoProfile -Command "& Rozpocznij przetwarzanie PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File" "% ~ dpn0.ps1" "" -Verb RunAs "PAUSE
Pamiętaj, aby umieścić plik wsadowy w tym samym folderze, co skrypt PowerShell, dla którego chcesz go użyć, i nadaj mu tę samą nazwę. Wtedy, bez względu na to, do jakiego systemu przeniesiesz te pliki, będziesz mógł uruchomić swój skrypt PowerShell bez konieczności obstawiania przy jakichkolwiek ustawieniach bezpieczeństwa w systemie. Możesz z pewnością wprowadzić te zmiany ręcznie za każdym razem, ale to oszczędza ci kłopotów i nie będziesz musiał się martwić, że później powrócisz do zmian.
Referencje:
- Uruchamianie skryptów PowerShell z pliku wsadowego - blog programisty Daniela Schroedera
- Sprawdzanie uprawnień administratora w PowerShell - Hej, skrypciarze! Blog