Shaun Luttin
Shaun Luttin

Reputation: 141434

Start several process with Start-Process and then kill them all with Stop-Process

We're using the following script to start five processes. Each of them run in a command prompt. We want to be able to stop all the processes afterward. How can we do that?

RunDemo.ps1

$global:p = @();

function global:kill-demo {
    $global:p | % {
        Write-Host "Killing $($_.ProcessName)"
        kill $_
        Write-Host "$($_.ProcessName) dead"
    }
}

# Authorization Server
Push-Location "./AuthorizationServer"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

# Aurelia Application
Push-Location "./AureliaApp"
$global:p += Start-Process npm -ArgumentList "run start" -PassThru
Pop-Location

# Oidc Client JS
Push-Location "./OidcClientJs"
$global:p += Start-Process npm -ArgumentList "run start" -PassThru
Pop-Location

# Resource Server 01
Push-Location "./ResourceServer01"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

# Resource Server 02
Push-Location "./ResourceServer02"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

Ideally, we would like to be able to open PowerShell and do the following. The output indicates that PowerShell is finding the processes and stopping them, though the command prompts all remain open.

PS> .\RunDemo.ps1
PS> kill-demo
Killing dotnet
dotnet dead
Killing cmd
cmd dead
Killing cmd
cmd dead
Killing dotnet
dotnet dead
Killing dotnet
dotnet dead

The script does work when we start simpler processes like notepad.exe or node.exe without running a web application.

Upvotes: 3

Views: 4996

Answers (2)

Shaun Luttin
Shaun Luttin

Reputation: 141434

The following ended up working to kill the processes and all their child processes.

$global:p = @();

function global:Find-ChildProcess {
    param($ID = $PID)

    $result = Get-CimInstance win32_process |
        Where-Object { $_.ParentProcessId -eq $ID }
    Select-Object -Property ProcessId

    $result |
        Where-Object { $null -ne $_.ProcessId } |
        ForEach-Object {
        Find-ChildProcess -id $_.ProcessId
    }
}

function global:Stop-Demo {
    $global:p |
        ForEach-Object { 
        Stop-Process -Id $_.Id;
        Find-ChildProcess -ID $_.Id;
    } |
        ForEach-Object { 
        Stop-Process -id 
        $_.ProcessId 
    }
}

Push-Location "./AuthorizationServer"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

Push-Location "./AureliaApp"
$global:p += Start-Process npm -ArgumentList "run start" -PassThru
Pop-Location

Push-Location "./OidcClientJs"
$global:p += Start-Process npm -ArgumentList "run start" -PassThru
Pop-Location

Push-Location "./ResourceServer01"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

Push-Location "./ResourceServer02"
$global:p += Start-Process dotnet -ArgumentList "run" -PassThru
Pop-Location

Upvotes: 1

Kory Gill
Kory Gill

Reputation: 7153

You can use Get-Help to discover many capabilities of PowerShell commands. In this case, get-help start-process -full, will describe -PassThru which does:

-PassThru

Returns a process object for each process that the cmdlet started. By default, this cmdlet does not generate any output.

You can use it something like so, and in your case, save the IDs in an array or something similar.

$x = Start-Process notepad.exe -PassThru
# wait some time, etc.
Stop-Process -Id $x.Id

Upvotes: 5

Related Questions