Terminando um script no PowerShell

394

Eu estava procurando uma maneira de finalizar um script do PowerShell (PS1) quando ocorre um erro irrecuperável dentro de uma função. Por exemplo:

function foo() {
    # Do stuff that causes an error
    $host.Exit()
}

Claro que não existe $host.Exit(). Existe $host.SetShouldExit(), mas isso realmente fecha a janela do console, que não é o que eu quero. O que eu preciso é de algo equivalente ao Python sys.exit()que simplesmente pare a execução do script atual sem mais delongas.

Edit: Sim, é apenas exit. Duh.

kprobst
fonte
8
Se você quiser evitar fechar a janela do PowerShell ou o ISE no meu caso; use "return". Apenas termina o contexto atual de execução. O "cara novo" explica completamente todas as opções para fins educacionais; convém alterar sua resposta aceita (atualmente tem mais votos positivos) para futuros usuários do StackOverflow. Isso permitirá que você depure o script também.
ZaxLofful
Isso responde sua pergunta? O que exatamente é "saída" no PowerShell?
Mark Schultheiss

Respostas:

389

Você deve usar a exitpalavra-chave .

Michael Bray
fonte
15
Puta merda, se eu não estivesse tão envolvido tentando descobrir como fazer essas coisas de maneira inteligente, provavelmente teria tentado isso para começar e descobri que funciona :) Obrigado.
precisa saber é o seguinte
118
Como é essa a resposta aceita? Ele "fecha a janela do console" especificamente, o que o autor da pergunta disse "que não é o que eu quero".
claudekennilol
3
@claudekennilol Somente o autor da pergunta pode aceitar uma resposta. Perderam o fato de que a saída deveria fechar a janela ou mudaram de idéia e consideraram aceitável para seus propósitos.
Iszi
3
Ele não fecha a janela do console na v3 ou v4, que eu uso. Bem, isso acontecerá se você executar o script no explorer, mas não importa como você finalize o script, ele fará isso. Se estiver executando em uma janela de comando do PowerShell, ela não fecha a janela.
Joshua Nurczyk
14
A resposta de New Guy é muito mais minuciosa e os merecedores são marcados como aceitos.
perfil completo de Jim Aho
585

Percebo que este é um post antigo, mas me vejo voltando muito a esse tópico, pois é um dos principais resultados de pesquisa ao pesquisar esse tópico. No entanto, sempre deixo mais confuso do que quando cheguei devido às informações conflitantes. Em última análise, eu sempre tenho que realizar meus próprios testes para descobrir isso. Então desta vez vou postar minhas descobertas.

TL; DR A maioria das pessoas desejará usar Exitpara finalizar os scripts em execução. No entanto, se seu script estiver apenas declarando funções para serem usadas posteriormente em um shell, você desejará usarReturn nas definições dessas funções.

