Iniciar um Processo no PowerShell: Lançamento Intuitivo de Processos

Para entender por que o Start-Process e todos esses outros comandos são limitados, primeiro você tem que entender como um arquivo EXE típico funciona. Quando um arquivo EXE é executado, ele realiza qualquer ação para a qual foi projetado; ele faz ping em algo (ping), inicia um instalador de software (setup), procura algum registro DNS (nslookup), o que quer que seja. Para esta parte e Start-Process and outros comandos para iniciar um processo funcionam muito bem. É simples. A limitação ocorre quando esse EXE retorna alguma saída.

Podemos iniciar um processo no PowerShell de várias maneiras diferentes. Temos os cmdlets Start-Process do PowerShell e Invoke-Expression, podemos chamar o executável diretamente ou usar o símbolo de e comercial (&) para invocar expressões. A maneira mais comum é usar Start-Process porque é provavelmente a mais intuitiva. O PowerShell é conhecido por sua abordagem intuitiva para nomeação de comandos e Start-Process é uma excelente escolha. No entanto, esse comando é limitado.

Streams

Um arquivo EXE, como muitos outros arquivos executáveis, não se limita ao Windows e tem um conceito de fluxos padrão. Fluxos padrão são como os arquivos executáveis retornam saída. Esses fluxos vêm em três sabores: stdin, stdout e stderr. Stdin é o fluxo que pode ser passado para o executável, sobre o qual não nos concentraremos aqui. Stdout é o fluxo que o executável usa para enviar saída normal, sem erros.

Em termos do PowerShell, pense em stdout como o que o Write-Output retorna. Quando ocorre um erro (dependendo se o desenvolvedor do executável o escreveu corretamente), o executável deve retornar saída via stderr. Esta é uma stream que é reservada para retornar qualquer informação de erro.

Essas streams permitem que os usuários desses arquivos executáveis diferenciem entre o que é uma saída típica e o que é um erro. As streams existem há décadas e, portanto, o Windows e o PowerShell sabem tudo sobre elas e adotaram as suas próprias.

Códigos de Saída

Um código de saída, código de retorno ou código de resultado é outro conceito antigo que os arquivos executáveis também seguem. Um código de saída é um inteiro que permite ao executável sinalizar um status para o usuário quando ele sai.

Há alguns códigos de saída padrão que os programas são supostos a seguir, como se o código de saída for 0, tudo está bem, o código de saída 3010 significa que precisa de uma reinicialização e assim por diante. O PowerShell pode capturar esse código de saída de algumas maneiras diferentes, como usando a variável automática $LastExitCode. Códigos de saída são outro método pelo qual o arquivo executável comunica ao usuário.

Capturando Streams e Códigos de Saída

Agora que você entende o que estamos trabalhando, vamos usar um exemplo. Para manter simples, vou usar o bom e velho ping.exe. Primeiro, vou pingar o google.com, o que retornará um resultado bem-sucedido. Não estamos usando o start process do PowerShell aqui.

PS C:\> ping google.com
Pinging google.com [2607:f8b0:4004:80b::200e] with 32 bytes of data:

Reply from 2607:f8b0:4004:80b::200e: time=61ms
Reply from 2607:f8b0:4004:80b::200e: time=65ms
Reply from 2607:f8b0:4004:80b::200e: time=80ms
Reply from 2607:f8b0:4004:80b::200e: time=78ms

Ping statistics for 2607:f8b0:4004:80b::200e:

Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 61ms, Maximum = 80ms, Average = 71ms

PS> $LastExitCode
0
PS> $?
True

I’ll now purposefully ping a host that doesn’t resolve a DNS name and will fail. Notice the value of $LastExitCode.

PS> ping googlllll.com

Ping request could not find host googlllll.com. Please check the name and try again.
PS> $LASTEXITCODE
1

Você viu que o código de saída difere porque o resultado do ping foi diferente, mas você não viu os fluxos porque nativamente o PowerShell não entende a diferença quando se trata de arquivos executáveis. O texto que você vê no console é branco; não é o texto de erro vermelho que você conhece e ama.

Podemos capturar os fluxos e redirecionar para arquivos de algumas maneiras diferentes, como usando > e 2> como abaixo. Este é o modo antigo.

PS> ping googllll.com > output.msg 2> output.err
PS> Get-Content .\output.err
PS> Get-Content .\output.msg

Ping request could not find host googllll.com. Please check the name and try again.

Observe, no entanto, que, neste caso, mesmo que ping.exe esteja retornando um código de saída 1 (como mostrado acima), essa saída ainda será enviada para stdout. Isso é comum. Qual fluxo e código de saída são retornados é completamente escolha do desenvolvedor e vem em muitos estilos diferentes, infelizmente.

Se você quiser seguir o caminho “novo”, poderia usar Start-Process e usar os parâmetros -RedirectStandardError e -RedirectStandardOutput, mas eles ainda seriam enviados apenas para arquivos.

Limitações do Start-Process

Você pode ver que iniciar um processo e retornar alguma saída comum não é tão comum. Além disso, o PowerShell não lida muito bem com os fluxos e códigos de saída. Se eu fosse usar Start-process para executar ping.exe e quisesse acompanhar o que aconteceu no resultado, teria que fazer algo assim sempre que quisesse executar um arquivo executável.

PS> Start-Process -FilePath -NoNewWindow ping -ArgumentList 'google.com' -RedirectStandardOutput output.txt -RedirectStandardError err.txt
PS> $LastExitCode
PS> Get-Content -Path output.txt
PS> Get-Content -Path err.txt

I still wouldn’t get my error text either!

Vamos corrigir tudo isso. Baixe uma pequena função que criei chamada Invoke-Process da PowerShell Gallery.

PS> Install-Script 'Invoke-Process'
PS> . Invoke-Process.ps1

Agora execute ping usando um host válido e veja o que acontece.

Invoke-Process -FilePath ping -ArgumentList ‘google.com’

Repare como obtemos a mesma saída. Isso é bom!

Agora execute ping usando um host inválido.

Invoke-Process -FilePath ping -ArgumentList ‘googlddde.com’

Agora repare que obtemos o texto de erro vermelho típico como esperávamos se algo desse errado. Invoke-Process usa Start-Process por baixo dos panos para capturar stdout, stderr e o código de saída e depois envia a saída para qualquer fluxo para onde deveria ir. É assim que deveria ser!

É uma pena que o PowerShell não tenha facilitado o trabalho com fluxos e códigos de saída de arquivos executáveis, mas eu suponho que hoje em dia, podemos adicionar isso lá agora que é de código aberto!

Source:
https://adamtheautomator.com/start-process/