Jak przekazać argumenty wiersza polecenia do pliku ps1 programu PowerShell

90

Przez lata używałem cmd/DOS/Windowspowłoki i przekazywałem argumenty wiersza poleceń do plików wsadowych. Na przykład, mam pliku, zuzu.bataw nim, mam dostęp %1, %2itp Teraz chcę zrobić to samo, gdy nazywam PowerShellskrypt when I am in a Cmd.exe shell. Mam skrypt xuxu.ps1(i dodałem PS1 do mojej zmiennej PATHEXT i powiązanych plików PS1 z PowerShell). Ale bez względu na to, co robię, wydaje mi się, że nie mogę nic uzyskać ze $argszmiennej. Ma zawsze długość 0.

Jeśli jestem w PowerShellpowłoce, zamiast cmd.exetego działa (oczywiście). Ale nie czuję się jeszcze wystarczająco komfortowo, aby żyć w środowisku PowerShell w pełnym wymiarze godzin. Nie chcę pisać powershell.exe -command xuxu.ps1 p1 p2 p3 p4. Chcę pisać xuxu p1 p2 p3 p4.

Czy to możliwe, a jeśli tak, to w jaki sposób?

Przykład, którego nie mogę uruchomić, jest trywialny, foo.ps1:

Write-Host "Num Args:" $args.Length;
foreach ($arg in $args) {
    Write-Host "Arg: $arg";
}

Wyniki są zawsze takie:

C:\temp> foo
Num Args: 0
C:\temp> foo a b c d
Num Args: 0
c:\temp>
Daniel „Dang” Griffith
źródło

Odpowiedzi:

34

Ten artykuł jest pomocny. W szczególności ta sekcja:

-Plik

Uruchamia określony skrypt w zakresie lokalnym („ze źródła kropkowego”), dzięki czemu funkcje i zmienne utworzone przez skrypt są dostępne w bieżącej sesji. Wprowadź ścieżkę do pliku skryptu i wszelkie parametry. Plik musi być ostatnim parametrem polecenia, ponieważ wszystkie znaki wpisane po nazwie parametru pliku są interpretowane jako ścieżka do pliku skryptu, po której następują parametry skryptu.

to znaczy

powershell.exe -File "C:\myfile.ps1" arg1 arg2 arg3

oznacza uruchomienie pliku myfile.ps1 i arg1 arg2 i arg3 to parametry skryptu PowerShell.

Arj
źródło
1
To nadal nie pomaga w przypadku tego, czego chce operator („Chcę wpisać xuxu p1 p2 p3 p4”).
thdoan
19

Po przejrzeniu dokumentacji programu PowerShell odkryłem kilka przydatnych informacji na temat tego problemu. Nie możesz użyć, $argsjeśli użyłeś the param(...)na początku pliku; zamiast tego będziesz musiał użyć $PSBoundParameters. Skopiowałem / wkleiłem Twój kod do skryptu PowerShell i działał tak, jak można się spodziewać w wersji 2 programu PowerShell (nie jestem pewien, w której wersji byłeś, kiedy napotkasz ten problem).

Jeśli używasz $PSBoundParameters(i działa to TYLKO, jeśli używasz param(...)na początku skryptu), to nie jest to tablica, a tablica mieszająca, więc będziesz musiał odwołać się do niej za pomocą pary klucz / wartość.

param($p1, $p2, $p3, $p4)
$Script:args=""
write-host "Num Args: " $PSBoundParameters.Keys.Count
foreach ($key in $PSBoundParameters.keys) {
    $Script:args+= "`$$key=" + $PSBoundParameters["$key"] + "  "
}
write-host $Script:args

A kiedy dzwonisz z ...

PS> ./foo.ps1 a b c d

Wynik to...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d
Randall Borck
źródło
Nie oznacza to, że OP uruchamia swój wiersz poleceń za pomocą powershell.exe lub pwsh. Zachowanie zmienia się, gdy robi to OP.
Eric Hansen
1
@EricHansen Nie wiem, co masz na myśli, i tak otrzymuję ten sam wynik: `Powershell> powershell.exe. \ ParamTest.ps1 val1 val2 val3 val4 Num Args: 4 $ p1 = val1 $ p2 = val2 $ p3 = val3 $ p4 = val4 `
Randall Borck
@RandallBrock Zachowanie argumentów zmienia się dla mnie. Jeśli jestem w CMD / partia i robię coś takiego pwsh .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, to naprawdę nie podoba mi się to. Z drugiej strony, jeśli jestem w PowerShell i robię .\ParamTest.ps1 -arg1 val1 -listOfArgs val2 val3 val4, to działa tak, jak bym się spodziewał. Słyszałem, że tak właśnie ma działać ze względu na „względy bezpieczeństwa”.
Eric Hansen,
@EricHansen Zastanawiam się, czy to kwestia wersji. Dla mnie pwsh uruchamia 6.2.0, ale powershell.exe uruchamia 5.1.17134.858, z których oba dają te same wyniki wymienione: wyniki Powershell>pwsh .\ParamTest.ps1 val1 val2 val3 val4:Num Args: 4 $p1=val1 $p2=val2 $p3=val3 $p4=val4
Randall Borck
1
@Timo Nie wiem dokładnie, co robisz, ale paramjest to konstrukcja językowa, jednak musi być pierwszą rzeczą w pliku. Czy wcześniej zadeklarowałeś zmienną lub coś innego? Więcej informacji tutaj: docs.microsoft.com/en-us/powershell/module/…
Randall Borck
18

