Monday, 2 April 2018

Powershell processstartinfo waitforexit


Powershell processstartinfo waitforexit
Obter através da App Store Leia esta publicação em nosso aplicativo!
Obtendo ExitCode usando Start-Process e WaitForExit em vez de - Wait.
Estou tentando executar um programa do PowerShell, aguardar a saída, depois ter acesso ao ExitCode, mas não ter muita sorte. Eu não quero usar - Aguarde com o Processo de Início, como eu preciso de algum processamento para continuar em segundo plano.
Aqui está um script de teste simplificado:
A execução deste script fará com que o bloco de notas seja iniciado. Depois disso, é fechado manualmente, o código de saída será impresso, e ele será iniciado de novo, sem usar - wait. Nenhum ExitCode é fornecido quando isso é encerrado:
Eu preciso ser capaz de executar um processamento adicional entre iniciar o programa e aguardá-lo para sair, então eu não posso fazer uso de "Esperar". Alguma idéia de como posso fazer isso e ainda ter acesso à propriedade. ExitCode desse processo?
Duas coisas que você poderia fazer, eu acho.
Crie o objeto System. Diagnostics. Process manualmente e ignore o Start-Process Execute o executável em uma tarefa em segundo plano (apenas para processos não interativos).
Veja como você poderia fazer:
Há duas coisas para lembrar aqui. Um é adicionar o argumento - PassThru e dois é adicionar o argumento - Wait. Você precisa adicionar o argumento de espera por causa desse defeito, connect. microsoft/PowerShell/feedback/details/520554/start-process-does-not-return-exitcode-property.
Depois de fazer isso, um objeto de processo é passado de volta e você pode observar a propriedade ExitCode desse objeto. Aqui está um exemplo:
Se você executá-lo sem - PassThru ou - Wait, ele não imprimirá nada.
Ao tentar a sugestão final acima, descobri uma solução ainda mais simples. Tudo o que eu tinha que fazer era armazenar em cache o identificador do processo. Assim que fiz isso, $ process. ExitCode funcionou corretamente. Se eu não escondeu o process handle, $ process. ExitCode era nulo.
Ou tente adicionar isso.
Ao usar este código, você ainda pode permitir que o PowerShell se ocupe de gerir os fluxos de saída / erro redirecionados, o que você não pode fazer usando System. Diagnostics. Process. Start () diretamente.
A opção '' Esperar 'parecia me bloquear mesmo que meu processo tivesse terminado.
Eu tentei a solução de Adrian e isso funciona. Mas eu usei Wait-Process em vez de confiar em um efeito colateral de recuperar o process handle.

