Umgang mit Befehlszeilenargumenten in PowerShell

494

Was ist der "beste" Weg, um mit Befehlszeilenargumenten umzugehen?

Es scheint, als gäbe es mehrere Antworten darauf, was der "beste" Weg ist, und daher bin ich nicht sicher, wie ich mit etwas so Einfachem umgehen soll wie:

script.ps1 /n name /d domain

UND

script.ps1 /d domain /n name.

Gibt es ein Plugin, das damit besser umgehen kann? Ich weiß, dass ich das Rad hier neu erfinde.

Offensichtlich ist das, was ich bereits habe, nicht schön und sicherlich nicht das "Beste", aber es funktioniert ... und es ist hässlich.

for ( $i = 0; $i -lt $args.count; $i++ ) {
    if ($args[ $i ] -eq "/n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-n"){ $strName=$args[ $i+1 ]}
    if ($args[ $i ] -eq "/d"){ $strDomain=$args[ $i+1 ]}
    if ($args[ $i ] -eq "-d"){ $strDomain=$args[ $i+1 ]}
}
Write-Host $strName
Write-Host $strDomain
Aaron Wurthmann
quelle

Antworten:

917

Sie erfinden das Rad neu. Normale Powershell - Skripts haben Parameter , beginnend mit -, wiescript.ps1 -server http://devserver

Dann behandeln Sie sie im paramAbschnitt am Anfang der Datei.

Sie können Ihren Parametern auch Standardwerte zuweisen, diese von der Konsole lesen, falls sie nicht verfügbar sind, oder die Skriptausführung stoppen:

 param (
    [string]$server = "http://defaultserver",
    [Parameter(Mandatory=$true)][string]$username,
    [string]$password = $( Read-Host "Input password, please" )
 )

Innerhalb des Skripts können Sie einfach

write-output $server

da alle Parameter zu Variablen werden, die im Skriptbereich verfügbar sind.

In diesem Beispiel $servererhält das einen Standardwert, wenn das Skript ohne dieses aufgerufen wird. Das Skript wird angehalten, wenn Sie den -usernameParameter weglassen , und fragt nach einer Terminaleingabe, wenn -passwordes weggelassen wird.

Update: Möglicherweise möchten Sie auch ein "Flag" (einen booleschen true / false-Parameter) an ein PowerShell-Skript übergeben. Beispielsweise akzeptiert Ihr Skript möglicherweise eine "Kraft", bei der das Skript in einem vorsichtigeren Modus ausgeführt wird, wenn keine Kraft verwendet wird.

Das Schlüsselwort dafür ist [switch]Parametertyp:

 param (
    [string]$server = "http://defaultserver",
    [string]$password = $( Read-Host "Input password, please" ),
    [switch]$force = $false
 )

Innerhalb des Skripts würden Sie dann folgendermaßen damit arbeiten:

if ($force) {
  //deletes a file or does something "bad"
}

Wenn Sie jetzt das Skript aufrufen, setzen Sie den Parameter switch / flag wie folgt:

.\yourscript.ps1 -server "http://otherserver" -force

Wenn Sie ausdrücklich angeben möchten, dass das Flag nicht gesetzt ist, gibt es dafür eine spezielle Syntax

.\yourscript.ps1 -server "http://otherserver" -force:$false

Links zu relevanten Microsoft-Dokumentationen (für PowerShell 5.0; die Versionen 3.0 und 4.0 sind auch unter den Links verfügbar):

Naivisten
quelle
58
Einer der großen Vorteile von PowerShell besteht darin, dass es eine Standardparameter-Parsing-Infrastruktur bietet, die einfach zu verwenden ist.
Keith Hill
14
@naivists, ab PowerShell 2.0 [string]$username = $(throw "-username is required.")gibt es stattdessen eine Syntax für obligatorische Parameter : [Parameter(Mandatory=$true)][string]$username. Hier finden Sie weitere Informationen zum Unterschied zwischen diesen Techniken: blogs.technet.com/b/heyscriptingguy/archive/2011/05/22/…
v.karbovnichy
7
Seien Sie vorsichtig mit dem Fehler, wenn kein Argument geliefert wird. Powershell holt sich einfach zusätzlichen Text aus der Befehlszeile :. \ yourscript.ps1 -server " serv " -Kennwort "mypass" Tippfehler Dies weist $ username auf magische Weise 'Tippfehler' zu.
Sheamus
4
Die Verwendung eines Parameterblocks scheint jedoch andere unbeabsichtigte Konsequenzen zu haben: stackoverflow.com/questions/40940819/…
Logan
1
@sheamus: das ist kein bug! Powershell verarbeitet und weist die Argumente in der angegebenen Reihenfolge zu, sofern sie nicht durch Verwendung des richtigen Parameternamens überschrieben werden, z. B. wenn Ihr Parameterblock Folgendes auflistet: $ user $ pass $ server, und Sie führen Ihre script.ps1 abc aus Setzen Sie in $ user, b in $ pass und c in $ server, es sei denn, Sie weisen sie speziell zu! Wenn Sie also sagen: yourscript.ps1 -pass abc, wird $ pass auf a gesetzt und die verbleibenden (unbenannten) Parameter werden verwendet, um die fehlenden in der im Parameterblock angegebenen Reihenfolge auszufüllen, also $ user = b, $ server = c.
Fernando Madruga