How to Check if a Process Is Running in PowerShell

To check if a process is running in PowerShell, call Get-Process with the name and turn the result into True or False. -ErrorAction SilentlyContinue hides the error when nothing matches:

[bool](Get-Process -Name explorer -ErrorAction SilentlyContinue)

Use the process name without .exe, like explorer or chrome. Below I check several names, start a program only when it isn’t running, wait for it to exit, and cover what changed between PowerShell 7 and Windows PowerShell 5.1.

Check if a process is running (True or False)

Wrapping the check in a small function makes scripts easier to read. Here explorer is running and ContosoSync, a made-up app, isn’t:

function Test-ProcessRunning ([string]$Name) {
    [bool](Get-Process -Name $Name -ErrorAction SilentlyContinue)
}

foreach ($name in 'explorer', 'ContosoSync') {
    '{0,-12} running: {1}' -f $name, (Test-ProcessRunning $name)
}

Output:

explorer     running: True
ContosoSync  running: False
PowerShell check if a process is running and return True or False
explorer is running, ContosoSync isn’t (PowerShell 7)

Get-Process returns one object per running copy, so [bool] is True when at least one exists. The Get-Process guide covers the other columns it returns.

What Get-Process says when the process isn’t running

Without -ErrorAction, a missing process writes an error. It’s the same message in both versions:

try {
    Get-Process -Name ContosoSync -ErrorAction Stop
}
catch {
    "Failed. $($_.Exception.Message)"
}

Output:

Failed. Cannot find a process with the name "ContosoSync". Verify the process name and call the cmdlet again.

That’s useful in a console but noisy in scripts, which is why the function above silences it. -Name also accepts wildcards like ‘chrom*’ when you only know part of the name. More on handling errors is in try and catch in PowerShell.

Start a program only if it isn’t already running

A common job is starting an app once and never twice. I used ping with a hidden window as a harmless test program:

foreach ($try in 1, 2) {
    if (Get-Process -Name PING -ErrorAction SilentlyContinue) {
        "Try ${try}: PING is already running, not starting another"
    }
    else {
        Start-Process ping -ArgumentList '-n', '5', '127.0.0.1' -WindowStyle Hidden
        Start-Sleep -Milliseconds 500
        "Try ${try}: PING wasn't running, started it"
    }
}
"Instances now: $(@(Get-Process -Name PING).Count)"

Output:

Try 1: PING wasn't running, started it
Try 2: PING is already running, not starting another
Instances now: 1
PowerShell start a process only if it is not already running
The second try finds PING running and skips it (PowerShell 7)

The short sleep gives Windows time to register the new process before the next check. Start-Process has the options for arguments, hidden windows and waiting.

Wait for a process to stop

Wait-Process pauses the script until the process exits. With -Timeout it gives up and throws an error instead of waiting forever:

try {
    Wait-Process -Name PING -Timeout 1 -ErrorAction Stop
}
catch {
    "After 1 second: Failed. $($_.Exception.Message)"
}
Wait-Process -Name PING
"PING has exited: $(-not (Get-Process -Name PING -ErrorAction SilentlyContinue))"

Output:

After 1 second: Failed. This command stopped operation because process "PING (72944)" is not stopped in the specified time-out.
PING has exited: True

The error includes the process ID, so it changes on every run. To end a process that’s hung instead of waiting, see killing a process by name.

Who is running the process?

-IncludeUserName adds the account that owns each process. PowerShell 7 shows it in a normal window, but Windows PowerShell 5.1 needs admin rights:

try {
    Get-Process -Name explorer -IncludeUserName -ErrorAction Stop |
        Select-Object -First 1 -Property Name, Id, UserName |
        ForEach-Object { "{0} is running as {1}" -f $_.Name, $_.UserName }
}
catch {
    "Failed. $($_.Exception.Message.Split('.')[0])."
}

Output:

explorer is running as DESKTOP-4T7K2QX\alice
PowerShell Get-Process IncludeUserName requires elevated user rights in 5.1
-IncludeUserName needs an elevated window in 5.1 (Windows PowerShell 5.1)

That’s the PowerShell 7 result, with my real names replaced. In 5.1, Microsoft’s Win32_Process GetOwner method is the documented way around it without elevation. Showing logged-in users is the next step if you need sessions, not processes.

Check if a process is running on a remote computer

Old scripts use Get-Process -ComputerName. PowerShell 7 removed that parameter, and on my PC 5.1 failed even against localhost:

try {
    Get-Process -Name explorer -ComputerName localhost -ErrorAction Stop | Select-Object -First 1 -ExpandProperty Name
}
catch {
    "Failed. $($_.Exception.Message)"
}

Output:

Failed. A parameter cannot be found that matches parameter name 'ComputerName'.

That’s PowerShell 7. Windows PowerShell 5.1 says “Couldn’t connect to remote machine.” Microsoft now points to Invoke-Command, which works in both versions over WinRM:

Invoke-Command -ComputerName PC-AUSTIN-01, PC-DENVER-07 -ScriptBlock {
    [bool](Get-Process -Name ContosoSync -ErrorAction SilentlyContinue)
} | Select-Object PSComputerName, @{ n = 'Running'; e = { $_ } }

I didn’t have a second PC for this one, so it’s shown as code. If Invoke-Command can’t connect, enable WinRM on the target.

Frequently Asked Questions

How do I check if a process is running in PowerShell?

Use [bool](Get-Process -Name name -ErrorAction Sil