Executando executáveis ​​no PowerShell.
O Windows PowerShell foi projetado como uma interface de linha de comando (CLI) interativa. Um dos principais propósitos de uma CLI é permitir que você execute programas. No entanto, eu perdi o número de vezes que eu vi perguntas como esta: "Eu preciso executar a ferramenta de linha de comando such-and-such no PowerShell. Tentei citar os parâmetros de várias maneiras sem sucesso. Como faço para que este programa seja executado corretamente no PowerShell? "
Executar um executável com cotação correta no Cmd. exe não é um problema porque o Cmd. exe não faz qualquer análise extra da linha de comando do executável. Se você estiver escrevendo um script de shell Cmd. exe (ou seja, um arquivo em lotes) que executa um executável, você pode ver exatamente o que a linha de comando do executável será simplesmente prefixando a linha de comando do executável com o Echo, que informa o Cmd. exe para emita a linha de comando na tela em vez de executá-la. Esta é uma técnica de depuração simples e eficaz.
No entanto, o PowerShell complica isso um pouco porque seu analisador de linha de comando é mais complexo que o analisador do Cmd. exe por necessidade. O comando Echo no PowerShell é realmente um alias para Write-Host, então você não pode usar o comando Echo no PowerShell para ver a linha de comando exata como você pode em Cmd. exe. A linha inferior é que o PowerShell não possui uma maneira integrada de ver a linha de comando exata do executável.
Para contornar essa limitação, escrevi um programa de linha de comando curto chamado ShowArgs. exe. O objetivo deste programa é produzir seus parâmetros de linha de comando sem qualquer análise ou interpretação. Ao substituir o ShowArgs. exe pelo programa que você está tentando executar (mantendo os parâmetros do seu programa), você pode ver os parâmetros reais da linha de comando que o PowerShell usará.
O programa ShowArgs. exe e seu código fonte estão disponíveis para download, clicando no botão Download do código, perto do topo da página. O arquivo ShowArgs. zip também contém o programa ShowArgs-GUI. exe, que funciona do mesmo modo que ShowArgs. exe, exceto que exibe seus parâmetros de linha de comando em uma caixa de diálogo pop-up em vez de exibi-los na janela do console.
Usando o ShowArgs. exe, vou mostrar-lhe como resolver os problemas mais comuns de "como posso citar coisas corretamente" ao executar executáveis ​​no PowerShell. Para os exemplos neste artigo, criei um diretório chamado C: \ Ferramentas de exemplo e o ShowArgs. exe copiado para ele.
Iniciando executáveis ​​no PowerShell.
Para executar um executável no PowerShell, você precisará especificar seu nome. Isso é o mesmo que executar um executável no Cmd. exe. Por exemplo, a Figura 1 mostra dois exemplos de execução do ShowArgs. exe diretamente no PowerShell. Na Figura 1, o prefixo. \ É necessário para executar ShowArgs. exe porque o PowerShell não executa executáveis ​​do diretório atual por padrão.
Figura 1: executando um executável diretamente no PowerShell.
Se o nome do arquivo, o caminho ou o nome do caminho do executável não contiverem espaços, o uso do operador de chamada (&) é opcional, como mostrado na Figura 2. Caso contrário, o operador de chamada é necessário.
Figura 2: Usar o operador de chamada é opcional se não houver espaços no nome do arquivo, caminho ou nome do caminho do executável.
No entanto, você não pode usar o operador de chamada para invocar uma linha de comando inteira. A Figura 3 ilustra esse erro comum. O primeiro comando na Figura 3 falha porque a string citada após o operador de chamada não é um nome de arquivo (assim como os estados de mensagem de erro). O segundo comando na Figura 3 corrige esse erro. Neste comando, apenas o nome do executável é colocado entre aspas, seguido dos parâmetros.
Você pode capturar a saída de um executável em uma variável, como mostrado na Figura 4. O primeiro comando na Figura 4 executa Find. exe /? e captura a saída na variável $ findHelp. O segundo comando na Figura 4 mostra que a variável contém uma matriz e o último comando exibe o conteúdo da matriz. (Se o programa emitir apenas uma linha, a variável conterá uma única seqüência em vez de uma matriz.)
Citando Parâmetros na Linha de Comando de um Executivo.
Quando um parâmetro contém espaços, você precisa colocar esse parâmetro entre aspas. As próprias cotações não fazem parte do parâmetro, o que significa que você pode citar parâmetros que não possuem espaços se desejado, mas as cotações são opcionais.
As seguintes diretrizes podem ajudá-lo a evitar problemas ao especificar parâmetros executáveis ​​no PowerShell. Todos os exemplos desta seção usam ShowArgs. exe com parâmetros hipotéticos. Eu encorajo você a executar esses exemplos para que você veja os parâmetros de linha de comando exatos que o PowerShell usará.
Diretriz 1. Você só precisa adicionar aspas quando você está especificando um parâmetro diretamente na linha de comando e esse parâmetro contém espaços. Aqui está um exemplo:
Este comando se comporta exatamente como esperado. O PowerShell vê que a seqüência citada contém um espaço e cita-a ao passar para o executável. Não há necessidade de incorporar citações extras na string. Em outras palavras, você não precisa fazer nenhum dos seguintes procedimentos:
O PowerShell removerá as cotações extras para que o parâmetro tenha apenas um conjunto de cotações. Assim, as citações extras não realizam nada, exceto tornando o comando mais difícil de ler. Se o parâmetro não contém espaços, as citações são opcionais.
Diretriz 2. Se você deseja passar uma variável como parâmetro de um executável, basta colocar a variável na linha de comando do executável. Aqui está um exemplo:
Se o conteúdo da variável contiver espaços, o PowerShell irá adicionar automaticamente aspas. Como com o exemplo anterior, você não precisa incorporar aspas extras.
Diretriz 3. Se um parâmetro usa um argumento que está "ligado" ao parâmetro (ou seja, você deve escrever o parâmetro e seu argumento em conjunto, sem um espaço interativo), você pode citar o parâmetro inteiro, incluindo seu argumento. (Para aqueles que não estão familiarizados com a diferença entre parâmetros e argumentos, um parâmetro é algo especificado após o comando que direciona seu comportamento, enquanto um argumento fornece informações adicionais para um parâmetro.) Alternativamente, você pode citar o argumento do parâmetro separadamente. Por exemplo, os seguintes comandos são equivalentes:
Isso também se aplica se o parâmetro e o argumento tiverem um caractere entre eles, como dois pontos (:) ou um sinal de igual (=). Em outras palavras, os dois comandos a seguir são equivalentes:
Esses dois comandos também são equivalentes:
Como antes, a incorporação de citações extras é desnecessária.
Diretriz 4. Se você usa uma variável como argumento de um parâmetro, não precisa fazer nenhuma citação extra, mesmo que o conteúdo da variável tenha espaços. Por exemplo, todos os comandos a seguir funcionarão corretamente:
Diretriz 5. Se o parâmetro começar com um hífen (-), o argumento do parâmetro está conectado ao parâmetro (sem espaço entre) e o argumento do parâmetro está em uma variável, você precisa escapar do hífen inicial com um tiquetaque (` ) ou citar o parâmetro inteiro e o argumento conectado. Por exemplo, o seguinte comando não funcionará corretamente:
Em vez disso, você precisa usar um desses comandos:
Esta regra aplica-se se o parâmetro e seu argumento estão conectados diretamente (por exemplo, - name $ name) ou com um caractere (como: ou =) entre eles. No entanto, não se aplica se o argumento do parâmetro não estiver em uma variável. Por exemplo, os dois comandos a seguir são equivalentes:
Se você não tiver certeza sobre a linha de comando real que o PowerShell vai usar, substitua o nome do executável por ShowArgs. exe e você verá os parâmetros de linha de comando exatos que o PowerShell usará para executar o executável.
Obtendo o código de saída do executável.
Cmd. exe usa a variável de ambiente dinâmico ERRORLEVEL para armazenar o código de saída do último executável que foi executado. O PowerShell usa a variável $ LASTEXITCODE em vez disso. Normalmente, você pode saber se um executável foi concluído sem erros, verificando se $ LASTEXITCODE é igual a zero.
Construindo uma linha de comando do executável com base em condições.
Se você precisa criar uma linha de linha de comando que depende de condições, talvez seja necessário maior flexibilidade. Por exemplo, considere o script Test. ps1 na Listagem 1.
Se você executar Test1.ps1 com o parâmetro - Test, o PowerShell executará o comando:
No entanto, nós realmente queremos o PowerShell para executar esse comando em vez disso:
Ou seja, queremos que o PowerShell interprete a variável $ params como a própria linha de comando, e não um único parâmetro de seqüência de caracteres para o executável.
Uma solução é usar o cmdlet Start-Process, conforme mostrado na Listagem 2. O cmdlet Start-Process possui o parâmetro - ArgumentList, que é uma matriz de parâmetros de linha de comando. O PowerShell não faz nenhuma citação automática desses parâmetros, então você terá que inserir aspas, quando necessário.
Usar o cmdlet Start-Process tem algumas desvantagens:
Se você deseja capturar a saída do executável, você precisa usar o parâmetro - RedirectStandardOutput. Test3.ps1 na Listagem 3 ilustra esta técnica. Este script cria um arquivo temporário, executa o executável (redirecionando a saída para o arquivo temporário) e recupera a saída usando o cmdlet Get-Content. O cmdlet Start-Process não atualiza a variável $ LASTEXITCODE.
Por um pouco mais de flexibilidade, você pode usar a função Start-Executable mostrada na Listagem 4. A função Start-Executable não usa um arquivo temporário e atualiza a variável $ LASTEXITCODE. O parâmetro - ArgumentList da função funciona da mesma forma que o parâmetro - ArgumentList do cmdlet Start-Process.

Exemplo de uso.
Resolvi assim:
Eu redirecionava a entrada, a saída e o erro e administrai a leitura dos fluxos de saída e erro. Esta solução funciona para o SDK 7- 8.1, tanto para o Windows 7 como para o Windows 8.
Eu tentei fazer uma aula que resolva seu problema usando a leitura de fluxo assíncrono, levando em conta Mark Byers, Rob, Stevejay responde. Ao fazê-lo, percebi que existe um erro relacionado à leitura assíncrona do fluxo de saída do processo.
Você não pode fazer isso:
Você receberá System. InvalidOperationException: StandardOut não foi redirecionado ou o processo ainda não começou.
Então, você deve iniciar a saída assíncrona lida após o processo ser iniciado:
Fazendo isso, faça uma condição de corrida porque o fluxo de saída pode receber dados antes de configurá-lo como assíncrono:
Então algumas pessoas podem dizer que você só precisa ler o fluxo antes de configurá-lo como assíncrono. Mas o mesmo problema ocorre. Haverá uma condição de corrida entre a leitura síncrona e configurará o fluxo em modo assíncrono.
Não há como conseguir uma leitura assíncrona segura de um fluxo de saída de um processo na forma real "Processo" e "ProcessStartInfo" foi projetado.
Você provavelmente está melhor usando a leitura assíncrona, como sugerido por outros usuários para o seu caso. Mas você deve estar ciente de que você pode perder algumas informações devido à condição de corrida.
Nenhuma das respostas acima está fazendo o trabalho.
A solução Rob trava e a solução 'Mark Byers' obtém a exceção descarta. (Eu tentei as "soluções" das outras respostas).
Então eu decidi sugerir outra solução:
Este código é depurado e funciona perfeitamente.
Eu acho que isso é uma abordagem simples e melhor (não precisamos do AutoResetEvent):
Eu estava tendo o mesmo problema, mas a razão era diferente. No entanto, isso aconteceria no Windows 8, mas não no Windows 7. A seguinte linha parece ter causado o problema.
A solução era NÃO desativar UseShellExecute. Agora recebi uma janela popup do Shell, que é indesejável, mas muito melhor do que o programa esperando que nada de particular aconteça. Então eu adicionei o seguinte trabalho para isso:
Agora, o único problema que me incomoda é o porquê isso está acontecendo no Windows 8, em primeiro lugar.
Introdução.
A resposta atualmente aceita não funciona (lança exceção) e há muitas soluções alternativas, mas nenhum código completo. Isso é, obviamente, desperdiçando muito tempo das pessoas porque esta é uma questão popular.
Combinando a resposta de Mark Byers e a resposta de Karol Tyl, escrevi um código completo baseado em como eu quero usar o método Process. Start.
Eu usei-o para criar um diálogo de progresso em torno dos comandos git. É assim que eu usei isso:
Em teoria, você também pode combinar stdout e stderr, mas não testei isso.
Eu sei que isso é velho, mas, depois de ler toda essa página, nenhuma das soluções estava funcionando para mim, embora eu não tentei Muhammad Rehan porque o código era um pouco difícil de seguir, embora eu acho que ele estava no caminho certo . Quando eu digo que não funcionou, isso não é inteiramente verdade, às vezes funcionaria bem, acho que é algo a ver com a duração da saída antes de uma marca EOF.
De qualquer forma, a solução que funcionou para mim era usar diferentes threads para ler o StandardOutput e StandardError e escrever as mensagens.
Espero que isso ajude alguém, que pensou que isso poderia ser tão difícil!
As outras soluções (incluindo o EM0) ainda estão bloqueadas para o meu aplicativo, devido a tempos de espera internos e ao uso de StandardOutput e StandardError pela aplicação gerada. Aqui está o que funcionou para mim:
Editar: inicialização adicionada de StartInfo para codificar a amostra.
Este post talvez esteja desactualizado, mas descobri a principal causa por que normalmente ele trava é devido ao excesso de pilha para o redirectStandardoutput ou se você tem redirectStandarderror.
Como os dados de saída ou os dados de erro são grandes, isso causará um tempo de espera, pois ele ainda está processando por tempo indefinido.

Processo . Método WaitForExit (Int32)
A documentação de referência da API tem uma nova casa. Visite o navegador da API no docs. microsoft para ver a nova experiência.
Instrui o componente Processo a aguardar o número especificado de milissegundos para que o processo associado saia.
Assembly: System (no System. dll)
Parâmetros.
A quantidade de tempo, em milissegundos, para aguardar o encerramento do processo associado. O máximo é o maior valor possível de um inteiro de 32 bits, que representa infinito para o sistema operacional.
Valor de retorno.
é verdade se o processo associado tenha saído; caso contrário, falso.
A configuração de espera não pôde ser acessada.
Nenhum Id do processo foi configurado e um identificador do qual a propriedade Id pode ser determinada não existe.
Não existe nenhum processo associado a este objeto Processo.
Você está tentando chamar WaitForExit (Int32) para um processo que está sendo executado em um computador remoto. Este método está disponível somente para processos que estão sendo executados no computador local.
WaitForExit (Int32) faz o thread atual aguardar até o processo associado terminar. Ele deve ser chamado após todos os outros métodos serem chamados no processo. Para evitar o bloqueio do segmento atual, use o evento Exitado.
Esse método instrui o componente Processo a aguardar um período finito de tempo para o processo sair. Se o processo associado não sair pelo final do intervalo porque a solicitação de término é negada, o falso é retornado ao procedimento de chamada. Você pode especificar um número negativo (Infinito) por milissegundos e Processar. WaitForExit (Int32) irá comportar-se da mesma forma que a sobrecarga WaitForExit (). Se você passar 0 (zero) para o método, ele retorna verdadeiro somente se o processo já foi encerrado; Caso contrário, ele retorna imediatamente falso.
No Quadro 3.5 e versões anteriores, se o milissegundo fosse -1, a sobrecarga WaitForExit (Int32) esperava milissegundos MaxValue (aproximadamente 24 dias), não indefinidamente.
Quando a saída padrão foi redirecionada para manipuladores de eventos assíncronos, é possível que o processamento de saída não seja concluído quando esse método retornar. Para garantir que o tratamento de eventos assíncrono tenha sido concluído, chame a sobrecarga WaitForExit () que não leva nenhum parâmetro depois de receber uma verdade dessa sobrecarga. Para ajudar a garantir que o evento Exited seja tratado corretamente nas aplicações Windows Forms, defina a propriedade SynchronizingObject.
Quando um processo associado é encerrado (é encerrado pelo sistema operacional através de uma terminação normal ou anormal), o sistema armazena informações administrativas sobre o processo e retorna ao componente que chamou WaitForExit (Int32). O componente Processo pode acessar a informação, que inclui o ExitTime, usando o Handle para o processo encerrado.
Como o processo associado saiu, a propriedade Handle do componente já não aponta para um recurso de processo existente. Em vez disso, o identificador pode ser usado apenas para acessar as informações do sistema operacional sobre o recurso do processo. O sistema está ciente de manipulações para processos que não foram lançados pelos componentes do Processo, portanto, mantém as informações ExitTime e Handle na memória até que o componente Processo liberte especificamente os recursos. Por esse motivo, sempre que você ligar para uma instância do Start for Process, chame Close quando o processo associado for encerrado e você não precisa mais de informações administrativas sobre isso. Fechar libera a memória alocada para o processo encerrado.
Consulte o exemplo de código para a propriedade ExitCode.
para uma confiança total para o chamador imediato. Este membro não pode ser usado por código parcialmente confiável.

Processo . Método WaitForExit.
A documentação de referência da API tem uma nova casa. Visite o navegador da API no docs. microsoft para ver a nova experiência.
Define o período de tempo para aguardar o processo associado para sair e bloqueia o segmento de execução atual até o tempo decorrido ou o processo foi encerrado. Para evitar o bloqueio do segmento atual, use o evento Exitado.
Para exemplos de código, consulte as páginas de referência da propriedade StandardError e ExitCode.
Assembly: System (no System. dll)
Instrui o componente Processo a esperar indefinidamente para que o processo associado saia.
Instrui o componente Processo a aguardar o número especificado de milissegundos para que o processo associado saia.

No comments:

Post a Comment