Saída x Retorno x Ruptura

  • Saída: Isso "sairá" do contexto em execução no momento. Se você chamar esse comando a partir de um script, ele sairá do script. Se você chamar esse comando do shell, ele sairá do shell.

    Se uma função chamar o comando Exit, ela sairá do contexto em que estiver sendo executada. Portanto, se essa função for chamada apenas de dentro de um script em execução, ela será encerrada. No entanto, se o seu script apenas declarar a função para que possa ser usada no shell atual e você a executar a partir do shell, ele sairá do shell porque o shell é o contexto no qual a função que contém o Exitcomando está sendo executada.

    Nota: Por padrão, se você clicar com o botão direito do mouse em um script para executá-lo no PowerShell, assim que o script for executado, o PowerShell será fechado automaticamente. Isso não tem nada a ver com o Exitcomando ou qualquer outra coisa no seu script. É apenas um comportamento padrão do PowerShell para scripts sendo executados usando este método específico de execução de um script. O mesmo vale para arquivos em lotes e para a janela Linha de Comando.

  • Retorno: Isso retornará ao ponto de chamada anterior. Se você chamar esse comando a partir de um script (fora de qualquer função), ele retornará ao shell. Se você chamar esse comando do shell, ele retornará ao shell (que é o ponto de chamada anterior para um único comando executado no shell). Se você chamar esse comando de uma função, ele retornará para onde quer que a função tenha sido chamada.

    A execução de qualquer comando após o ponto de chamada para o qual ele é retornado continuará a partir desse ponto. Se um script for chamado a partir do shell e ele contiver o Returncomando fora de qualquer função, quando retornar ao shell, não haverá mais comandos a serem executados, fazendo com que o Returnusado dessa maneira seja essencialmente o mesmo que Exit.

  • Interromper: Isso interrompe os loops e alterna os casos. Se você chamar esse comando enquanto não estiver em loop ou alternar entre maiúsculas e minúsculas, o script será interrompido. Se você chamar Breakdentro de um loop aninhado dentro de um loop, ele sairá apenas do loop no qual foi chamado.

    Há também um recurso interessante de Breakonde você pode prefixar um loop com um rótulo e, em seguida, pode interromper esse loop rotulado, mesmo que o Breakcomando seja chamado dentro de vários grupos aninhados dentro desse loop rotulado.

    While ($true) {
        # Code here will run
    
        :myLabel While ($true) {
            # Code here will run
    
            While ($true) {
                # Code here will run
    
                While ($true) {
                    # Code here will run
                    Break myLabel
                    # Code here will not run
                }
    
                # Code here will not run
            }
    
            # Code here will not run
        }
    
        # Code here will run
    }
Cara novo
fonte
39
Também vale a pena notar que Exitpode usar um código de retorno como parâmetro (o padrão é 0) - por exemplo Exit 3.
Aucuparia
2
Eu concordo, esta é uma resposta muito melhor. "Pausa" pode ter conseqüências não intencionais.
Iagomartinez
Não sei se o seu comentário sobre "Sair" está completamente correto, embora seja uma ótima resposta no geral. A saída parece estar causando o fechamento do ISE de uma maneira que nada mais parece estar fazendo. Simplesmente sair do contexto (por exemplo, a conclusão do script) não faz isso.
Bill K
11
@ BillK De fato. Eu atualizei a resposta. Quando escrevi isso pela primeira vez, lembro de não encontrar nenhuma documentação oficial sobre Exit. Eu então fiz um Get-Command Exite Get-Alias Exitsem resultados. Procurei então se era uma palavra-chave e não encontrei nenhuma documentação oficial. Olhando agora, no entanto, não sei como cheguei a essa conclusão. Claramente, é uma palavra-chave ( technet.microsoft.com/en-us/library/hh847744.aspx ). Talvez porque Exit seja uma das únicas palavras-chave que não possui um tópico de ajuda sobre_ próprio e, portanto, a lista de tópicos na barra lateral esquerda não o incluiu.
New Guy
6
E o Throw?
JDC
80

Exittambém sairá do PowerShell. Se você deseja "quebrar" apenas a função ou script atual - use Break:)

If ($Breakout -eq $true)
{
     Write-Host "Break Out!"
     Break
}
ElseIf ($Breakout -eq $false)
{
     Write-Host "No Breakout for you!"
}
Else
{
    Write-Host "Breakout wasn't defined..."
}
EverydayNerd
fonte
5
Por favor, não use isso breakquando quiser apenas interromper a função atual ... os scripts de chamada também podem ser interrompidos!
DannyMeister
49

Write-Error é para erros sem finalização e throw é para erros com finalização

O cmdlet Write-Error declara um erro sem fim. Por padrão, os erros são enviados no fluxo de erros para o programa host a ser exibido, juntamente com a saída.

Erros que não terminam gravam um erro no fluxo de erros, mas não param o processamento do comando. Se um erro sem finalização for declarado em um item em uma coleção de itens de entrada, o comando continuará processando os outros itens na coleção.

Para declarar um erro de encerramento, use a palavra-chave Throw. Para obter mais informações, consulte about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).

