577 Stimmen

Wie übergebe ich mehrere Parameter an eine Funktion in PowerShell?

Wenn ich eine Funktion habe, die mehr als einen String-Parameter akzeptiert, scheint der erste Parameter alle zugewiesenen Daten zu erhalten, während die übrigen Parameter als leer übergeben werden.

Ein einfaches Testskript:

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

Test("ABC", "DEF")

Die generierte Ausgabe ist

$arg1 Wert: ABC DEF
$arg2 Wert: 

Die korrekte Ausgabe sollte sein:

$arg1 Wert: ABC
$arg2 Wert: DEF

Dies scheint auf mehreren Maschinen zwischen v1 und v2 konsistent zu sein, daher mache ich offensichtlich etwas falsch. Kann mir jemand genau zeigen, was?

8 Stimmen

Du rufst einfach so an: Test "ABC" "DEF"

2 Stimmen

Meiner bescheidenen Meinung nach zeigt die Tatsache, dass diese Frage und Antwort so viele positive Bewertungen haben, dass die aktuelle Implementierung.... nicht intuitiv ist.

746voto

x0n Punkte 49409

Parameter in Aufrufen von Funktionen in PowerShell (alle Versionen) sind Leerzeichen-getrennt, nicht komma-getrennt. Außerdem sind die Klammern vollkommen unnötig und führen zu einem Syntaxfehler in PowerShell 2.0 (oder neuer), wenn Set-StrictMode -Version 2 oder höher aktiv ist. Klammern werden nur in .NET Methoden verwendet.

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

ps> foo 1 2 3
a: 1; b: 2; c: 3

34 Stimmen

Das Wichtigste, was mir letztendlich geholfen hat, das zu begreifen, ist der letzte Satz: "Argumente in Klammern werden nur in .NET-Methoden verwendet."

4 Stimmen

Ich ziehe es vor, Klammern und Kommas zu verwenden.. ist es möglich, dies in Powershell zu tun?

10 Stimmen

@samyi Nein. Das Übergeben eines (1,2,3) an eine Funktion wird effektiv als Array behandelt; ein einzelnes Argument. Wenn Sie OO-Methode-Style-Argumente verwenden möchten, verwenden Sie Module: $m = new-module -ascustomobject { function Add($x,$y) { $x + $y } }; $m.Add(1,1)

342voto

Michael Sorens Punkte 33793

Die richtige Antwort wurde bereits gegeben, aber dieses Problem scheint weit verbreitet genug zu sein, um einige zusätzliche Details für diejenigen bereitzustellen, die die Feinheiten verstehen möchten.

Ich hätte dies nur als Kommentar hinzugefügt, aber ich wollte eine Abbildung einbeziehen - ich habe dies von meiner Schnellreferenzkarte zu PowerShell-Funktionen abgerissen. Dies setzt voraus, dass die Signatur der Funktion f f($a, $b, $c) ist:

Syntax-Fehlerquellen eines Funktionsaufrufs

Daher kann eine Funktion mit Leerzeichen getrennten positionalen Parametern oder unabhängigen benannten Parametern aufgerufen werden. Die anderen Fehlerquellen zeigen, dass Sie auf Kommas, Klammern, und Leerzeichen achten müssen.

Zum weiteren Lesen empfehle ich meinen Artikel Down the Rabbit Hole: A Study in PowerShell Pipelines, Functions, and Parameters. Der Artikel enthält auch einen Link zur Schnellreferenz-/Wandkarte.

98voto

user2233949 Punkte 1775

Es gibt hier einige gute Antworten, aber ich wollte noch auf ein paar andere Dinge hinweisen. Funktionsparameter sind tatsächlich ein Bereich, in dem PowerShell glänzt. Zum Beispiel können Sie benannte oder positionale Parameter in erweiterten Funktionen wie folgt haben:

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

Dann könnten Sie es entweder aufrufen, indem Sie den Parameternamen angeben, oder Sie könnten einfach positionale Parameter verwenden, da Sie sie explizit definiert haben. Daher würden beide dieser Beispiele funktionieren:

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

Das erste Beispiel funktioniert, obwohl Name als zweites angegeben ist, weil wir den Parameternamen explizit verwendet haben. Das zweite Beispiel funktioniert jedoch basierend auf der Position, daher müsste Name zuerst stehen. Wenn möglich, versuche ich immer, Positionen zu definieren, damit beide Optionen verfügbar sind.

