Comment gérer les arguments de ligne de commande dans PowerShell

494

Quelle est la "meilleure" façon de gérer les arguments de ligne de commande?

Il semble qu'il y ait plusieurs réponses sur ce qu'est la "meilleure" façon et en conséquence je suis coincé sur la façon de gérer quelque chose d'aussi simple que:

script.ps1 /n name /d domain

ET

script.ps1 /d domain /n name.

Existe-t-il un plugin qui peut mieux gérer cela? Je sais que je réinvente la roue ici.

Évidemment, ce que j'ai déjà n'est pas joli et n'est sûrement pas le "meilleur", mais ça marche .. et c'est Moche.

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
la source

Réponses:

917

Vous réinventez la roue. Les scripts PowerShell normaux ont des paramètres commençant par -, commescript.ps1 -server http://devserver

Ensuite, vous les gérez dans la paramsection au début du fichier.

Vous pouvez également attribuer des valeurs par défaut à vos paramètres, les lire depuis la console s'ils ne sont pas disponibles ou arrêter l'exécution du script:

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

Dans le script, vous pouvez simplement

write-output $server

puisque tous les paramètres deviennent des variables disponibles dans la portée du script.

Dans cet exemple, le $serverobtient une valeur par défaut si le script est appelé sans lui, le script s'arrête si vous omettez le -usernameparamètre et demande une entrée de terminal si -passwordest omis.

Mise à jour: vous pouvez également vouloir passer un "indicateur" (un paramètre booléen vrai / faux) à un script PowerShell. Par exemple, votre script peut accepter une "force" où le script s'exécute dans un mode plus prudent lorsque la force n'est pas utilisée.

Le mot clé pour cela est le [switch]type de paramètre:

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

À l'intérieur du script, vous travailleriez avec comme ceci:

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

Maintenant, lorsque vous appelez le script, vous définissez le paramètre switch / flag comme ceci:

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

Si vous souhaitez explicitement indiquer que l'indicateur n'est pas défini, il existe une syntaxe spéciale pour cela

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

Liens vers la documentation Microsoft pertinente (pour PowerShell 5.0; les versions 3.0 et 4.0 sont également disponibles sur les liens):

naïvistes
la source
58
En effet, l'un des grands avantages de PowerShell est qu'il fournit une infrastructure d'analyse de paramètres standard facile à utiliser.
Keith Hill
14
@naivists, de PowerShell 2.0 au lieu de [string]$username = $(throw "-username is required.")il y a syntaxe des paramètres obligatoires: [Parameter(Mandatory=$true)][string]$username. Voici plus d'informations sur la différence entre ces techniques: blogs.technet.com/b/heyscriptingguy/archive/2011/05/22/…
v.karbovnichy
7
Méfiez-vous du bogue quand un argument n'est pas fourni; powershell récupérera tout texte supplémentaire à partir de la ligne de commande:. \ yourscript.ps1 -server " serv " -password "mypass" typo Ceci affectera comme par magie "typo" à $ username.
sheamus
4
L'utilisation d'un bloc param semble avoir d'autres conséquences inattendues cependant: stackoverflow.com/questions/40940819/…
Logan
1
@sheamus: ce n'est pas un bug! Powershell traitera et assignera les arguments dans l'ordre qui leur est donné, à moins qu'il ne soit remplacé en utilisant le nom de paramètre approprié, par exemple, si votre bloc de paramètres répertorie: $ user $ pass $ server et que vous exécutez abc yourscript.ps1, un sera mis en $ user, b en $ pass et c en $ server, à moins que vous ne les assigniez spécifiquement! Donc, si vous dites: yourscript.ps1 -pass abc, $ pass sera défini sur a, et les paramètres restants (sans nom) seront utilisés pour remplir les paramètres manquants, dans l'ordre indiqué dans le bloc de paramètres, donc $ user = b, $ serveur = c.
Fernando Madruga