Jak przekazać wiele parametrów do funkcji w PowerShell?

Jeśli mam funkcję, która akceptuje więcej niż jeden parametr string, pierwszy parametr wydaje się pobierać wszystkie dane przypisane do niego, a pozostałe parametry są przekazywane jako puste.

Skrypt szybkiego testu:

Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC", "DEF")

Wygenerowane wyjście to

$arg1 value: ABC DEF
$arg2 value: 

Poprawne wyjście powinno być:

$arg1 value: ABC
$arg2 value: DEF

To wydaje się być zgodne między v1 i v2 na wielu maszynach, więc oczywiście robię coś nie tak. Czy ktoś może wskazać dokładnie co?

 328
Author: George Stocker, 2011-02-14

14 answers

Parametry w wywołaniach funkcji w PowerShell (wszystkie wersje) są rozdzielane spacjami, a nie przecinkami. Nawiasy są również całkowicie niezauważalne i powodują błąd parsowania w PowerShell 2.0 (lub nowszym), Jeśli Set-StrictMode jest aktywna. Argumenty podane w nawiasach są używane tylko w metodach. NET.

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3
 451
Author: x0n,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 14:25:58

Poprawna odpowiedź została już dostarczona, ale ta kwestia wydaje się wystarczająco rozpowszechniona, aby uzasadnić kilka dodatkowych szczegółów dla tych, którzy chcą zrozumieć subtelności. Dodałbym to tylko jako komentarz, ale chciałem dołączyć ilustrację-zerwałem to z mojego szybkiego wykresu referencyjnego na temat funkcji PowerShell. Zakłada się, że sygnatura funkcji f wynosi f($a, $b, $c):

pułapki składniowe wywołania funkcji

Można więc wywołać funkcję z rozdzielonymi spacjamipozycyjnymi parametrami lub niezależne od kolejności nazwane parametry. Inne pułapki ujawniają, że trzeba być świadomym przecinków, nawiasów, i białej spacji.

Do dalszego czytania zobacz mój artykuł Down the Rabbit Hole: badanie potoków PowerShell, funkcji i parametrów właśnie opublikowany na Simple-Talk.com. artykuł zawiera również link do quick reference / wall chart.

 215
Author: Michael Sorens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-08 15:26:41

Wywołujesz funkcje PowerShell bez nawiasu i bez użycia przecinka jako separatora. Spróbuj użyć:

   test "ABC" "DEF"

W PowerShell przecinek (,) jest operatorem tablicy, np.

   $a = "one", "two", "three"

Ustawia $a na tablicę z trzema wartościami.

 38
Author: Todd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-05 14:28:46

Kilka dobrych odpowiedzi tutaj, ale chciałem zwrócić uwagę na kilka innych rzeczy. Parametry funkcji są właściwie miejscem, w którym PowerShell świeci. Na przykład, możesz mieć parametry nazwane lub pozycyjne w zaawansowanych funkcjach, jak tak:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

Wtedy możesz albo wywołać go przez podanie nazwy parametru, albo po prostu użyć parametrów pozycyjnych, ponieważ wyraźnie je zdefiniowałeś. Więc jedno z nich by zadziałało:

Get-Something -Id 34 -Name "Blah" 
Get-Something "Blah" 34

Pierwszy przykład działa mimo, że nazwa jest podaliśmy drugi, ponieważ jawnie użyliśmy nazwy parametru. Drugi przykład działa na podstawie pozycji, więc nazwa musi być pierwsza. Jeśli to możliwe, zawsze staram się definiować pozycje tak, aby obie opcje były dostępne.

PowerShell ma również możliwość definiowania zestawów parametrów. Używa tego zamiast metody przeciążenia i znowu jest całkiem przydatna: {]}

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

Teraz funkcja przyjmie albo nazwę, albo id, ale nie oba. Możesz używać ich pozycyjnie lub po imieniu. Ponieważ są one innego typu, PowerShell to zrozumie. Więc wszystko to zadziała

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

Można również przypisać dodatkowe parametry do różnych zestawów parametrów. (Oczywiście był to dość prosty przykład) wewnątrz funkcji można określić, który zestaw parametrów został użyty z $PsCmdlet.Parametrówetname property. Na przykład:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

Następnie, na pokrewnej stronie, istnieje również Walidacja parametrów w PowerShell. To jeden z moich ulubionych PowerShell funkcje i sprawia, że kod wewnątrz funkcji jest bardzo czysty. Istnieje wiele walidacji, których możesz użyć. Kilka przykładów to

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

W pierwszym przykładzie, ValidatePattern akceptuje Wyrażenie regularne, które zapewnia, że Podany parametr pasuje do tego, czego oczekujesz. Jeśli nie, intuicyjny wyjątek jest rzucany, informując dokładnie, co jest nie tak. Więc w tym przykładzie 'coś' działałoby dobrze, ale 'lato' nie przejdzie walidacji.

ValidateRange zapewnia że wartość parametru znajduje się pomiędzy zakresem oczekiwanym dla liczby całkowitej. Więc 10 lub 99 zadziała, ale 101 rzuci wyjątek.

