I'm looking for a way to gracefully close/quit the GoogleDrive app which runs under the process GoogleDriveFS.
get-process GoogleDriveFS
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
219 16 10796 5732 0.05 4392 1 GoogleDriveFS
333 22 11820 32364 0.17 8424 1 GoogleDriveFS
297 19 16528 34860 0.06 12036 1 GoogleDriveFS
245 17 10472 23992 0.03 14296 1 GoogleDriveFS
572 26 52256 82728 0.84 17788 1 GoogleDriveFS
518 21 28668 68208 0.44 18460 1 GoogleDriveFS
1024 59 47016 89396 27.95 19452 1 GoogleDriveFS
is something like Process.CloseMainWindow Method suitable for this ? or is there a better way to ensure the app isn't running?
tl;dr
System.Diagnostics.Process.CloseMainWindow()
will not work, for the reasons explained in the bottom section.
Note:
You can try the following to achieve graceful termination, but there's no guarantee it will work:
# Asks all GoogleDriveFS processes to terminate, which they may or may not do.
# A status line is output to stdout for each targeted process,
# indicating whether the termination request was successfully *sent*.
# Note: ".exe" must be used, whereas it mustn't be
# with PowerShell's *-Process cmdlets.
taskkill.exe /im GoogleDriveFS.exe
If it doesn't, forceful termination is your only option, which is most easily accomplished with:
# !! Forcefully terminates all GoogleDriveFS, without cleanup.
Stop-Process -Force -Name GoogleDriveFS
Note: As discussed below, Stop-Process
always terminates forcefully. The only function of the -Force
switch is to suppress a potential confirmation prompt that is presented when you attempt to terminate processes belonging to a different user (only works with elevation).
Here's a snippet that first tries graceful termination, then falls back to forceful termination after a specifiable timeout:
$processName = 'GoogleDriveFS'
$timeOutSecs = 2
# Get all existing processes of interest.
$processes = Get-Process -ErrorAction Ignore -Name $processName
if (-not $processes) {
Write-Verbose -Verbose "No $processName processes running."
} else {
# Ask the processes to terminate, which they may or may not do.
taskkill.exe /im "$processName.exe" *>$null
try {
# Wait for up to $timeOutSecs seconds for the processes to -
# potentially - terminate gracefully.
$processes | Wait-Process -ErrorAction Stop -Timeout $timeOutSecs
} catch {
Write-Warning "Forcefully terminating (remaining) $processName processes..."
# Note: This assumes that you don't care about any new
# processes that may have launched since Get-Process was called.
$processes | Stop-Process -Force
}
}
On Windows, graceful termination is fundamentally only an option for GUI-subsystem applications, i.e. processes that have a main window (whether visible or not) and therefore a message loop to which the WM_CLOSE
message can be posted.
In other words: you cannot ask console applications on Windows to terminate gracefully (unless they implement some application-specific custom mechanism through which other processes can request termination).
For supported applications, there are important considerations:
Termination isn't guaranteed, and even if it does happen, its timing isn't guaranteed:
WM_CLOSE
message, such as when it happens to be displaying a modal dialog at the time or happens to be stuck.Therefore, if you need to ensure termination, you'll have to monitor the process for actual termination afterwards, and possibly terminate it forcefully after a suitable timeout period.
taskkill.exe
offers forceful termination via its /f
option.System.Diagnostics.Process.Kill()
Stop-Process
cmdlet invariably uses this method, i.e. invariably terminates processes forcefully - allowing requesting graceful termination on an opt-in basis is the subject of GitHub issue #13664.At the Windows API level, it doesn't matter if the targeted main window is visible or not, so that even (GUI-subsystem) processes that by design run invisibly - as GoogleDriveFS.exe
appears to be - can be targeted with a WM_CLOSE
message.
While System.Diagnostics.Process.CloseMainWindow()
is designed to request graceful termination of a given process by sending a WM_CLOSE
message to its main window, it unfortunately doesn't find that window if it happens to be invisible (hidden) (still applies as of .NET 6.0)
By contrast, the taskkill.exe
utility does not have this limitation.
A limitation that BOTH methods share is the inability to target processes that are UWP / Microsoft Store applications.
EnumWindows
WinAPI method, which only supports desktop applications.FindWindowEx
and posting WM_CLOSE
to it, is possible.