Powershell - если процесс не запущен, запустите его - PullRequest
21 голосов
/ 12 января 2012

Нуб, помогите пожалуйста. Я пытаюсь написать скрипт, который проверит, запущен ли процесс, и если нет, запустите его. Если процесс запущен, он ничего не должен делать. До сих пор я придумал следующее, но он запускает новый экземпляр процесса независимо от того, запущен ли он уже. Любая помощь приветствуется.

$Prog = "C:\utilities\prog.exe"
$Running = Get-Process prog -ErrorAction SilentlyContinue
$Start = ([wmiclass]"win32_process").Create($Prog)
if($Running -eq $null)
{$Start}
else
{}

Ответы [ 4 ]

28 голосов
/ 12 января 2012

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

$Prog = "C:\utilities\prog.exe"
$Running = Get-Process prog -ErrorAction SilentlyContinue
$Start = ([wmiclass]"win32_process").Create($Prog) # the process is created on this line
if($Running -eq $null) # evaluating if the program is running
{$Start}

Можно создать блок кода, который должен быть дополнительно проанализирован в вашем коде, обернув его в {} (блок скриптов):

$Prog = "C:\utilities\prog.exe"
$Running = Get-Process prog -ErrorAction SilentlyContinue
$Start = {([wmiclass]"win32_process").Create($Prog)} 
if($Running -eq $null) # evaluating if the program is running
{& $Start} # the process is created on this line

Однако, если вы ищете короткий однострочный для решения вашей проблемы:

if (! (ps | ? {$_.path -eq $prog})) {& $prog}
10 голосов
/ 12 января 2012

В командлете Get-Process аргумент имени процесса должен быть именем исполняемого файла без расширения файла .Попробуйте заменить $Prog = "C:\utilities\prog.exe" на $Prog = "prog".

. По моему мнению, ваш сценарий будет более читабельным, если вы отфильтруете процесс , используя вместо этого командлет Where-Object .Вот пример:

$programName = "prog"
$isRunning = (Get-Process | Where-Object { $_.Name -eq $programName }).Count -gt 0

if ($isRunning)
 # ...
else
 # ...

Таким образом, вы можете избавиться от аргумента -ErrorAction SilentlyContinue, который может сбить с толку того, кто не знает о том, что Get-Process выдает ошибку , если не удается найти процесс с указанным именем.

5 голосов
/ 12 января 2012

Помните, что PowerShell обрабатывает объекты, а не только текст. В то время как в обычных пакетных файлах вы можете установить переменную в строку, а затем просто использовать ее как команду:

set Foo=dir /b
%Foo%

... это не работает в PowerShell. Таким образом, ваше присвоение $Start уже создает новый процесс, так как команда после = запускается, а ее результат присваивается $Start.

Кроме того, вы все усложняете без необходимости. Вместо этого я бы предложил следующее:

$Running = Get-Process prog -ErrorAction SilentlyContinue
if (!$Running) { Start-Process C:\utilities\prog.exe }

Поскольку Get-Process возвращает объект (который оценивается в $true) или $null (который оценивается в $false), вы можете упростить проверку, как показано выше. Это называется приведением типа, поскольку оператор if ожидает логическое значение, а правила для того, что будет обрабатываться как $true и $false, очень согласованы в таких случаях, как указано выше. И это звучит лучше.

Я также использовал командлет Start-Process вместо WMI для создания нового процесса. Вы даже можете использовать следующее:

if (!$Running) { C:\utilities\prog.exe }

, если приложение не является консольным приложением (и, таким образом, блокирует сценарий PowerShell до его завершения). PowerShell по-прежнему является оболочкой, поэтому запуск программ - это то, что изначально отлично работает: -)

Вы могли бы даже вставить переменную $running, но я думаю, что комментарий был бы для того, чтобы уточнить, что вы делаете.

4 голосов
/ 12 января 2012
$path = "C:\utilities\prog.exe"        
$list = get-process | where-object {$_.Path -eq $path }     
if ($list -eq $null) { start-process -filepath $path }

или

$path = "C:\utilities\prog.exe"
get-process | where-object {$_.Path -eq $path } | measure-object | where-object { $_.Count -eq 0} | foreach-object {start-process -filepath $path }

Это сэкономит вам оператор if и одну декларацию переменной. Это может быть также однострочная команда:

  1. Получить процессы
  2. Выберите те пути, которые вас интересуют
  3. Используйте объект меры, чтобы получить статистику о вашем списке
  4. Продолжить трубопровод, только если значение счетчика stats равно 0
  5. Начать процесс

Не позволяйте foreach в конце оттолкнуть вас. Объект меры вернет только один элемент, где будет возвращать один или ноль. Foreach используется только для выполнения, если результат равен нулю. Это не запустит больше чем один процесс. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...