Cómo pasar valores booleanos a un script de PowerShell desde un símbolo del sistema

103

Tengo que invocar un script de PowerShell desde un archivo por lotes. Uno de los argumentos del script es un valor booleano:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify $false

El comando falla con el siguiente error:

Cannot process argument transformation on parameter 'Unify'. Cannot convert value "System.String" to type "System.Boolean", parameters of this type only accept booleans or numbers, use $true, $false, 1 or 0 instead.

At line:0 char:1
+  <<<< <br/>
+ CategoryInfo          : InvalidData: (:) [RunScript.ps1], ParentContainsErrorRecordException <br/>
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,RunScript.ps1

A partir de ahora, estoy usando una cadena para conversión booleana dentro de mi script. Pero, ¿cómo puedo pasar argumentos booleanos a PowerShell?

mutelogan
fuente

Respuestas:

57

Parece que powershell.exe no evalúa completamente los argumentos del script cuando -Filese usa el parámetro. En particular, el $falseargumento se trata como un valor de cadena, de manera similar al ejemplo siguiente:

PS> function f( [bool]$b ) { $b }; f -b '$false'
f : Cannot process argument transformation on parameter 'b'. Cannot convert value 
"System.String" to type "System.Boolean", parameters of this type only accept 
booleans or numbers, use $true, $false, 1 or 0 instead.
At line:1 char:36
+ function f( [bool]$b ) { $b }; f -b <<<<  '$false'
    + CategoryInfo          : InvalidData: (:) [f], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,f

En lugar de usarlo -File, podría intentarlo -Command, que evaluará la llamada como script:

CMD> powershell.exe -NoProfile -Command .\RunScript.ps1 -Turn 1 -Unify $false
Turn: 1
Unify: False

Como sugiere David , usar un argumento de cambio también sería más idiomático, simplificando la llamada al eliminar la necesidad de pasar un valor booleano explícitamente:

CMD> powershell.exe -NoProfile -File .\RunScript.ps1 -Turn 1 -Unify
Turn: 1
Unify: True
Emperador XLII
fuente
6
Para aquellos (como yo) que tienen que mantener el parámetro "-File" y no pueden cambiar a un argumento de cambio, pero tienen control sobre los valores de cadena que se envían, entonces la solución más simple es convertir el parámetro en un booleano usando [System.Convert] :: ToBoolean ($ Unify); los valores de la cadena deben ser "Verdadero" o "Falso".
Chris Haines
187

Un uso más claro podría ser utilizar parámetros de cambio en su lugar. Entonces, solo la existencia del parámetro Unify significaría que se estableció.

Al igual que:

param (
  [int] $Turn,
  [switch] $Unify
)
David Mohundro
fuente
21
Esta debería ser la respuesta aceptada. Para promover la discusión, puede establecer un valor predeterminado como cualquier otro parámetro como este:[switch] $Unify = $false
Mario Tacke
Pasé por alto esta respuesta, ya que estaba seguro de que Boolean era el camino a seguir. No lo es. Switch encapsula la funcionalidad del booleano y detiene este tipo de errores: "No se puede convertir el valor" False "al tipo" System.Management.Automation.ParameterAttribute ". Los interruptores funcionaron para mí.
TinyRacoon
2
@MarioTacke Si no especifica el parámetro de cambio al invocar el script, se establece automáticamente en $false. Por tanto, no es necesario establecer explícitamente un valor predeterminado.
doubleDown
Esta sugerencia funcionó muy bien; pude actualizar uno de los parámetros de [bool] a [switch] y esto me permitió pasar el argumento a través del Programador de tareas.
JustaDaKaje
12

Esta es una pregunta anterior, pero en realidad hay una respuesta a esto en la documentación de PowerShell. Tuve el mismo problema y, por una vez, RTFM lo resolvió. Casi.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe

