Iniciar Processo no PowerShell: Inicialização Intuitiva de Processos

Para entender por que Start-Process e todos esses outros comandos são limitados, primeiro você precisa entender como um arquivo EXE típico funciona. Quando um arquivo EXE é executado, ele realiza qualquer ação para a qual foi projetado; ele envia um ping para algo (ping), inicia um instalador de software (setup), procura algum registro DNS (nslookup), seja o que for. 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 muitas maneiras diferentes. Temos os cmdlets Start-Process e Invoke-Expression do PowerShell, podemos chamar o executável diretamente ou usar o símbolo de ampersand (&) para invocar expressões. A maneira mais comum é usar Start-Process porque é provavelmente a mais intuitiva. O PowerShell é conhecido por sua abordagem intuitiva para nomear comandos e Start-Process é uma excelente escolha. No entanto, esse comando é limitado.

Streams

Um arquivo EXE, como muitos outros arquivos executáveis não limitados ao Windows, tem o conceito de fluxos padrão. Fluxos padrão são como arquivos executáveis retornam saída. Esses fluxos vêm em três variantes; stdin, stdout e stderr. Stdin é o fluxo que pode ser passado para o executável, sobre o qual não vamos nos concentrar aqui. Stdout é o fluxo que o executável usa para enviar saída normal, não de erro.

Em termos do PowerShell, pense em stdout como o que 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 corrente que é reservada para retornar qualquer informação de erro.

Essas correntes permitem que os usuários desses arquivos executáveis diferenciem entre o que é saída típica e o que é um erro. As correntes 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 seguem também. Um código de saída é um número 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 este código de saída de algumas maneiras diferentes, como usando a variável automática $LastExitCode. Os códigos de saída são mais um método que o arquivo executável comunica ao usuário.

Capturando Correntes 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 google.com, que retornará um resultado bem-sucedido. Não estamos usando o processo de inicialização 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 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 método 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 vai para stdout. Isso é comum. Qual fluxo e código de saída são retornados depende completamente do desenvolvedor e vem em muitos estilos diferentes, infelizmente.

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

Limitações do Start-Process

Você pode ver que iniciar um processo e retornar alguma saída comum não é muito comum. Além disso, o PowerShell não lida muito bem com os fluxos e códigos de saída. Se eu quisesse usar Start-process para executar ping.exe e quisesse rastrear o que aconteceu no resultado, teria que fazer algo assim toda vez 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 o ping usando um host válido e veja o que acontece.

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

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

Agora execute o comando ping usando um host inválido.

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

Agora observe que recebemos o típico texto de erro vermelho como esperado se algo deu errado. Invoke-Process utiliza Start-Process por baixo dos panos para capturar stdout, stderr e o código de saída, e então envia a saída para o fluxo correto. É assim que deve ser!

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

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