Stop-Process kills a process immediately, with no chance to save open files.
For GUI applications (Notepad, Word, browsers), the right approach is to send a close signal to the main window, which is equivalent to clicking the X button:
# The application receives a `WM_CLOSE` message and can handle it normally.
# Output: True
(Get-Process Notepad).CloseMainWindow()
What the Return Value Means
CloseMainWindow() returns True if the close message was delivered successfully. A True return means the message was delivered, not that the process has exited. The process may still be running while it handles the close (e.g., waiting for user input on a “save changes?” dialog).
False means no close message was sent, which happens when the process has no main window (see below).
Wait for the Process to Exit
To wait for the process to actually finish:
$proc = Get-Process Notepad
$proc.CloseMainWindow()
$proc.WaitForExit()
WaitForExit() blocks until the process terminates:
$proc.WaitForExit(5000) # wait up to 5 seconds
It returns True if the process exited within the timeout, False if it’s still running.
Graceful Close with Fallback Kill
Ask nicely first, then force-kill if the process is still alive after a timeout.
$proc = Get-Process Notepad -ErrorAction SilentlyContinue
if ($proc) {
$proc.CloseMainWindow() | Out-Null
if (-not $proc.WaitForExit(5000)) {
$proc | Stop-Process -Force
}
}
The | Out-Null suppresses the True/False return value since we’re checking the outcome via WaitForExit instead.
Processes Without a Main Window
CloseMainWindow() only works for processes with a visible main window. Background services have no main window to close, so the method returns False.
You can check upfront with the MainWindowHandle property, which is 0 for processes without a window:
$proc = Get-Process some-service
if ($proc.MainWindowHandle -eq 0) {
# No window, stop-process is the only option
$proc | Stop-Process
}
For processes without a window, use Stop-Service if available, otherwise Stop-Process.