3

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?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Tony
  • 8,681
  • 7
  • 36
  • 55
  • might be useful: https://superuser.com/questions/1682641/how-to-check-if-process-is-running-properly-in-powershell – Tony Apr 08 '22 at 16:09

3 Answers3

2

tl;dr

System.Diagnostics.Process.CloseMainWindow() will not work, for the reasons explained in the bottom section.

Note:

  • If the target processes weren't started from your own user account, you'll need to run the following from an elevated (run as admin) session.

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:

        • The target process may be in a state where it cannot process the WM_CLOSE message, such as when it happens to be displaying a modal dialog at the time or happens to be stuck.
        • The target process may quietly refuse to terminate.
        • The target process may put up a modal dialog to confirm the intent to terminate, notably when trying to close an editor-like application that has an unsaved document open.
      • 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.

  • 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.

      • However, this applies only to "pure" UWP applications (e.g, Settings, Calculator), and not to desktop applications packaged as UWP apps (e.g., Windows Terminal, Microsoft Edge).
      • The reason is that both methods rely on the EnumWindows WinAPI method, which only supports desktop applications.
      • However, manually finding a UWP application's main window via FindWindowEx and posting WM_CLOSE to it, is possible.
mklement0
  • 382,024
  • 64
  • 607
  • 775
1

You can do something like this:

do {
    $running = try { Get-Process -Name GoogleDriveFS -ErrorAction Stop } catch { Write-Host "Error: $($PSItem.Exception.Message) " }
    $running | ForEach-Object {
        
        $_.CloseMainWindow()
        Write-Debug -Message "Closing ($_).pm "
    
    }
}
until ($running -eq $null)

However, this will prompt for the user to confirm the close.

You could also use the close() method to avoid prompting the user or kill() to immediately release all resources.

CloseMainWindow() Closes a process that has a user interface by sending a close message to its main window.

Close() Frees all the resources that are associated with this component.

Kill() Immediately stops the associated process.

via https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=net-6.0#methods

  • 1
    Unfortunately, `.CloseMainWindow()` won't work with processes whose main windows is _hidden_, which I think is the case here. `.Close()` has no effect on the target process at all - it simply frees the resources associated with _its representation in .NET_ – mklement0 Apr 08 '22 at 21:45
0

You could use the --quit argument of GoogleDriveFS.exe :

"C:\Program Files\Google\Drive File Stream\64.0.4.0\GoogleDriveFS.exe" --quit

But it will break after each software update so running this bat file should be better :

"%ProgramFiles%\Google\Drive File Stream\launch.bat" --quit

This bat file looks up the latest GoogleDriveFS.exe and runs it with the same arguments as the script.

And from Powershell :

Start-Process -FilePath "${env:ProgramFiles}\Google\Drive File Stream\launch.bat" -ArgumentList '--quit' -Wait -NoNewWindow
Bruno
  • 160
  • 6