powershell - pass - ¿Cómo paso un rango de valores en la línea de comando? pasando una expresión como argumento
powershell pass parameters to ps1 file (1)
Tengo el siguiente código:
$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null
$srv_range | % {
$pod= $_
$servers = @()
1..2 | % {
$server = $NewVMTemplate | Select-Object *
$server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
$servers += $server
}
ForEach ( $server in $servers) {
write-host $server.Name
}
}
salida:
PowerCLI C:/ ./eraseme.ps1
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
pod29-srv1
pod29-srv2
pod30-srv1
pod30-srv2
pod40-srv1
pod40-srv2
pod50-srv1
pod50-srv2
pod51-srv1
pod51-srv2
pod52-srv1
pod52-srv2
Quiero ingresar el rango desde CLI, pero obtengo el siguiente resultado con este código
param(
[Parameter(Mandatory=$False)] $srv_range
)
#$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null
$srv_range | % {
$pod= $_
$servers = @()
1..2 | % {
$server = $NewVMTemplate | Select-Object *
$server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
$servers += $server
}
ForEach ( $server in $servers) {
write-host $server.Name
}
}
PowerCLI C:/ ./eraseme.ps1 29..30+40+50..52
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
pod29..30+40+50..52-srv1
pod29..30+40+50..52-srv2
¿Cómo puedo ingresar el rango desde CLI y obtener el mismo resultado que el primer código?
Su problema es que el argumento
29..30+40+50..52
se trata como un
literal de cadena
en su
./eraseme.ps1 29..30+40+50..52
: no se reconoce como una
expresión
.
Para
forzar el reconocimiento como una
expresión
, simplemente encierre el argumento en
(...)
:
./eraseme.ps1 (29..30+40+50..52)
Tenga en cuenta que puede hacer que su script sea más robusto declarando su parámetro con un tipo más específico , en cuyo caso un intento de llamarlo con una cadena fallaría de inmediato:
[Parameter(Mandatory=$False)] [int[]] $srv_range
(También se podrían aplicar otras optimizaciones a su secuencia de comandos).
Información de antecedentes opcional
En cuanto a cuando un token sin comillas se trata como una expresión frente a una cadena (expandible) en modo argumento (ver about_Parsing ):
-
(...)
,$(...)
y@(...)
por sí mismos o al comienzo de un token crean un nuevo contexto de análisis , en el que se pueden usar expresiones o incluso comandos anidados :-
(...)
es suficiente para una sola expresión o comando.$(...)
(el operador de subexpresión ) puede encerrar múltiples expresiones / comandos; también puede@()
(el operador de subexpresión de matriz ), y además garantiza que su salida siempre se trate como una matriz . -
En particular, las siguientes expresiones no se reconocen sin estar encerradas en una de las anteriores:
-
[...]
(escriba literales) y acceso a sus miembros, como[Environment]::Version
-
..
(expresiones de rango) como1..10
-
-
Si, al comienzo de un token ,
(...)
,$(...)
o@(...)
son seguidos por caracteres adicionales, el primer carácter adicional se considera el comienzo de un nuevo argumento separado . -
Por el contrario, si están
precedidos
por un
literal sin comillas
o una
referencia de solo variable
,
$(...)
funciona como dentro de"..."
(una cadena expandible),(...)
comienza un nuevo argumento que es una expresión, y@(...)
se toma como literal@
con(...)
nuevamente comenzando un nuevo argumento que es una expresión.
-
-
Una
@
seguida del nombre de una variable (p. Ej.,@params
) que contiene una colección o una tabla hash de valores de parámetros inicia el splatting de parámetros . -
@{ ... }
se puede usar para pasar un literal de tabla hash (por ejemplo,@{ key = ''value'' }
). -
{ ... }
crea un bloque de script ([scriptblock]
). -
Por sí mismos o al comienzo de un token , las referencias variables, incluido el acceso a los miembros (acceso a la propiedad, llamadas a métodos, indexación) se pueden usar como están :
-
Expresiones como
$HOME
,$PSVersionTable.PSVersion
,$someArray[0]
y$someString.ToUpper()
se reconocen y devuelven como su tipo inherente. -
Sin acceso de miembro, es decir, con una referencia de variable simple como
$HOME
, los caracteres subsiguientes se consideran (potencialmente) parte del mismo argumento que luego se interpreta como una cadena expandible ; consulte a continuación. -
Con acceso de miembro, el primero de los caracteres adicionales se considera el inicio de un nuevo argumento (por ejemplo,
$foo.Length-more
da como resultado dos argumentos: el valor de$foo.Length
y string literal$foo.Length
).
-
-
Todo lo demás se trata como una cadena expandible , es decir, similar al contenido de una cadena entre comillas dobles, excepto que los metacaracteres [1] aún necesitan escapar y ciertos tokens se interpretan como argumentos múltiples .
-
Expandible significa que las referencias de variables simples incrustadas (por ejemplo,
$HOME/Desktop
o$env:APPDATA/Test
) se interpolan (se reemplazan con sus valores en cadena).
Tenga en cuenta que esto puede dar como resultado una representación que difiere del formato de salida predeterminado de un valor dado como se muestra en la consola, por ejemplo (nuevamente, consulte esta respuesta para obtener más información).-
Incluya un nombre de variable en
{...}
para eliminar la ambigüedad de los caracteres posteriores, si es necesario (por ejemplo,${HOME}
).
-
Incluya un nombre de variable en
-
Para acceder a la propiedad de un valor variable o usar un índice o llamar a un método o incorporar comandos arbitrarios , debe encerrar la expresión en
$(...)
, por ejemplo,v$($PSVersionTable.PSVersion)
-
En general, es más seguro encerrar tokens con referencias / expresiones de variables incrustadas en
"..."
, ya que evita los siguientes casos límite:-
$(...)
al comienzo de un token sin comillas no se interpreta como parte de una cadena expandible , se trata como un argumento separado (por ejemplo,Write-Output $(''ab'')c
da como resultado dos argumentos: el resultado de$(''ab'')
y literalc
). -
.
al comienzo de un token seguido inmediatamente por una referencia de variable simple o subexpresión resulta en argumentos separados también .
(Por ejemplo,..$HOME
da como resultado dos argumentos: literal.
Y el valor de$HOME
)
-
-
Nota: Aunque el resultado de la expansión es una cadena, no necesariamente sigue siendo una: el tipo final está determinado por el tipo del parámetro del comando en cuestión al que está vinculado el valor expandido.
-
Escapando / citando:
-
PowerShell tiene muchos más metacaracteres que
cmd.exe
, y un obstáculo notable es que debe ser escapado para ser tratado literalmente, porque es el operador de construcción de matrices de PowerShell. -
Para escapar de un solo carácter , prefijelo con
`
(retroceso) . -
Para evitar la necesidad de escapar metacaracteres individualmente , encierre el valor en
"..."
(comillas dobles) o''...''
(comillas simples) :-
Use comillas dobles si desea que la cadena se interpole (expanda) , es decir, si desea poder incrustar referencias variables y subexpresiones.
-
Dentro de
una cadena entre comillas dobles,
`
-escape los siguientes caracteres. tratarlos como literales:` " $
-
Dentro de
una cadena entre comillas dobles,
-
Use comillas simples para tratar el valor como un literal .
-
Dentro de
una cadena entre comillas simples, escapa un
''
como''''
-
Dentro de
una cadena entre comillas simples, escapa un
-
-
Las comillas simples o dobles suelen ser la forma más fácil de escapar de espacios en un valor.
-
-
-
Finalmente, tenga en cuenta que
--%
, el llamado símbolo de detener el análisis (PSv3 +), cambia por completo la interpretación de todos los argumentos restantes: diseñado para usar con líneas de comandocmd.exe
heredadas, deja de interpretar el resto de la línea excepto expansión decmd.exe
-style%...%
variables de entorno . ConsulteGet-Help about_Parsing
En cuanto al uso de tokens citados :
-
''...''
o"..."
solos o al comienzo de un token :-
Estos se analizan como de costumbre: como una cadena literal (
''...''
) o expandible ("..."
). - Cualquier carácter adicional hace que el primer carácter adicional se considere el comienzo de un nuevo argumento separado .
-
Estos se analizan como de costumbre: como una cadena literal (
-
''...''
o"..."
están precedidos por una referencia literal o entre variables sin comillas :- Se evalúan como de costumbre y el resultado (es decir, con las comillas eliminadas) se agrega a lo que les precede (evaluado).
[1] Los
metacaracteres en modo argumento
(caracteres con significado sintáctico especial) son:
<space> '' " ` , ; ( ) { } | & < > @ #
.
De estos,
< > @ #
solo son especiales al
comienzo
de un token.
Ejemplos
Write-Output 1..10 # STRING: -> ''1..10''
Write-Output (1..10) # EXPRESSION: -> @(1, 2, ...)
# Write-Output $(1..10) would work too, but is only necessary if
# the enclosed expression comprises *multiple* statements.
Write-Output [Environment]::Version # STRING: -> ''[Environment]::Ticks''
Write-Output ([Environment]::Version) # EXPRESSION: -> a [System.Version] instance.
Write-Output a,b # !! ARRAY @(1, 2), because "," is not escaped.
Write-Output a`,b #`# STRING ''ab''
Write-Output "a,b" # ditto
Write-Output ''a,b'' # ditto
Write-Output $HOME/Desktop # EXPANDED string (e.g.) ''C:/Users/jdoe/Desktop''
Write-Output "$HOME/Desktop" # ditto
Write-Output ''$HOME/Desktop'' # LITERAL string ''$HOME/Desktop''
Write-Output dir=$HOME # EXPANDED string (e.g.) ''dir=C:/Users/jdoe/Desktop''
Write-Output $PSVersionTable.PSVersion # a [System.Version] instance
Write-Output "$($PSVersionTable.PSVersion)/more" # a [string]; e.g., ''5.1.14393.576/more''
Write-Output "v$($PSVersionTable.PSVersion)" # ditto; e.g., ''v5.1.14393.576''
# !!! These DO NOT WORK as intended.
Write-Output $($PSVersionTable.PSVersion)/more # $(...) at the *start*
Write-Output $PSVersionTable.PSVersion/more # $(...) missing
Write-Output "$PSVersionTable.PSVersion/more" # $(...) missing
Write-Output .$HOME # Specifically, .$ at the beginning is the problem; escaping . works