Solicitar la entrada del usuario en PowerShell

209

Quiero solicitar al usuario una serie de entradas, incluida una contraseña y un nombre de archivo.

Tengo un ejemplo de uso host.ui.prompt, que parece razonable, pero no puedo entender el retorno.

¿Hay una mejor manera de obtener la entrada del usuario en PowerShell?

AJ
fuente

Respuestas:

333

Read-Host es una opción simple para obtener una entrada de cadena de un usuario.

$name = Read-Host 'What is your username?'

Para ocultar contraseñas puedes usar:

$pass = Read-Host 'What is your password?' -AsSecureString

Para convertir la contraseña a texto sin formato:

[Runtime.InteropServices.Marshal]::PtrToStringAuto(
    [Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass))

En cuanto al tipo devuelto por $host.UI.Prompt(), si ejecuta el código en el enlace publicado en el comentario de @ Christian, puede encontrar el tipo de retorno canalizándolo a Get-Member(por ejemplo $results | gm). El resultado es un diccionario donde la clave es el nombre de un FieldDescriptionobjeto utilizado en la solicitud. Para acceder al resultado de la primera solicitud en el ejemplo vinculado, escriba:$results['String Field'] .

Para acceder a la información sin invocar un método, deje los paréntesis desactivados:

PS> $Host.UI.Prompt

MemberType          : Method
OverloadDefinitions : {System.Collections.Generic.Dictionary[string,psobject] Pr
                    ompt(string caption, string message, System.Collections.Ob
                    jectModel.Collection[System.Management.Automation.Host.Fie
                    ldDescription] descriptions)}
TypeNameOfValue     : System.Management.Automation.PSMethod
Value               : System.Collections.Generic.Dictionary[string,psobject] Pro
                    mpt(string caption, string message, System.Collections.Obj
                    ectModel.Collection[System.Management.Automation.Host.Fiel
                    dDescription] descriptions)
Name                : Prompt
IsInstance          : True

$Host.UI.Prompt.OverloadDefinitionsle dará la (s) definición (es) del método. Cada definición se muestra como <Return Type> <Method Name>(<Parameters>).

Rynant
fuente
Gracias, @Rynant. ¡Respuesta aceptada por ser el único que realmente respondió mi pregunta principal! ;) Toda la otra información es realmente útil también, especialmente porque todavía estoy buscando mi lugar en PS.
AJ.
No hay problema, @AJ. Otra forma de obtener información sobre un método es omitir los paréntesis. Agregaré un ejemplo a mi respuesta.
Rynant
3
Para su información, también puede usar Get-Credential si obtiene nombres de usuario y contraseñas.
Matt Lyons
75

Usar el enlace de parámetros es definitivamente el camino a seguir aquí. No solo es muy rápido de escribir (solo agregue por [Parameter(Mandatory=$true)]encima de sus parámetros obligatorios), sino que también es la única opción que no se odiará más adelante.

Más abajo:

[Console]::ReadLineestá explícitamente prohibido por las reglas de FxCop para PowerShell. ¿Por qué? Porque solo funciona en PowerShell.exe, no en PowerShell ISE , PowerGUI , etc.

Read-Host es, simplemente, una mala forma. Read-Host detiene incontrolablemente el script para solicitar al usuario, lo que significa que nunca podrá tener otro script que incluya el script que utiliza Read-Host.

Estás tratando de pedir parámetros.

Debe usar el [Parameter(Mandatory=$true)]atributo y escribir correctamente para solicitar los parámetros.

Si usa esto en un [SecureString], solicitará un campo de contraseña. Si usa esto en un tipo de Credencial, ( [Management.Automation.PSCredential]), aparecerá el cuadro de diálogo de credenciales, si el parámetro no está allí. Una cadena simplemente se convertirá en un cuadro de texto antiguo simple. Si agrega un mensaje de ayuda al atributo de parámetro (es decir, [Parameter(Mandatory = $true, HelpMessage = 'New User Credentials')]) se convertirá en texto de ayuda para el mensaje.

Comenzar a automatizar
fuente
55
Esta es la solución más flexible y fácil de usar, pero casi ignoré su consejo porque no había ejemplos de código claro como en la respuesta de Rynant . ¿Puedes proporcionar algunos ejemplos bien formateados?
Iain Samuel McLean Élder
44
"Read-Host es, simplemente, una mala forma" ... a menos que lo esté usando para aceptar condicionalmente la entrada que se omitió porque alguien no estaba llamando a su script con CUALQUIER parámetro. AUGE.
2
No: todavía es mala forma entonces. Es por eso que marca los parámetros como obligatorios.
Comienza a automatizar el
2
¿Qué pasa si quieres escribir un guión interactivo? Digamos que es un script que solo requiere la entrada del usuario si se cumplen ciertas condiciones. Por ejemplo, si su script debe configurar un directorio de destino para un SDK, es posible que desee confirmar que el usuario desea eliminar el directorio si ya existe.
Jason Goemaat
66
Creo que user1499731 tenía un buen punto ... Hay momentos en los que necesita recibir información del usuario que solo se puede proporcionar de manera significativa después de que se muestre cierta información o se realice otra operación. En ese caso, no puede usar un parámetro, y las razones dadas aquí para Read-Hostser "mala forma" no se aplican. Además, .ShouldProcess()tiene restricciones que Read-Hostno, como limitarse a solo unas pocas respuestas. Sin embargo, estoy de acuerdo en que .ShouldProcess()es mejor, cuando sea aplicable.
LarsH
14

Coloque esto en la parte superior de su secuencia de comandos. Hará que el script solicite al usuario una contraseña. La contraseña resultante se puede usar en otra parte de su script a través de $ pw .

   Param(
     [Parameter(Mandatory=$true, Position=0, HelpMessage="Password?")]
     [SecureString]$password
   )

   $pw = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))

Si desea depurar y ver el valor de la contraseña que acaba de leer, use:

   write-host $pw
usuario2334160
fuente
3

Como alternativa, puede agregarlo como parámetro de script para la entrada como parte de la ejecución del script

 param(
      [Parameter(Mandatory = $True,valueFromPipeline=$true)][String] $value1,
      [Parameter(Mandatory = $True,valueFromPipeline=$true)][String] $value2
      )
Disidente
fuente