La documentación del parámetro -File establece que "En casos excepcionales, es posible que deba proporcionar un valor booleano para un parámetro de cambio. Para proporcionar un valor booleano para un parámetro de cambio en el valor del parámetro Archivo, incluya el nombre y el valor del parámetro en llaves, como las siguientes: -File. \ Get-Script.ps1 {-All: $ False} "

Tuve que escribirlo así:

PowerShell.Exe -File MyFile.ps1 {-SomeBoolParameter:False}

Entonces, no hay '$' antes de la declaración de verdadero / falso, y eso funcionó para mí, en PowerShell 4.0

LarsWA
fuente
1
¡Gracias por compartir! Resolvió mi problema a la perfección.
Julia Schwarz
1
El enlace de la respuesta parece haber cambiado de contenido. Sin embargo, encontré la respuesta aquí
Slogmeister Extraordinaire
Enlace de documentación actual about_powershell.exe alternativamente simplemente sonópowershell -h .
Set
Me sorprende que esta incómoda solución haya funcionado alguna vez; no funciona en Windows PowerShell v5.1 (ni con ni sin un líder $); También tenga en cuenta que ya no es necesario en PowerShell Core . He pedido que se corrija la documentación; ver github.com/MicrosoftDocs/PowerShell-Docs/issues/4964
mklement0
11

Intente configurar el tipo de su parámetro en [bool]:

param
(
    [int]$Turn = 0
    [bool]$Unity = $false
)

switch ($Unity)
{
    $true { "That was true."; break }
    default { "Whatever it was, it wasn't true."; break }
}

Este ejemplo valores predeterminados $Unitya $falsesi no se proporciona de entrada.

Uso

.\RunScript.ps1 -Turn 1 -Unity $false
Filburt
fuente
1
La respuesta del Emperador XLII y su comentario sobre el -Fileparámetro deben cubrir todos los aspectos de la pregunta original. Dejaré mi respuesta porque alguien también puede encontrar útil mi sugerencia sobre cómo proporcionar un valor predeterminado.
Filburt
Bien hecho Filburt. Su respuesta hizo que revisara mi script, que ya tiene especificado por defecto como el valor requerido $ false (escribí eso hace varios años y lo había olvidado por completo), por lo que ni siquiera tengo que especificar el parámetro booleano problemático en el línea de comando ahora. Excelente :)
Zeek2
5

Creo que la mejor manera de usar / establecer un valor booleano como parámetro es usarlo en su script PS así:

Param(
    [Parameter(Mandatory=$false)][ValidateSet("true", "false")][string]$deployApp="false"   
)

$deployAppBool = $false
switch($deployPmCmParse.ToLower()) {
    "true" { $deployAppBool = $true }
    default { $deployAppBool = $false }
}

Entonces ahora puedes usarlo así:

.\myApp.ps1 -deployAppBool True
.\myApp.ps1 -deployAppBool TRUE
.\myApp.ps1 -deployAppBool true
.\myApp.ps1 -deployAppBool "true"
.\myApp.ps1 -deployAppBool false
#and etc...

Entonces, en los argumentos de cmd, puede pasar un valor booleano como una cadena simple :).

Drasius
fuente
2

En PowerShell, los parámetros booleanos se pueden declarar mencionando su tipo antes de su variable.

    function GetWeb() {
             param([bool] $includeTags)
    ........
    ........
    }

Puede asignar valor pasando $ true | $ falso

    GetWeb -includeTags $true
Ahmed Ali
fuente
Simplemente pasar los argumentos de entrada nombrados explícitamente así funcionó de maravilla. Gracias Ahmed
Steve Taylor
0

Para resumir y complementar las respuestas existentes , a partir de Windows PowerShell v5.1 / PowerShell Core 7.0.0-preview.4:

La respuesta de David Mohundro apunta con razón que, en lugar de [bool]parámetros, debe usar [switch]parámetros en PowerShell , donde la presencia frente a la ausencia del nombre del interruptor ( -Unifyespecificado frente a no especificado) implica su valor , lo que hace que el problema original desaparezca.


