web-dev-qa-db-fra.com

Comment vérifier correctement si un processus est en cours d'exécution et l'arrêter

Quelle est la bonne façon de déterminer si un processus est en cours d'exécution, par exemple FireFox, et de l'arrêter?

J'ai fait quelques recherches et le meilleur moyen que j'ai trouvé était le suivant:

if((get-process "firefox" -ea SilentlyContinue) -eq $Null){ 
        echo "Not Running" 
}

else{ 
    echo "Running"
    Stop-Process -processname "firefox"
 }

Est-ce la manière idéale de le faire? Si non, quelle est la bonne façon de le faire?

33
user4350786

La façon dont vous le faites vous interroge deux fois sur le processus. Lynn soulève également un point positif à propos de Nice. J'essaierais probablement quelque chose comme ce qui suit:

# 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
63
Joey

Si vous n'avez pas besoin d'afficher le résultat exact "running"/"not runnuning", vous pouvez simplement:

ps notepad -ErrorAction SilentlyContinue | kill -PassThru

Si le processus ne fonctionnait pas, vous n'obtiendrez aucun résultat. S'il était en cours d'exécution, vous recevrez le résultat get-process et le processus sera arrêté.

6
Adam Luniewski

@ jmp242 - le type générique System.Object ne contient pas la méthode CloseMainWindow, mais la conversion statique du type System.Diagnostics.Process lors de la collecte de la variable ProcessList fonctionne pour moi. Le code mis à jour (de cette réponse ) avec cette diffusion (et la boucle changée pour utiliser ForEach-Object) se trouve ci-dessous.

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
        }
    }
}
0
Kit

Merci @ Joey. C'est ce que je cherche.

Je viens d'apporter quelques améliorations:

  • prendre en compte plusieurs processus 
  • pour éviter d'atteindre le délai d'expiration lorsque tous les processus sont terminés 
  • emballer le tout dans une fonction

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        
    }
}
0
smo