Powershell finalmente bloquear não executado no agendador de tarefas do Windows

1

Estou executando uma tarefa do agendador de tarefas do Windows:

Powershell 
-command C:\file.ps1  2>&1 > c:\test.log

file.ps1 contém

Try{
    echo "a"
    sleep 5
    echo "b"
}
Finally{
    echo "c"
}

Quando inicio a tarefa manualmente e espero que ela termine, o test.log contém "abc". Mas quando eu o interrompo, saindo manualmente (botão "End"), ele contém apenas "a".

Eu achei que Finally teve a intenção de executar mesmo ao sair de um script do PowerShell? Meu resultado esperado foi "ac"

    
por Peter 12.03.2018 / 13:44

1 resposta

2

Como mencionado nos comentários de Lieven Keersmaekers, o bloco finally não tem chance de ser executado quando você usa End para interromper a tarefa. Isso é porque o End apenas mata o processo. O PowerShell ficaria feliz em executar o bloco finally antes de fazer suas outras saídas, mas o PowerShell não pode fazer nada após o sinal de término do processo - está morto. Não há como qualquer processo lidar com isso. Nas palavras de Raymond Chen :

TerminateProcess is the low-level process killing function. It bypasses DLL_PROCESS_DETACH and anything else in the process. Once you kill with TerminateProcess, no more user-mode code will run in that process. It's gone. Do not pass go. Do not collect $200.

Existe uma solução alternativa, no entanto. Como o comando End do Agendador de Tarefas não mata subprocessos do processo de tarefa, seu script principal do PowerShell pode iniciar um processo de monitoramento para executar qualquer limpeza final. Esse script pode se parecer com algo assim (vamos chamá-lo de watchdog.ps1 ):

$watched = Get-Process -Id $args[0]
$watched.WaitForExit()
'Cleanup' >> c:\test.log

Leva um ID de processo, aguarda até que o processo saia, e só então faz alguma limpeza, o equivalente ao seu bloco final.

Então seu script principal pode ter esta aparência:

$myPid = [System.Diagnostics.Process]::GetCurrentProcess().Id
$watchdog = Start-Process 'powershell' "-c .\watchdog.ps1 $myPid" -PassThru -WindowStyle Hidden
'Starting'
sleep 10
'Finished'

No começo, ele inicia o script de watchdog, fornecendo seu próprio ID de processo. Em seguida, ele realiza seus negócios normais, saindo normalmente quando isso é feito.

Se você quiser que a limpeza do watchdog ocorra somente se o script principal for interrompido, adicione essa linha ao final do script principal:

$watchdog.Kill()

Isso evitará que o cão de guarda continue além da segunda linha.

Seu redirecionamento só será aplicado ao processo principal, portanto, o watchdog deve manipular sua própria direção de saída. Dependendo da configuração da sua tarefa agendada, pode ser necessário colocar o caminho completo para o script de watchdog no comando launchdog-launching do script principal.

    
por 12.03.2018 / 22:39