Innym przydatnym jest ValidateSet, który pozwala na jawne zdefiniowanie tablicy dopuszczalnych wartości. Jeśli zostanie wprowadzone coś innego, zostanie wyrzucony wyjątek. Są też inne, ale prawdopodobnie najbardziej przydatnym jest ValidateScript. Wymaga to bloku skryptu, który musi zostać oceniony na $true, więc niebo jest limitem. Na przykład:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

W tym przykładzie mamy pewność, że nie tylko $Path istnieje, ale że jest to plik (w przeciwieństwie do katalogu) i ma .rozszerzenie csv. ($_ odnosi się do parametru, gdy znajduje się wewnątrz bloku skryptu.) Możesz również przekazać znacznie większe, Wielowierszowe bloki skryptów, jeśli ten poziom jest wymagany, lub użyć wielu blokad skryptów, jak to zrobiłem tutaj. Jest niezwykle przydatny i zapewnia ładne, czyste funkcje i intuicyjne wyjątki.

 19
Author: user2233949,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-31 16:11:26
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test "ABC" "DEF"
 13
Author: John B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-04 20:31:00

Jeśli jesteś programistą C # / Java / C++ / Ruby / Python / Pick-a-Language - od-tego-wieku i chcesz wywoływać swoją funkcję przecinkami, ponieważ zawsze to robiłeś, potrzebujesz czegoś takiego:

$myModule = new-module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}

Teraz zadzwoń:

$myModule.test("ABC", "DEF")

I zobaczysz

arg1 = ABC, and arg2 = DEF
 10
Author: Ryan Shillington,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-20 14:54:20

Jeśli spróbujesz:

PS > Test("ABC", "GHI") ("DEF")

Otrzymujesz:

$arg1 value: ABC GHI
$arg2 value: DEF

Więc widzisz, że nawias oddziela parametry

Jeśli spróbujesz:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

Otrzymujesz:

$arg1 value: ABC
$arg2 value: DEF

Teraz możesz znaleźć natychmiastową użyteczność nawiasu-spacja nie stanie się separatorem dla następnego parametru - zamiast tego masz funkcję eval.

 5
Author: RaSor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-20 15:01:57

Jeśli nie wiesz (lub nie zależy Ci) ile argumentów przekażesz do funkcji, możesz również użyć bardzo prostego podejścia, takiego jak;

Kod :

function FunctionName()
{
    Write-Host $args
}

To wydrukuje wszystkie argumenty. Na przykład:

FunctionName a b c 1 2 3

Wyjście

a b c 1 2 3

Uważam to za szczególnie przydatne podczas tworzenia funkcji, które używają zewnętrznych poleceń, które mogą mieć wiele różnych (i opcjonalnych) parametrów, ale polegają na tym poleceniu, aby dostarczyć informacji zwrotnych na temat błędów składniowych itd.

Oto kolejny przykład z prawdziwego świata (tworzenie funkcji do polecenia tracert, którego nienawidzę pamiętać o obciętej nazwie);

Kod :

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
 4
Author: Draino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-27 02:49:20

Nie wiem, co robisz z funkcją, ale spójrz na użycie słowa kluczowego 'param'. Jest nieco bardziej wydajny do przekazywania parametrów do funkcji i sprawia, że jest bardziej przyjazny dla użytkownika. Poniżej link do zbyt skomplikowanego artykułu Microsoftu na ten temat. To nie jest tak skomplikowane, jak brzmi artykuł. Param

Oto przykład z wątku na tej stronie:

Zobacz to.

 3
Author: Rodney Fisk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36
Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC") ("DEF")
 2
Author: kleopatra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-22 09:06:35

I stwierdza, co następuje wcześniej:

Powszechnym problemem jest użycie formy liczby pojedynczej $arg, która jest niepoprawna.
Powinna być zawsze liczba mnoga jako $args.

Nie o to chodzi.
W rzeczywistości, $arg może być czymkolwiek innym. Problemem było użycie przecinka i parantezy.
Uruchamiam następujący kod, który zadziałał, a wyjście następuje:

Kod:

Function Test([string]$var1, [string]$var2)
{
    Write-Host "`$var1 value: $var1"
    Write-Host "`$var2 value: $var2"
}

Test " ABC "" DEF "

Wyjście:

$var1 wartość: ABC $var2 value: DEF

 1
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-08 00:44:06
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

Jest to właściwa deklaracja params https://technet.microsoft.com/en-us/library/dd347600.aspx

I rzeczywiście działa

 1
Author: Sergii Kimlik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-17 13:00:09

Ponieważ jest to często oglądane pytanie chcę wspomnieć, że funkcja PowerShell powinna używać zatwierdzonych czasowników (czasownik-rzeczownik jako nazwa funkcji). Możesz również określić, czy parametr jest obowiązkowy i pozycja parametru:

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Aby przekazać parametr do funkcji możesz użyć pozycji :

Test-Script "Hello" "World"

Lub ty podaj parametr Nazwa :

Test-Script -arg1 "Hello" -arg2 "World"

Ty nie używaj nawiasów Jak to robisz, gdy wywołujesz funkcję w C#.


Polecam zawszepodawać nazwy parametrów, gdy używasz więcej niż jednego parametru, ponieważ jest to bardziej czytelne.

 1
Author: Martin Brandl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-21 18:50:50

Możesz przekazać parametry w funkcji również w ten sposób.

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}
 0
Author: Kaushal Khamar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-14 06:55:22