Solicitar entrada do usuário no PowerShell

209

Quero solicitar ao usuário uma série de entradas, incluindo uma senha e um nome de arquivo.

Eu tenho um exemplo de uso host.ui.prompt, que parece sensato, mas não consigo entender o retorno.

Existe uma maneira melhor de obter entrada do usuário no PowerShell?

AJ.
fonte

Respostas:

333

Read-Host é uma opção simples para obter entrada de string de um usuário.

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

Para ocultar senhas, você pode usar:

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

Para converter a senha em texto sem formatação:

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

Quanto ao tipo retornado por $host.UI.Prompt(), se você executar o código no link postado no comentário de @ Christian, poderá descobrir o tipo de retorno canalizando-o para Get-Member(por exemplo, $results | gm). O resultado é um dicionário onde a chave é o nome de um FieldDescriptionobjeto usado no prompt. Para acessar o resultado para o primeiro prompt no exemplo ligada você deverá digitar: $results['String Field'].

Para acessar informações sem chamar um método, deixe os parênteses desativados:

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.OverloadDefinitionsfornecerá a (s) definição (ões) do método. Cada definição é exibida como <Return Type> <Method Name>(<Parameters>).

Rynant
fonte
Obrigado, @Rynant. Resposta aceita por ser o único que realmente respondeu à minha pergunta principal! ;) Todas as outras informações também são realmente úteis, principalmente porque eu ainda estou procurando no PS.
AJ.
Não tem problema, @AJ. Outra maneira de obter informações sobre um método é deixar os parênteses. Vou adicionar um exemplo à minha resposta.
Rynant 23/11
3
Para sua informação, você também pode usar a Get-Credential se estiver recebendo nomes de usuário e senhas.
Matt Lyons
75

Usar a ligação de parâmetro é definitivamente o caminho a percorrer aqui. Não só é muito rápido escrever (basta adicionar [Parameter(Mandatory=$true)]acima dos parâmetros obrigatórios), mas também é a única opção que você não se odiará mais tarde.

Mais abaixo:

[Console]::ReadLineé explicitamente proibido pelas regras do FxCop para o PowerShell. Por quê? Porque ele funciona apenas no PowerShell.exe, não no PowerShell ISE , PowerGUI etc.

O Read-Host é, simplesmente, uma forma ruim. O Read-Host interrompe incontrolavelmente o script para avisar o usuário, o que significa que você nunca pode ter outro script que inclua o script que usa o Read-Host.

Você está tentando pedir parâmetros.

Você deve usar o [Parameter(Mandatory=$true)]atributo e corrigir a digitação para solicitar os parâmetros.

Se você usar isso em um [SecureString], ele solicitará um campo de senha. Se você usar isso em um tipo de credencial, ( [Management.Automation.PSCredential]), a caixa de diálogo de credenciais será exibida, se o parâmetro não estiver lá. Uma string se tornará uma caixa de texto antiga simples. Se você adicionar um HelpMessage ao atributo de parâmetro (ou seja, [Parameter(Mandatory = $true, HelpMessage = 'New User Credentials')]), ele se tornará um texto de ajuda para o prompt.

Automação de partida
fonte
5
Essa é a solução mais flexível e fácil de usar, mas quase ignorei seu conselho, porque não havia exemplos de código claros, como na resposta de Rynant . Você pode fornecer alguns exemplos bem formatados?
Iain Samuel McLean Elder
4
"O host de leitura é, simplesmente, uma forma ruim" ... a menos que você o esteja usando para aceitar condicionalmente as entradas deixadas de fora porque alguém não estava chamando seu script com QUALQUER parâmetro. ESTRONDO.
2
Não: ainda é uma má forma então. É por isso que você marca os parâmetros como obrigatórios.
Start-Automating
2
E se você quiser escrever um script interativo? Digamos que seja um script que exija a entrada do usuário apenas se determinadas condições forem atendidas. Por exemplo, se o seu script for configurar um diretório de destino para um SDK, convém confirmar que o usuário deseja excluir o diretório, se ele já existir.
9138 Jason Goemaat
6
Acho que o usuário1499731 teve um bom argumento ... Há momentos em que você precisa receber informações do usuário que só podem ser fornecidas de maneira significativa depois que algumas informações são exibidas ou outra operação é executada. Nesse caso, você não pode usar um parâmetro, e os motivos dados aqui para Read-Hostser "má forma" não se aplicam. Além disso, .ShouldProcess()possui restrições que Read-Hostnão existem, como limitar-se a apenas algumas respostas. No entanto, concordo que .ShouldProcess()é melhor, quando aplicável.
LarsH
14

Coloque isso na parte superior do seu script. Isso fará com que o script solicite uma senha ao usuário. A senha resultante pode ser usada em outro lugar no seu script via $ pw .

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

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

Se você deseja depurar e ver o valor da senha que você acabou de ler, use:

   write-host $pw
user2334160
fonte
3

Como alternativa, você pode adicioná-lo como um parâmetro de script para entrada como parte da execução do script

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