Observando um script Get-WebFile no PoshCode, http://poshcode.org/3226 , notei esta engenhoca estranha para mim:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Qual o motivo disso, ao contrário do seguinte?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Ou melhor ainda:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Pelo que entendi, você deve usar o Write-Error para erros que não terminam e o Throw para terminar os erros. Parece-me que você não deve usar o Write-Error seguido de Return. Existe alguma diferença?
powershell
error-handling
powershell-2.0
Bill Barry
fonte
fonte
return
se não retornar para o chamador noprocess
bloco de uma função (avançado); em vez disso, prossegue para o próximo objeto de entrada no pipeline. De fato, este é o cenário típico para gerar erros sem finalização: se o processamento de outros objetos de entrada ainda for possível.Throw
gera um erro de terminação de script , que não é o mesmo que os erros de terminação de instrução acionados, por exemplo, porGet-Item -NoSuchParameter
ou1 / 0
.Respostas:
Write-Error
deve ser usado se você deseja informar o usuário sobre um erro não crítico. Por padrão, tudo o que faz é imprimir uma mensagem de erro em texto em vermelho no console. Ele não impede que um pipeline ou um loop continue.Throw
por outro lado, produz o que é chamado de erro final. Se você usar o throw, o pipeline e / ou o loop de corrente serão encerrados. De fato, toda a execução será encerrada, a menos que você use umatrap
ou umatry/catch
estrutura para lidar com o erro de finalização.Há uma coisa a nota, se você definir
$ErrorActionPreference
a"Stop"
e usarWrite-Error
ele irá produzir um erro de encerramento .No script ao qual você vinculou, encontramos o seguinte:
Parece que o autor dessa função queria interromper a execução dessa função e exibir uma mensagem de erro na tela, mas não queria que o script inteiro parasse de executar. O autor do script poderia ter usado,
throw
no entanto, isso significaria que você precisaria usar atry/catch
ao chamar a função.return
sairá do escopo atual, que pode ser uma função, script ou bloco de scripts. Isso é melhor ilustrado com o código:Saída para ambos:
Uma pegadinha aqui está usando
return
comForEach-Object
. Não interromperá o processamento como se poderia esperar.Mais Informações:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnfonte
return
.A principal diferença entre o cmdlet Write-Error e a palavra-chave throw no PowerShell é que o primeiro simplesmente imprime algum texto no fluxo de erro padrão (stderr) , enquanto o último termina o processamento do comando ou função em execução, que é então tratado pelo PowerShell enviando informações sobre o erro ao console.
Você pode observar o comportamento diferente dos dois nos exemplos que você forneceu:
Neste exemplo, a
return
palavra-chave foi adicionada para interromper explicitamente a execução do script depois que a mensagem de erro foi enviada ao console. No segundo exemplo, por outro lado, areturn
palavra-chave não é necessária, pois a terminação é implicitamente feita porthrow
:fonte
[System.Management.Automation.ErrorRecord]
instâncias, que são coletadas por padrão na$Error
coleção automática ($Error[0]
contém o erro mais recente). Mesmo se você apenas usarWrite-Error
com uma string , essa string será quebrada em uma[System.Management.Automation.ErrorRecord]
instância.Importante : Existem 2 tipos de erros de finalização , que infelizmente os tópicos atuais da ajuda conflitam :
erros de terminação de instrução , conforme relatado por cmdlets em determinadas situações não recuperáveis e por expressões nas quais ocorre uma exceção .NET / um erro de tempo de execução do PS; somente a instrução é finalizada e a execução do script continua por padrão .
roteiro -terminating erros (mais precisamente: runspace-terminação ), como quer desencadeadas por
Throw
ou escalando um dos outros tipos de erro através de erro de ação valor de preferência variável / parâmetroStop
.A menos que capturados, eles terminam o espaço de execução atual (encadeamento); isto é, eles finalizam não apenas o script atual, mas também todos os chamadores, se aplicável).
Para uma visão abrangente do tratamento de erros do PowerShell, consulte este problema de documentação do GitHub .
O restante desta postagem se concentra em erros que não terminam ou que encerram com instruções .
Para complementar as respostas úteis existentes, com foco no cerne da questão: Como você escolhe se deseja relatar um erro que encerra ou não encerra uma declaração ?
O Relatório de Erros do Cmdlet contém diretrizes úteis; deixe-me tentar um resumo pragmático :
A idéia geral por trás dos erros sem terminação é permitir o processamento "tolerante a falhas" de grandes conjuntos de entradas : a falha ao processar um subconjunto dos objetos de entrada não deve (por padrão) abortar o processo - potencialmente demorado - como um todo , permitindo inspecionar os erros e reprocessar apenas os objetos com falha posteriormente - conforme relatado por meio dos registros de erros coletados na variável automática
$Error
.Relate um erro NÃO TERMINANDO , se seu cmdlet / função avançada:
$PSCmdlet.WriteError()
para relatar um erro sem fim (Write-Error
infelizmente, não faz com$?
que seja definido$False
no escopo do chamador - consulte este problema do GitHub ).$?
informa se o comando mais recente relatou pelo menos um erro sem finalização.$?
ser$False
pode significar que qualquer subconjunto (não vazio) de objetos de entrada não foi processado adequadamente, possivelmente o conjunto inteiro.$ErrorActionPreference
e / ou o parâmetro de cmdlet comum-ErrorAction
podem modificar o comportamento de erros sem finalização (apenas) em termos de comportamento de saída de erro e se os erros sem finalização devem ser escalados para os que terminam com script .Relate um erro de TERMO DE DECLARAÇÃO em todos os outros casos .
$PSCmdlet.ThrowTerminatingError()
para gerar um erro de encerramento de instrução.Throw
palavra - chave gera um erro de terminação de script que interrompe o script inteiro (tecnicamente: o encadeamento atual ).try/catch
manipulador outrap
instrução pode ser usado (que não pode ser usado com erros de finalização ), mas observe que mesmo os erros de finalização de instrução , por padrão, não impedem a execução do restante do script. Assim como ocorre nos erros sem encerramento ,$?
reflete$False
se a instrução anterior acionou um erro de encerramento.Infelizmente, nem todos os cmdlets principais do PowerShell seguem essas regras :
Embora seja improvável que falhe,
New-TemporaryFile
(PSv5 +) reportaria um erro sem fim, se falhasse, apesar de não aceitar a entrada do pipeline e produzir apenas um objeto de saída - isso foi corrigido pelo menos no PowerShell [Core] 7.0, no entanto: consulte este GitHub questão .Resume-Job
A ajuda de alega que a aprovação de um tipo de trabalho não suportado (como um trabalho criado com oStart-Job
qual não há suporte, porqueResume-Job
se aplica apenas a trabalhos de fluxo de trabalho) causa um erro de encerramento, mas isso não ocorre no PSv5.1.fonte
Write-Error
permite que o consumidor da função suprima a mensagem de erro com-ErrorAction SilentlyContinue
(alternativamente-ea 0
). Emborathrow
exija umatry{...} catch {..}
Para usar uma tentativa ... pegue com
Write-Error
:fonte
Além da resposta de Andy Arismendi :
Se o Erro de gravação encerra ou não o processo, depende da
$ErrorActionPreference
configuração.Para scripts não triviais,
$ErrorActionPreference = "Stop"
é uma configuração recomendada para falhar rapidamente.(em http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
No entanto, faz
Write-Error
chamadas terminando.Para usar o Erro de gravação como um comando sem finalização, independentemente de outras configurações do ambiente, você pode usar o parâmetro comum
-ErrorAction
com valorContinue
:fonte
Se sua leitura do código estiver correta, você estará correto. Erros de terminação devem ser utilizados
throw
e, se você estiver lidando com tipos .NET, também será útil seguir as convenções de exceção do .NET.fonte