Greg Bray
fonte
4
Essa parece a maneira mais correta de encerrar uma atividade com um erro. Ele delega ao chamador para tentar lidar com o erro, o que é muito melhor do que simplesmente tentar terminar abruptamente.
Paul Turner
Para mim, pelo menos nas funções do módulo, lance saídas, mas não define um código de saída. Isso foi executado via CLI, por exemplo powershell -command "& module-function ...". Eu precisava converter essas funções para lançar em um try-catch de empacotamento e sair dessa captura de empacotamento para realmente gerar um código de saída de erro.
Josh
2
Não se esqueça $PSCmdlet.ThrowTerminatingError()para aqueles casos em que jogue só não pode fazer o trabalho (problema conhecido com erros nenhum terminação de throw)
Djarid
33

Finaliza esse processo e fornece ao sistema operacional subjacente o código de saída especificado.

https://msdn.microsoft.com/en-us/library/system.environment.exit%28v=vs.110%29.aspx

[Environment]::Exit(1)

Isso permitirá que você saia com um código de saída específico, que pode ser retirado do chamador.

gabriwinter
fonte
3
No PowerShell, você pode simplesmente usar a Saída interna para isso, por exemplo Exit 1.
Jonas19
3
A saída interna nem sempre funcionará conforme o esperado. Tente isso no powershell: "Saída 5"> test1.ps1 powershell.exe. \ Test1.ps1 $ lastexitcode "[Environment] :: Exit (5)"> test2.ps1 powershell.exe. \ Test2.ps1 $ lastexitcode
gabriwinter
11
[Environment]::Exit(1)tem o efeito colateral de sair da janela do PowerShell quando eu a invoco em um script, onde o uso exitnão parece fazer isso.
Josh Desmond
25

Eu acho que você está procurando em Returnvez de Break. A quebra é normalmente usada para loops e apenas quebra do bloco de código mais interno. Use Return para sair de uma função ou script.

Roubar
fonte
7
Isso não está correto - o OP solicita especificamente a saída de um script de dentro de uma função . Returnsimplesmente retornará da função, não do script. ( ReturnNo topo nível de um script será finalizado o roteiro, mas isso não era a questão.)
Michael Sorens
11
essa 'resposta' realmente comenta a resposta do EverydayNerd?
precisa saber é o seguinte
22

Lançar uma exceção será bom, especialmente se você desejar esclarecer o motivo do erro:

throw "Error Message"

Isso irá gerar um erro de finalização.

Amr Bahaa
fonte
3
Eu não acho que isso acrescenta mais do que a resposta de Greg Bray quase um ano antes stackoverflow.com/a/20556550/695671
Jason S
12

Pode ser que seja melhor usar "trap". Uma interceptação do PowerShell especifica um bloqueio de código a ser executado quando ocorrer um erro ou finalização. Tipo

Get-Help about_trap

para saber mais sobre a declaração de armadilha.

fpschultze
fonte
10

Por coincidência, descobri que (por exemplo , simplesmente , onde o rótulo não existe ) parece romper o script inteiro (mesmo de dentro de uma função) e mantém o host vivo. Dessa forma, você pode criar uma função que quebre o script de qualquer lugar (por exemplo, um loop recursivo) sem conhecer o escopo atual (e criar rótulos):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 
ferro
fonte
11
A sua resposta é verdade, mas estar ciente que esta pode causar problemas para chamadores de seu script, se eles não concordam com o seu desejo de sair todo o script: stackoverflow.com/questions/45746588/...
DannyMeister
5

Eu usei isso para uma reexecução de um programa. Não sei se isso ajudaria, mas é uma instrução if simples que requer apenas duas entradas diferentes. Funcionou em PowerShell para mim.

$rerun = Read-Host "Rerun report (y/n)?"

if($rerun -eq "y") { Show-MemoryReport }
if($rerun -eq "n") { Exit }

Não sei se isso ajuda, mas acredito que isso seria ao longo das linhas de finalizar um programa depois de executá-lo. No entanto, neste caso, toda entrada definida requer uma saída listada e categorizada. Você também pode solicitar que a saída chame uma nova linha de prompt e encerre o programa dessa maneira.

Michael Meli
fonte