Я выполняю следующую команду powershell на этапе сборки с использованием TFS 2018.

Start-Job -ScriptBlock {
    Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
}

Поскольку я не хочу, чтобы скрипт влиял на этап сборки, он должен просто запустить и забыть скрипт. Поэтому я использую Start-Job. Но кажется, что, как только шаг сделан, процесс убит. Есть ли способ сохранить время жизни процесса, даже если этап сборки выполнен или процесс сборки завершен?

Дополнительная информация ... Сценарий powershell должен запускаться на удаленном сервере. Сам скрипт запускает .exe с параметрами.

2
doorman 27 Фев 2018 в 23:24

4 ответа

Лучший ответ

Чтобы просто запустить и забыть , запустите скрипт с Invoke-Command -AsJob:

Invoke-Command -AsJob -FilePath \\MyServer\run.ps1 -ComputerName MyServer -Args arg1, arg2
Start-Sleep 1 # !! Seemingly, this is necessary, as @doorman has discovered.
  • Это должно запустить скрипт удаленно, асинхронно , с созданием задания в сеансе local для контроля его выполнения.

    • Предупреждение : использование Start-Sleep - возможно, с более длительным временем ожидания - на первый взгляд, необходимо создать удаленный процесс до выхода вызывающего сценария, но такое решение может быть не полностью надежным , поскольку не гарантировано время.
  • Поскольку вы не планируете контролировать удаленное выполнение, сеанс local , завершающий работу, а также задание по мониторингу, не должны иметь значения.

2
mklement0 1 Мар 2018 в 17:13

Когда вы хотите, чтобы скрипт остановился ? Вы можете использовать сделай цикл и найди <condition>, который соответствует твоим потребностям.

Start-Job -ScriptBlock {
    do{
        Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
        Start-Sleep 2
    }while(<condition>)
}

В качестве альтернативы вы можете использовать условие $true, чтобы оно выполнялось вечно. Вам придется остановить работу позже в сценарии, когда она вам больше не нужна.

$job = Start-Job -ScriptBlock {
    do{
        Invoke-Command -FilePath \\MyServer\run.ps1 -ComputerName MyServer -ArgumentList arg1, arg2
        Start-Sleep 2
    }while($true)
}

Stop-Job $job
Remove-Job $job

Я добавил Start-Sleep 2, чтобы он не блокировал ваш процессор, так как понятия не имею, что делает скрипт - удалите, если не требуется.

1
g.sulman 27 Фев 2018 в 20:46

@doorman - PowerShell изначально является однопоточным приложением. Практически во всех случаях это огромное преимущество. Даже форсируя несколько потоков, вы можете видеть, что дочерние потоки всегда зависят от основного потока. Если бы это было не так, было бы очень легко создать утечки памяти. Это почти всегда хорошо, так как при закрытии основного потока .Net очищает все остальные потоки, о которых вы, возможно, забыли. Вы случайно натолкнулись на случай, когда такое поведение не выгодно для вашей ситуации.

Существует несколько способов решения этой проблемы, но, возможно, самый простой - это использовать командную строку good ol 'для запуска независимого нового экземпляра, совсем не основанного на исходном сценарии. Для этого вы можете использовать invoke-expression вместе с 'cmd / c'. См. ниже:

invoke-expression 'cmd /c start powershell -NoProfile -windowstyle hidden -Command {
    $i = 0
    while ($true) {
        if($i -gt 30) {
            break
        }
        else {
            $i | Out-File C:\Temp\IndependentSessionTest.txt -Append
            Start-Sleep -Seconds 1
            $i++
        }
    }
}
'

Это запустит новый сеанс, запустит нужный сценарий, не отобразит окно и не будет использовать ваш профиль powershell при запуске сценария. Вы сможете увидеть, что даже если вы прекратите исходный сеанс PowerShell, этот процесс продолжится. В этом можно убедиться, посмотрев файл IndependentSessionTest.txt после того, как вы закроете главное окно powershell и увидите, что файл продолжает получать обновленные номера.

Надеюсь, это указывает на правильное направление.

Вот некоторые ссылки на источники:

Сценарий запуска PowerShell в новом экземпляре

Как запустить скрипт PowerShell без отображения окна?

1
Jerris Heaton 1 Мар 2018 в 16:21

Почему не как то так

Invoke-Command -Filepath \\MyServer\Run.ps1 -Computername MyServer -Argumentlist Arg1,Arg2 -AsJob
$JobCount = (get-job).Count
Do
{
    Start-Sleep -Seconds 1
    $totalJobCompleted = (get-job | Where-Object {$_.state -eq "Completed"} | Where-Object {$_.Command -like "NAMEOFCOMMAND*"}).count
}
Until($totalJobCompleted -ge $JobCount)
1
Jebuz 27 Фев 2018 в 20:53