it-swarm.com.de

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 ihm zugewiesenen Daten zu erhalten, und die verbleibenden Parameter werden als leer übergeben.

Ein schnelles Testskript:

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

Test("ABC", "DEF")

Die erzeugte Ausgabe ist

$arg1 value: ABC DEF
$arg2 value: 

Die korrekte Ausgabe sollte sein:

$arg1 value: ABC
$arg2 value: DEF

Dies scheint auf mehreren Rechnern zwischen v1 und v2 konsistent zu sein, also mache ich offensichtlich etwas falsch. Kann jemand genau darauf hinweisen, was?

381
Nasir

Parameter in Aufrufen von Funktionen in PowerShell (alle Versionen) sind durch Leerzeichen und nicht durch Kommas getrennt . Außerdem sind die Klammern nicht erforderlich und verursachen in PowerShell 2.0 (oder höher) einen Analysefehler, wenn Set-StrictMode aktiv ist. Argumente in 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
_
515
x0n

Die richtige Antwort wurde bereits gegeben, aber dieses Problem scheint weit genug verbreitet zu sein, um einige zusätzliche Details für diejenigen zu rechtfertigen, die die Feinheiten verstehen möchten. Ich hätte dies nur als Kommentar hinzugefügt, aber ich wollte eine Illustration einfügen - ich habe dies aus meinem Schnellreferenzdiagramm zu PowerShell-Funktionen herausgerissen. Dies setzt voraus, dass die Signatur der Funktion f f($a, $b, $c) ist:

syntax pitfalls of a function call

Daher kann man eine Funktion mit durch Leerzeichen getrennten Positionsparametern oder mit von der Reihenfolge unabhängigen benannten Parametern aufrufen. Die anderen Fallstricke zeigen, dass Sie Kommas, Klammern, und Leerzeichen kennen müssen.

Weitere Informationen finden Sie in meinem Artikel Down the Rabbit Hole: Eine Studie zu PowerShell-Pipelines, -Funktionen und -Parametern , der gerade auf Simple-Talk.com veröffentlicht wurde. Der Artikel enthält auch einen Link zur Kurzanleitung/Wandkarte.

240
Michael Sorens

Sie rufen PowerShell-Funktionen ohne Klammern und ohne das Komma als Trennzeichen auf. Versuchen Sie es mit:

test "ABC" "DEF"

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

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

Es setzt $a auf ein Array mit drei Werten.

43
Todd

Einige gute Antworten hier, aber ich wollte auf ein paar andere Dinge hinweisen. Funktionsparameter sind tatsächlich ein Ort, an dem PowerShell glänzt. Zum Beispiel können Sie in erweiterten Funktionen entweder benannte oder Positionsparameter haben, wie zum Beispiel:

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

Dann können Sie ihn entweder durch Angabe des Parameternamens aufrufen oder nur Positionsparameter verwenden, da Sie diese explizit definiert haben. Beides würde also funktionieren:

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

Das erste Beispiel funktioniert, obwohl Name als zweites angegeben wird, da wir den Parameternamen explizit verwendet haben. Das zweite Beispiel basiert jedoch auf der Position, sodass Name an erster Stelle stehen muss. Wenn möglich, versuche ich immer, Positionen zu definieren, damit beide Optionen verfügbar sind.

PowerShell kann auch Parametersätze definieren. Dies wird anstelle der Methodenüberladung verwendet 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 wird die Funktion entweder einen Namen oder eine ID annehmen, aber nicht beide. Sie können sie positionell oder namentlich verwenden. Da es sich um einen anderen Typ handelt, wird PowerShell es herausfinden. Das alles würde also funktionieren

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

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

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

Außerdem gibt es in PowerShell auf verwandten Seiten eine Parameterüberprüfung. Dies ist eine meiner bevorzugten PowerShell-Funktionen, durch die der Code in Ihren Funktionen sehr sauber wird. 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 angegebene Parameter Ihren Erwartungen entspricht. Wenn dies nicht der Fall ist, wird eine intuitive Ausnahme ausgelöst, die Ihnen genau sagt, was falsch ist. In diesem Beispiel würde also "Etwas" gut funktionieren, aber "Sommer" würde die Validierung nicht bestehen.

ValidateRange stellt sicher, dass der Parameterwert zwischen dem Bereich liegt, den Sie für eine Ganzzahl erwarten. Also würden 10 oder 99 funktionieren, aber 101 würde eine Ausnahme auslösen.

Ein weiterer nützlicher Befehl ist ValidateSet, mit dem Sie ein Array akzeptabler Werte explizit definieren können. Wenn etwas anderes eingegeben wird, wird eine Ausnahme ausgelöst. Es gibt auch andere, aber wahrscheinlich das nützlichste ist ValidateScript. Hierfür wird ein Skriptblock benötigt, der mit $ true ausgewertet werden muss, sodass der Himmel das Limit darstellt. 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 wird nicht nur sichergestellt, dass $ Path vorhanden ist, sondern dass es sich um eine Datei (im Gegensatz zu einem Verzeichnis) mit der Erweiterung .csv handelt. ($ _ bezieht sich auf den Parameter in Ihrem Skriptblock.) Sie können auch viel größere mehrzeilige Skriptblöcke übergeben, wenn diese Ebene erforderlich ist, oder mehrere Skriptblöcke verwenden, wie ich es hier getan habe. Es ist äußerst nützlich und sorgt für nette, saubere Funktionen und intuitive Ausnahmen.

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

