Powershell - CloseMainWindow 对所有人有用吗?

Powershell - CloseMainWindow work for all?

我正在寻找一种优雅地 close/quit 在 GoogleDriveFS 进程下运行的 GoogleDrive 应用程序的方法。

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

类似 Process.CloseMainWindow 的方法适合这个吗?还是有更好的方法来确保该应用不是 运行?

你可以这样做:

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)

但是,这将提示用户确认关闭。

您也可以使用 close() 方法来避免提示用户或 kill() 立即释放所有资源。

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.

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

tl;dr

System.Diagnostics.Process.CloseMainWindow() 工作,原因在底部解释。

注:

  • 如果目标进程不是从您自己的用户帐户启动的,您需要 运行 从 提升的 (运行作为管理员)会话。

你可以尝试以下实现优雅终止,但不能保证它会起作用:

# 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

如果没有,强制终止是您唯一的选择,最容易实现的是:

# !! Forcefully terminates all GoogleDriveFS, without cleanup.
Stop-Process -Force -Name GoogleDriveFS

注意:如下所述,Stop-Process 总是 强制终止。 -Force 开关的唯一功能是抑制在您尝试终止属于不同用户的进程时出现的潜在确认提示(仅适用于提升)。

这是一个 片段,它首先尝试正常终止,然后在指定的超时后退回到强制终止:

$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
  }
}

  • 在 Windows 上,正常 终止基本上只是 GUI-subsystem 应用程序的一个选项,即具有主 window(无论可见与否)的进程,因此有一个 消息循环 ,可以将 WM_CLOSE 消息发布到其中。

    • 换句话说:你不能要求console Windows 上的应用程序正常终止(除非他们实现了一些 application-specific 自定义机制,其他进程可以通过该机制请求终止)。

    • 对于受支持的应用程序,有重要注意事项

      • 无法保证终止,即使确实发生,也无法保证其时机

        • 目标进程可能处于无法处理WM_CLOSE消息的状态,比如当时恰好在显示模态对话框,或者恰好卡住了。
        • 目标进程可能会悄悄地拒绝终止。
        • 目标进程可能会提出一个模式对话框来确认终止的意图,特别是在试图关闭一个打开了未保存文档的 editor-like 应用程序时。
      • 因此,如果您需要确保终止,您必须监控进程以实际终止之后,可能会在适当的超时时间.

        强行终止它
  • 在WindowsAPI层级,目标主window是否可见无所谓,因此即使 (GUI-subsystem) 处理通过设计 运行 不可见的 - as GoogleDriveFS.exe appears to be - 也可以用 WM_CLOSE 作为目标消息。

    • 虽然System.Diagnostics.Process.CloseMainWindow()旨在通过发送WM_CLOSE 消息到它的主要 window,不幸的是 没有发现 window 如果它碰巧是不可见的(隐藏) (从 .NET 6.0 开始仍然适用)

    • 相比之下,taskkill.exe 实用程序没有 有此限制

    • 这两种方法的共同限制是无法针对 UWP/Microsoft Store 应用程序.

      • 但是,此仅适用于“纯”UWP 应用程序(例如,设置、计算器),不适用于桌面应用程序打包为 UWP 应用程序(例如,Windows 终端、Microsoft Edge)。
      • 原因是这两种方式都依赖于EnumWindowsWinAPI方式,只支持桌面应用
      • 但是,手动通过FindWindowEx找到UWP应用程序的主要window并向其发布WM_CLOSE 可能。