OK, więc najpierw jest to zerwanie podstawowej funkcji zabezpieczeń w programie PowerShell. Mając to na uwadze, oto jak możesz to zrobić:

  1. Otwórz okno Eksploratora Windows
  2. Menu Narzędzia -> Opcje folderów -> zakładka Typy plików
  3. Znajdź typ pliku PS1 i kliknij przycisk zaawansowane
  4. Kliknij przycisk Nowy
  5. W przypadku działania umieścić: Otwórz
  6. Dla aplikacji wpisz: „C: \ WINNT \ system32 \ WindowsPowerShell \ v1.0 \ powershell.exe” „-file” „% 1”% *

Możesz -NoProfiletam również umieścić argument, w zależności od tego, co robi twój profil.

EBGreen
źródło
4
Myślę, że kluczem jest krok 6, w którym przekazujesz parametry do powershell.exe. Daniel mówi, że skojarzył pliki PS1 z PowerShell, ale to nie przekazuje argumentów bez dodatkowych specyfikacji% 1% *. Należy również pamiętać, że parametr -File nie jest dostępny w wersji V1. To nowość w V2.
Keith Hill
Dobry chwyt dotyczący parametru -file, o którym zapomniałem.
EBGreen
Muszę zainstalować V2, zanim wypróbuję twoją sugestię. Dzięki. Kiedy mówisz, że narusza to podstawową funkcję zabezpieczeń, co masz na myśli? Wywołanie skryptu programu PowerShell z programu Cmd.exe tak, jakby był to plik .com / .bat / .exe? Przekazywanie parametrów do skryptu?
Daniel 'Dang' Griffith
1
Przepraszam, że powinienem był wyrazić się bardziej jasno. Wywołanie skryptu bez jawnego wywoływania powershell.exe. Nie mówię, że jest to ważna cecha bezpieczeństwa dla ciebie osobiście i jest to ochrona poprzez niejasność, której i tak nie zawsze jestem fanem.
EBGreen
6
Aby dodać do komentarza EBGreen, podstawowym problemem bezpieczeństwa, którego PowerShell stara się uniknąć, jest dwukrotne klikanie plików PS1 załączonych do wiadomości e-mail i uruchomienie skryptu. Dlatego pliki PS1 są domyślnie skojarzone tylko z edytorem. Microsoft naprawdę nie chce wersji PowerShell wirusa ILoveYou, np. „LOVE-LETTER-FOR-YOU.TXT.ps1”
Keith Hill
11

Możesz zadeklarować swoje parametry w pliku, na przykład param:

[string]$para1
[string]$param2

A następnie wywołaj plik PowerShell w ten sposób .\temp.ps1 para1 para2....para10itp.

VB
źródło
6

Może możesz zawinąć wywołanie PowerShell w taki .batplik:

rem ps.bat
@echo off
powershell.exe -command "%*"

Jeśli następnie umieścisz ten plik w folderze w swoim PATH, możesz wywołać skrypty PowerShell w ten sposób:

ps foo 1 2 3

Cytowanie może być jednak trochę skomplikowane:

ps write-host """hello from cmd!""" -foregroundcolor green
guillermooo
źródło
+1 za wyświetlanie potrójnych cudzysłowów. że utknąłem na chwilę.
DeanOC
1

Możesz nie otrzymać "xuxu p1 p2 p3 p4", jak się wydaje. Ale kiedy jesteś w PowerShell i ustawiasz

PS > set-executionpolicy Unrestricted -scope currentuser

Możesz uruchomić te skrypty w ten sposób:

./xuxu p1 p2 p3 p4

lub

.\xuxu p1 p2 p3 p4

lub

./xuxu.ps1 p1 p2 p3 p4

Mam nadzieję, że dzięki temu poczujesz się trochę bardziej komfortowo z PowerShell.

Atiq Rahman
źródło
0

jeśli chcesz wywoływać skrypty ps1 z cmd i przekazywać argumenty bez wywoływania takiego skryptu

powershell.exe script.ps1 -c test
script -c test ( wont work )

możesz wykonać następujące czynności

setx PATHEXT "%PATHEXT%;.PS1;" /m
assoc .ps1=Microsoft.PowerShellScript.1
ftype Microsoft.PowerShellScript.1=powershell.exe "%1" %*

To jest przy założeniu, że na Twojej ścieżce znajduje się program powershell.exe

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/ftype

ta32
źródło
Warto zauważyć, że wymaga to uruchomienia polecenia cmd jako Administrator. Poza tym staram się, aby to działało w systemie Windows 10 w wersji 1903 (18362.778) - wszystkie polecenia działają pomyślnie, ale argumenty nadal nie są przekazywane. Myślę, że pakowanie za pomocą pliku .bat jest najbardziej przenośnym rozwiązaniem.
David Airapetyan