Cómo manejar argumentos de línea de comandos en PowerShell

494

¿Cuál es la "mejor" forma de manejar los argumentos de la línea de comandos?

Parece que hay varias respuestas sobre cuál es la "mejor" forma y, como resultado, estoy atrapado en cómo manejar algo tan simple como:

script.ps1 /n name /d domain

Y

script.ps1 /d domain /n name.

¿Hay un complemento que pueda manejar esto mejor? Sé que estoy reinventando la rueda aquí.

Obviamente, lo que ya tengo no es bonito y seguramente no es el "mejor", pero funciona ... y es feo.

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
fuente

Respuestas:

917

Estás reinventando la rueda. Los scripts normales de PowerShell tienen parámetros que comienzan con -, comoscript.ps1 -server http://devserver

Luego los manejas en la paramsección al comienzo del archivo.

También puede asignar valores predeterminados a sus parámetros, leerlos desde la consola si no está disponible o detener la ejecución del script:

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

Dentro del guión puedes simplemente

write-output $server

ya que todos los parámetros se convierten en variables disponibles en el alcance del script.

En este ejemplo, $serverobtiene un valor predeterminado si se llama al script sin él, el script se detiene si omite el -usernameparámetro y solicita la entrada del terminal si -passwordse omite.

Actualización: es posible que también desee pasar una "bandera" (un parámetro booleano verdadero / falso) a un script de PowerShell. Por ejemplo, su script puede aceptar una "fuerza" donde el script se ejecuta en un modo más cuidadoso cuando no se usa la fuerza.

La palabra clave para eso es el [switch]tipo de parámetro:

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

Dentro del guión, entonces trabajarías de esta manera:

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

Ahora, al llamar al script, establecería el parámetro switch / flag de esta manera:

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

Si desea declarar explícitamente que el indicador no está configurado, hay una sintaxis especial para eso

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

Los enlaces a la documentación relevante de Microsoft (para PowerShell 5.0; aunque las versiones 3.0 y 4.0 también están disponibles en los enlaces):

naivistas
fuente
58
De hecho, una de las grandes ventajas de PowerShell es que proporciona una infraestructura de análisis de parámetros estándar que es fácil de usar.
Keith Hill
14
@naivists, desde PowerShell 2.0 en lugar de [string]$username = $(throw "-username is required.")que hay sintaxis de parámetros obligatorios: [Parameter(Mandatory=$true)][string]$username. Aquí hay más información sobre la diferencia entre estas técnicas: blogs.technet.com/b/heyscriptingguy/archive/2011/05/22/…
v.karbovnichy
77
Tenga cuidado con el error cuando no se proporciona un argumento; powershell simplemente tomará cualquier texto adicional de la línea de comando:. \ yourscript.ps1 -server " serv " -password "mypass" typo Esto asignará mágicamente 'typo' a $ username.
sheamus
44
Sin embargo, el uso de un bloque de parámetros parece tener otras consecuencias no deseadas: stackoverflow.com/questions/40940819/…
Logan
1
@sheamus: ¡eso no es un error! Powershell procesará y asignará los argumentos en el orden en que se proporcionan, a menos que se anule utilizando el nombre de parámetro adecuado, por ejemplo, si su bloque de parámetros enumera: $ user $ pass $ server, y usted ejecuta yourscript.ps1 abc, a será configurado en $ user, b en $ pass yc en $ server, ¡A MENOS que los asigne específicamente! Entonces, si dice: yourscript.ps1 -pass abc, $ pass se establecerá en a, y los parámetros restantes (sin nombre) se usarán para completar los que faltan, en el orden indicado en el bloque de parámetros, por lo que $ user = b, $ servidor = c.
Fernando Madruga