Friday, July 4, 2014

Gracefully shutdown Windows programs via Powershell

The problem with programmatically killing apps is that you may lose work or skip steps that are required or useful that would normally be accomplished by the application when shutdown properly.

To accomplish this there is a method implemented by Windows processes called CloseMainWindow(). However, some applications like Firefox have multiple windows spawned and CloseMainWindow() will only close the last focused window. In order to close all of the windows you must loop around and call CloseMainWindow() until all windows are closed.

This can be accomplished the following one-liner, replace <app name> with the name of your application (you don't need to include the extension .exe):

powershell -Command "while ($true){Try{$process=Get-Process <app name> -ErrorAction Stop}Catch [Microsoft.PowerShell.Commands.ProcessCommandException]{break;}if ($process) {$whateva=$process.CloseMainWindow()}else {break;}Start-Sleep -m 500}"

E.g. to close firefox
powershell -Command "while ($true){Try{$process=Get-Process firefox -ErrorAction Stop}Catch [Microsoft.PowerShell.Commands.ProcessCommandException]{break;}if ($process) {$whateva=$process.CloseMainWindow()}else {break;}Start-Sleep -m 500}"

##terminate a process gracefully

while ($true) {
Try
 {
   ## Tell powershell to stop on error
   $process = Get-Process firefox -ErrorAction Stop
 }
 Catch  [Microsoft.PowerShell.Commands.ProcessCommandException]
 {
  break;
 }
   if ($process) {
     ## catch the output in a variable to avoid echo'ing TRUE/FALSE to stdout
     $whateva = $process.CloseMainWindow()
    }
   else {
    break;
  }
   ## Sleep for half a second to avoid race condition of shutting down the app and looping
   Start-Sleep -m 500
}   

If you use a VM or Cygwin:

grace_kill_win.bsh:

#!/usr/bin/env bash
powershell -Command "while (\$true){Try{\$process=Get-Process $1 -ErrorAction Stop}Catch [Microsoft.PowerShell.Commands.ProcessCommandException]{break;}if (\$process) {\$whateva=\$process.CloseMainWindow()}else {break;}Start-Sleep -m 500}"

Afterward you can create an alias for it:
alias gkw='grace_kill_win.bsh'

Then you can kill anything gracefully with the command: gkw <application name>

No comments:

Post a Comment