Test "ABC" "DEF"
13
John B

Wenn Sie ein C #/Java/C++/Ruby/Python/Sprachauswahl-aus-diesem-Jahrhundert-Entwickler sind und anrufen möchten Ihre Funktion mit Kommas, weil das, was Sie immer getan haben, dann brauchen Sie so etwas:

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

Ruf jetzt an:

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

und du wirst sehen

arg1 = ABC, and arg2 = DEF
10

Wenn Sie nicht wissen (oder sich nicht darum kümmern), wie viele Argumente Sie an die Funktion übergeben, können Sie auch einen sehr einfachen Ansatz verwenden, wie z.

Code:

function FunctionName()
{
    Write-Host $args
}

Das würde alle Argumente ausdrucken. Zum Beispiel:

FunctionName a b c 1 2 3

Ausgabe

a b c 1 2 3

Ich finde dies besonders nützlich, wenn Funktionen erstellt werden, die externe Befehle verwenden, die viele verschiedene (und optionale) Parameter haben können, sich jedoch auf diesen Befehl stützen, um Rückmeldung zu Syntaxfehlern usw. zu geben.

Hier ist ein weiteres Beispiel aus der Praxis (Erstellen einer Funktion für den Befehl tracert, die ich nicht gern im Gedächtnis behalten muss).

Code:

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
7
Draino

Wenn du es versuchst:

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

du kriegst:

$arg1 value: ABC GHI
$arg2 value: DEF

sie sehen also, dass die Klammer die Parameter trennt

Wenn du es versuchst:

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

du kriegst:

$arg1 value: ABC
$arg2 value: DEF

Jetzt könnten Sie einen unmittelbaren Nutzen aus der Klammer ziehen - ein Leerzeichen wird nicht zum Trennzeichen für den nächsten Parameter -, stattdessen haben Sie eine Auswertungsfunktion.

5
RaSor

Ich weiß nicht, was Sie mit der Funktion machen, aber schauen Sie sich das Schlüsselwort 'param' an. Es ist um einiges leistungsfähiger, um Parameter an eine Funktion zu übergeben, und es ist benutzerfreundlicher. Unten finden Sie einen Link zu einem übermäßig komplexen Artikel von Microsoft. Es ist nicht so kompliziert, wie der Artikel es klingt. Param Usage

Hier ist auch ein Beispiel von einem Thread auf dieser Site:

Hör zu.

3
Rodney Fisk

Da dies eine häufig gestellte Frage ist, möchte ich erwähnen, dass eine PowerShell-Funktion genehmigte Verben ( Verb-Nomen als das verwenden sollte Funktionsname). Sie können auch festlegen, ob der Parameter obligatorisch und die Position des Parameters ist:

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

Um den Parameter an die Funktion zu übergeben, können Sie entweder die Position verwenden :

Test-Script "Hello" "World"

Oder Sie geben den Namen des Parameters an :

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

Sie verwenden keine Klammern wie Sie es tun, wenn Sie eine Funktion in C # aufrufen.


Ich würde empfehlen, immer die Parameternamen zu übergeben, wenn mehr als ein Parameter verwendet wird, da dies lesbarer ist .

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

Test("ABC") ("DEF")
2
user3222697
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

Dies ist die korrekte params-Deklaration https://technet.Microsoft.com/en-us/library/dd347600.aspx

Und es funktioniert tatsächlich

1
Serhii Kimlyk

Ich sage das Folgende früher:

Das häufigste Problem ist die Verwendung der Singularform $arg, die nicht korrekt ist.
Es sollte immer ein Plural als $args sein.

Das Problem ist nicht das.
Tatsächlich kann $arg alles andere sein. Das Problem war die Verwendung des Kommas und der Klammern.
Ich führe den folgenden Code aus, der funktioniert hat, und die Ausgabe folgt:

Code:

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

Test "ABC" "DEF"

Ausgabe:

$ var1-Wert: ABC $ var2-Wert: DEF

1
Eric

Ich sehe es hier nicht erwähnt, aber splatting Ihre Argumente sind eine nützliche Alternative und werden besonders nützlich, wenn Sie die Argumente für einen Befehl dynamisch erstellen (im Gegensatz zur Verwendung von Invoke-Expression ). Sie können Arrays für Positionsargumente und Hashtabellen für benannte Argumente verwenden. Hier sind einige Beispiele:

Splat mit Arrays (Positionsargumente)

Testverbindung mit Positionsargumenten

Test-Connection www.google.com localhost

Mit Array-Splatting

$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentArray

Beachten Sie, dass wir beim Aufteilen auf die aufgeteilte Variable mit einem @ anstelle eines $ verweisen. Dies gilt auch, wenn Sie eine Hashtable zum Aufteilen verwenden.

Splat With Hashtable (benannte Argumente)

Testverbindung mit benannten Argumenten

Test-Connection -ComputerName www.google.com -Source localhost

Mit Hashtable-Splatting

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash

Positionale und benannte Argumente gleichzeitig aufteilen

Testverbindung mit positionellen und benannten Argumenten

Test-Connection www.google.com localhost -Count 1

Aufteilen von Array und Hashtables

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray
0

Sie können Parameter in Funktion auch so übergeben.

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}
0
Kaushal Khamar