Nota: O comando na pergunta usa Start-Process, o que impede a captura direta da saída do programa de destino. Geralmente, não use Start-Processpara executar aplicativos de console de forma síncrona - apenas invoque-os diretamente , como em qualquer shell. Isso mantém o aplicativo conectado aos fluxos padrão do console de chamada, permitindo que sua saída seja capturada por atribuição simples $output = netdom ..., conforme detalhado abaixo.
Fundamentalmente , a captura de saída de utilitários externos funciona da mesma maneira que com os comandos nativos do PowerShell (você pode querer se atualizar sobre como executar ferramentas externas ):
$cmdOutput = <command> # captures the command's success stream / stdout
Observe que $cmdOutputrecebe uma matriz de objetos se <command>produz mais de 1 objeto de saída , o que, no caso de um programa externo, significa uma matriz de cadeias contendo as linhas de saída do programa .
Se você deseja $cmdOutputsempre receber uma única sequência - potencialmente com várias linhas - , use
$cmdOutput = <command> | Out-String
Para capturar a saída em uma variável e imprimir na tela :
<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed
Ou, se <command>for um cmdlet ou uma função avançada , você pode usar o parâmetro comum
-OutVariable/-ov :
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
Observe que -OutVariable, ao contrário dos outros cenários, sempre$cmdOutput é uma coleção , mesmo que apenas um objeto seja produzido. Especificamente, uma instância do tipo de matriz é retornada.
Veja esta edição do GitHub para uma discussão sobre essa discrepância.[System.Collections.ArrayList]
Para capturar a saída de vários comandos , use uma subexpressão ( $(...)) ou chame um bloco de script ( { ... }) com &ou .:
$cmdOutput = $(<command>; ...) # subexpression
$cmdOutput = & {<command>; ...} # script block with & - creates child scope for vars.
$cmdOutput = . {<command>; ...} # script block with . - no child scope
Observe que a necessidade geral de prefixar com &(o operador de chamada) um comando individual cujo nome / caminho é citado - por exemplo, $cmdOutput = & 'netdom.exe' ...- não está relacionado a programas externos per se (ele se aplica igualmente aos scripts do PowerShell), mas é um requisito de sintaxe : PowerShell analisa uma instrução que começa com uma string entre aspas no modo de expressão por padrão, enquanto o modo de argumento é necessário para chamar comandos (cmdlets, programas externos, funções, aliases), o que &garante.
A principal diferença entre $(...)e & { ... }/ . { ... }é que o primeiro coleta toda a entrada na memória antes de devolvê-lo como um todo, enquanto o último transmite a saída, adequado para o processamento de pipeline um por um.
Os redirecionamentos também funcionam da mesma maneira, fundamentalmente (mas veja as advertências abaixo):
$cmdOutput = <command> 2>&1 # redirect error stream (2) to success stream (1)
No entanto, para comandos externos, é mais provável que o seguinte funcione conforme o esperado:
$cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below.
Considerações específicas para programas externos :
Programas externos , porque operam fora do sistema de tipos do PowerShell, sempre retornam seqüências de caracteres por meio do fluxo de sucesso (stdout).
Se a saída contiver mais de 1 linha , o PowerShell, por padrão, a dividirá em uma matriz de seqüências de caracteres . Mais precisamente, as linhas de saída são armazenadas em uma matriz do tipo [System.Object[]]cujos elementos são cadeias de caracteres ( [System.String]).
Se você deseja que a saída seja uma única sequência potencialmente com várias linhas , canalize paraOut-String :
$cmdOutput = <command> | Out-String
O redirecionamento do stderr para o stdout2>&1 , para capturá-lo também como parte do fluxo de sucesso, vem com advertências :
Para fazer 2>&1stdout merge e stderr na fonte , vamos cmd.exelidar com o redirecionamento , usando as seguintes expressões:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /cchama cmd.execom o comando <command>e sai após a <command>conclusão.
- Observe as aspas simples
2>&1, o que garante que o redirecionamento seja passado para, em cmd.exevez de ser interpretado pelo PowerShell.
Observe que envolver cmd.exesignifica que suas regras para escapar caracteres e expandir variáveis de ambiente entram em jogo, por padrão, além dos próprios requisitos do PowerShell; no PS v3 +, você pode usar um parâmetro especial --%(o chamado símbolo de análise de parada ) para desativar a interpretação dos parâmetros restantes pelo PowerShell, exceto para cmd.exereferências de variáveis de ambiente no estilo, como %PATH%.
Observe que, como você está mesclando stdout e stderr na fonte com essa abordagem, não será possível distinguir entre linhas originadas por stdout e originadas por stderr no PowerShell; se você precisar dessa distinção, use o próprio 2>&1redirecionamento do PowerShell - veja abaixo.
Use o 2>&1 redirecionamento do PowerShell para saber quais linhas vieram de qual fluxo :
A saída Stderr é capturada como registros de erro ( [System.Management.Automation.ErrorRecord]), não cadeias, portanto a matriz de saída pode conter uma mistura de cadeias (cada cadeia representando uma linha stdout) e registros de erro (cada registro representando uma linha stderr) . Observe que, conforme solicitado por 2>&1, as seqüências de caracteres e os registros de erro são recebidos pelo fluxo de saída de sucesso do PowerShell ).
No console, os registros de erro são impressos em vermelho , e o primeiro, por padrão, produz exibição em várias linhas , no mesmo formato que o erro sem fim de um cmdlet seria exibido; os registros de erro subsequentes também são impressos em vermelho, mas apenas imprimem sua mensagem de erro em uma única linha .
Ao enviar para o console , as sequências geralmente vêm primeiro na matriz de saída, seguidas pelos registros de erro (pelo menos entre um lote de linhas stdout / stderr emitidas "ao mesmo tempo"), mas, felizmente, quando você captura a saída , é intercalado adequadamente , usando a mesma ordem de saída que você obteria sem 2>&1; em outras palavras: ao enviar para o console , a saída capturada NÃO reflete a ordem na qual as linhas stdout e stderr foram geradas pelo comando externo.
Se você capturar toda a saída em uma única string comOut-String , o PowerShell adicionará linhas extras , porque a representação da string de um registro de erro contém informações adicionais, como local ( At line:...) e categoria ( + CategoryInfo ...); curiosamente, isso se aplica apenas ao primeiro registro de erro.
- Para contornar esse problema, aplicar o
.ToString()método para cada objeto em vez de tubulação de saída Out-String:
$cmdOutput = <command> 2>&1 | % { $_.ToString() };
no PS v3 +, você pode simplificar:
$cmdOutput = <command> 2>&1 | % ToString
(Como bônus, se a saída não for capturada, isso produzirá uma saída adequadamente intercalada, mesmo ao imprimir no console).
Alternativamente, filtrar os registros de erro fora e enviá-los para fluxo de erro do PowerShell comWrite-Error (como um bônus, se a saída não é capturado, este produz uma saída propriamente intercalado mesmo quando a impressão para o console):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}
Start-Processpara executar aplicativos de console (por definição externos) de forma síncrona - apenas invoque-os diretamente , como em qualquer shell; a saber:netdom /verify $pc /domain:hosp.uhhg.org. Isso mantém o aplicativo conectado aos fluxos padrão do console de chamada, permitindo que sua saída seja capturada por atribuição simples$output = netdom .... A maioria das respostas dadas abaixo renuncia implicitamente aStart-Processfavor da execução direta.