Как правильно проверить, запущен ли процесс и остановить его
Каков правильный способ определить, работает ли процесс, например FireFox, и останавливать его?
Я немного огляделся, и лучшим способом я нашел следующее:
if((get-process "firefox" -ea SilentlyContinue) -eq $Null){
echo "Not Running"
}
else{
echo "Running"
Stop-Process -processname "firefox"
}
Это идеальный способ сделать это? Если нет, то какой правильный способ сделать это?
Ответы
Ответ 1
Как вы это делаете, вы дважды запрашиваете процесс. Также Линн поднимает хороший момент о том, чтобы быть хорошим первым. Вероятно, я бы попытался сделать что-то вроде следующего:
# get Firefox process
$firefox = Get-Process firefox -ErrorAction SilentlyContinue
if ($firefox) {
# try gracefully first
$firefox.CloseMainWindow()
# kill after five seconds
Sleep 5
if (!$firefox.HasExited) {
$firefox | Stop-Process -Force
}
}
Remove-Variable firefox
Ответ 2
Если вам не нужно отображать точный результат "running" / "not runnuning", вы можете просто:
ps notepad -ErrorAction SilentlyContinue | kill -PassThru
Если процесс не запущен, результатов не будет. Если он был запущен, вы получите вывод get-process
, и процесс будет остановлен.
Ответ 3
Спасибо @Джо. Это то, что я ищу.
Я просто приношу некоторые улучшения:
- учитывать несколько процессов
- чтобы избежать достижения таймаута, когда все процессы завершены
- для упаковки целого в функции
function Stop-Processes {
param(
[parameter(Mandatory=$true)] $processName,
$timeout = 5
)
$processList = Get-Process $processName -ErrorAction SilentlyContinue
if ($processList) {
# Try gracefully first
$processList.CloseMainWindow() | Out-Null
# Wait until all processes have terminated or until timeout
for ($i = 0 ; $i -le $timeout; $i ++){
$AllHaveExited = $True
$processList | % {
$process = $_
If (!$process.HasExited){
$AllHaveExited = $False
}
}
If ($AllHaveExited){
Return
}
sleep 1
}
# Else: kill
$processList | Stop-Process -Force
}
}
Ответ 4
@jmp242 - универсальный тип System.Object
не содержит метод CloseMainWindow
, но статическое приведение типа System.Diagnostics.Process
при сборе переменной ProcessList
работает для меня. Обновленный код (из этого ответа) с этим приведением (и изменением цикла для использования ForEach-Object
) приведен ниже.
function Stop-Processes {
param(
[parameter(Mandatory=$true)] $processName,
$timeout = 5
)
[System.Diagnostics.Process[]]$processList = Get-Process $processName -ErrorAction SilentlyContinue
ForEach ($Process in $processList) {
# Try gracefully first
$Process.CloseMainWindow() | Out-Null
}
# Check the 'HasExited' property for each process
for ($i = 0 ; $i -le $timeout; $i++) {
$AllHaveExited = $True
$processList | ForEach-Object {
If (-NOT $_.HasExited) {
$AllHaveExited = $False
}
}
If ($AllHaveExited -eq $true){
Return
}
Start-Sleep 1
}
# If graceful close has failed, loop through 'Stop-Process'
$processList | ForEach-Object {
If (Get-Process -ID $_.ID -ErrorAction SilentlyContinue) {
Stop-Process -Id $_.ID -Force -Verbose
}
}
}