Sin embargo, en ocasiones, es posible que deba pasar el valor del conmutador explícitamente , especialmente si está construyendo una línea de comando mediante programación :


En PowerShell Core , el problema original (descrito en la respuesta del Emperador XLII ) se ha solucionado .

Es decir, para pasar $trueexplícitamente a un [switch]parámetro llamado -Unify, ahora puede escribir:

pwsh -File .\RunScript.ps1 -Unify:$true  # !! ":" separates name and value, no space

Los siguientes valores se pueden utilizar: $false, false, $true, true, pero tenga en cuenta que la aprobación 0o 1hace no trabajo.

Tenga en cuenta que el nombre del conmutador está separado del valor con :y no debe haber espacios en blanco entre los dos.

Nota: Si declara un [bool]parámetro en lugar de a [switch](que generalmente no debería), debe usar la misma sintaxis; aunque-Unify $false debería funcionar, actualmente no lo hace; vea este problema de GitHub .


En Windows PowerShell , el problema original persiste y, dado que Windows PowerShell ya no se desarrolla activamente, es poco probable que se solucione.

  • La solución alternativa sugerida en la respuesta de LarsWA, aunque se basa en el tema de ayuda oficial al momento de escribir este artículo, no funciona en v5.1

    • Este problema de GitHub solicita que se corrija la documentación y también proporciona un comando de prueba que muestra la ineficacia de la solución.
  • Usar en -Commandlugar de -Filees la única solución eficaz :

:: # From cmd.exe
powershell -Command "& .\RunScript.ps1 -Unify:$true" 

Con -Commandestá pasando efectivamente una parte del código de PowerShell , que luego se evalúa como de costumbre, y dentro de PowerShell pasa $truey $falsefunciona (pero no true y false, como ahora también se acepta -File).

Advertencias :

  • El uso -Commandpuede resultar en una interpretación adicional de sus argumentos, como si contienen $caracteres. (con-File , los argumentos son literales ).

  • El uso -Commandpuede resultar en un código de salida diferente .

Para obtener más detalles, consulte esta respuesta y esta respuesta .

mklement0
fuente
0

Tuve algo similar al pasar un script a una función con invoke-command. Ejecuté el comando entre comillas simples en lugar de comillas dobles, porque luego se convierte en una cadena literal.'Set-Mailbox $sourceUser -LitigationHoldEnabled $false -ElcProcessingDisabled $true';

Bb
fuente
0

Ejecutar scripts de powershell en linux desde bash da el mismo problema. Lo resolvió casi igual que la respuesta de LarsWA:

Trabajando:

pwsh -f ./test.ps1 -bool:true

No funciona:

pwsh -f ./test.ps1 -bool=1
pwsh -f ./test.ps1 -bool=true
pwsh -f ./test.ps1 -bool true
pwsh -f ./test.ps1 {-bool=true}
pwsh -f ./test.ps1 -bool=$true
pwsh -f ./test.ps1 -bool=\$true
pwsh -f ./test.ps1 -bool 1
pwsh -f ./test.ps1 -bool:1
JanRK
fuente
-3

También puede utilizar 0para Falseo 1para True. De hecho, sugiere que en el mensaje de error:

No se puede procesar la transformación de argumentos en el parámetro 'Unificar'. No se puede convertir el valor "System.String"a tipo "System.Boolean", los parámetros de este tipo sólo aceptan booleanos o números, uso $true, $false, 1 o 0 en su lugar.

Para obtener más información, consulte este artículo de MSDN sobre valores y operadores booleanos .

Rahs
fuente
10
Eso no funciona. Está esperando el número entero 1 o 0, pero pasarlo lo -Fileinterpreta como una cadena, por lo que falla con el mismo error.
Erti-Chris Eelmaa
Esta respuesta es incorrecta, ya que la sugerencia no funciona
mjs