Как я могу начать фоновое задание в Powershell, которое переживает его родитель?

Рассмотрим следующий код:

start-job -scriptblock { sleep 10; cmd /c set > c:\env.txt; }
exit

Исходное задание убивается при выходе родителя, поэтому вызов cmd.exe никогда не возникает. Я хотел бы написать какой-то аналогичный код, так что родительский элемент немедленно выйдет, а ребенок продолжает работать в фоновом режиме.

Я хотел бы сохранить все в одном script, если это возможно.

Ответ 1

Вам нужно будет начать процесс:

start-process powershell -ArgumentList "sleep 10; cmd /c set > c:\env.txt" -WindowStyle hidden

Ответ 2

Вы также можете сделать это как

$a = start-job -scriptblock { sleep 10; cmd /c set > c:\env.txt; }
Register-ObjectEvent -InputObject $a -EventName StateChanged -SourceIdentifier "finished"
$b = Wait-Event -SourceIdentifier "finished"
exit

Ваш script будет ждать завершения конца скриптового блока.

Ответ 3

Если обнаружено, что использование Invoke-Command было в состоянии обойти ограничение, которое фоновое задание умеет с ним родительским. Приятно, что синтаксис почти такой же, как и для start-job, поэтому скриптовый блок можно сохранить как есть.

start-job -scriptblock { sleep 10; cmd /c set > c:\env.txt; }

просто превратится в

Invoke-Command -ComputerName . -AsJob -scriptblock { sleep 10; cmd /c set > c:\env.txt; }

и внезапно пережить смерть его родителя (возможно, потому что команда invoke-command подходит для запуска программ на другом компьютере, чтобы родительский элемент никогда не имел для него значения)

Ответ 4

Если вы используете Start-Process, вы создаете новый дочерний процесс, в котором ваш сеанс powershell будет выполняться как его родительский процесс. Если вы упустите родительский процесс powershell, который начнет это, новый процесс будет потерян и продолжит работу. Однако он не сохранится, если вы убьете родительское дерево процессов

Start-Process -FilePath notepad.exe

Powershell не может запустить новый независимый процесс за пределами своего дерева процессов для вас. Однако это можно сделать в Windows с помощью CreateProcess, и эта функция доступна через WMI. К счастью, вы можете вызвать это из powershell:

Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList notepad.exe

Таким образом, новый процесс также будет продолжать работать, если дерево процессов будет убито, потому что новый процесс не имеет сеанса powershell в качестве родителя, а хост-процесс WMI.