PowerShell hat auch die Möglichkeit, Parametersätze zu definieren. Es verwendet dies anstelle von Methodenüberladung und ist wiederum sehr nützlich:

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
    )
}

Jetzt nimmt die Funktion entweder einen Namen oder eine ID entgegen, aber nicht beides. Sie können sie positionell oder nach Namen verwenden. Da es sich um einen anderen Typ handelt, wird PowerShell das herausfinden. Daher würden all diese funktionieren:

Get-Something "Some Name"
Get-Something 23
Get-Something -Name "Some Name"
Get-Something -Id 23

Sie können auch zusätzliche Parameter den verschiedenen Parametersätzen zuweisen. (Das war offensichtlich ein ziemlich grundlegendes Beispiel.) Innerhalb der Funktion können Sie feststellen, welcher Parametersatz mit der Eigenschaft $PsCmdlet.ParameterSetName verwendet wurde. Zum Beispiel:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Hier wird etwas mit dem Namen gemacht"
}

Dann gibt es noch die Parametervalidierung in PowerShell. Das ist eines meiner Lieblingsfeatures von PowerShell, und es macht den Code innerhalb Ihrer Funktionen sehr sauber. Es gibt zahlreiche Validierungen, die Sie verwenden können. Ein paar Beispiele sind:

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

Im ersten Beispiel akzeptiert ValidatePattern einen regulären Ausdruck, der sicherstellt, dass der übergebene Parameter mit dem übereinstimmt, was Sie erwarten. Wenn nicht, wird eine intuitive Ausnahme geworfen, die Ihnen genau sagt, was falsch ist. In diesem Beispiel würde beispielsweise 'Something' gut funktionieren, aber 'Summer' würde die Validierung nicht bestehen.

ValidateRange stellt sicher, dass der Parameterwert zwischen dem von Ihnen erwarteten Bereich für eine ganze Zahl liegt. Also 10 oder 99 würden funktionieren, aber 101 würde eine Ausnahme auslösen.

Ein weiterer nützlicher Validator ist ValidateSet, mit dem Sie explizit ein Array akzeptabler Werte definieren können. Wenn etwas anderes eingegeben wird, wird eine Ausnahme ausgelöst. Es gibt auch andere, aber wahrscheinlich ist der nützlichste ValidateScript. Dies nimmt einen Skriptblock an, der zu $true ausgewertet werden muss, also sind Ihnen keine Grenzen gesetzt. Zum Beispiel:

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

In diesem Beispiel sind wir nicht nur versichert, dass $Path existiert, sondern auch, dass es eine Datei (im Gegensatz zu einem Verzeichnis) ist und eine .csv-Erweiterung hat. ($_ bezieht sich auf den Parameter, wenn Sie sich innerhalb Ihres Skriptblocks befinden.) Sie können auch viel größere, mehrzeilige Skriptblocks übergeben, wenn diese Ebene erforderlich ist, oder mehrere Skriptblocks wie ich hier. Es ist äußerst nützlich und sorgt für saubere Funktionen und intuitive Ausnahmen.

3 Stimmen

+1 für die Demonstration des Funktionsaufruf-Stils My_Function -NamedParamater "ParamValue". Dies ist ein Muster, dem mehr PS-Skripts folgen sollten, um die Lesbarkeit zu verbessern.

1 Stimmen

Ist es ein Tippfehler, zwei Position=0 zu haben?

1 Stimmen

Nein, das ist kein Tippfehler. Das wäre der Fall, wenn Sie Parameter Sets verwenden, die im Grunde genommen nur Methodenüberladungen sind. In diesem Fall könnten entweder name ODER id übergeben werden, aber nicht beide. Da beide Position 0 sind, wird PowerShell anhand des Typs herausfinden, welchen Sie verwenden, wenn Sie den Parameternamen nicht angeben. (Eins ist int und das andere ist string)

57voto

Todd Punkte 4827

Sie rufen PowerShell-Funktionen ohne Klammern und ohne Verwendung des Kommas als Trennzeichen auf. Versuchen Sie es mit:

test "ABC" "DEF"

In PowerShell ist das Komma (,) ein Array-Operator, z.B.

$a = "eins", "zwei", "drei"

Es setzt $a auf ein Array mit drei Werten.

22voto

John B Punkte 239
Funktion Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 Wert: $arg1"
    Write-Host "`$arg2 Wert: $arg2"
}

Test "ABC" "DEF"

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X