none
How to script clicking on "X" to close window

    Question

  • Hi,

    I'm a newbie to Powershell.   I'm trying to write a script that will close some applications running on a server gracefully.    The apps are running in CMD windows and the correct procedure to close them is to just click on the "X" in the upper right hand corner.   I assumed that the Alt+F4 keystroke combination would approximate that, but that doesn't work.   Any suggestions would be much appreciated.   My code is:

    #Stop running processes on a Test server
    add-type -AssemblyName microsoft.VisualBasic
    [Microsoft.VisualBasic.Interaction]::AppActivate("TestProcessor")
    add-type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.SendKeys]::SendWait("%F4")

    Shahab

    Saturday, November 10, 2012 6:00 AM

All replies

  • "exit" will close the window, won't it?

    Grant Ward, a.k.a. Bigteddy

    Saturday, November 10, 2012 6:49 AM
  • Only if the app in question has exited leaving cmd.exe in control of the window.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Sunday, November 11, 2012 3:19 AM
  • I tried the following and it didn't do anything, I tried both upper & lowercase:

    add-type -AssemblyName microsoft.VisualBasic
    [Microsoft.VisualBasic.Interaction]::AppActivate("TestProcessor")
    add-type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.SendKeys]::SendWait("Exit") 

    Sunday, November 11, 2012 9:51 PM
  • Tuesday, November 13, 2012 7:48 AM
  • Hi,

    Please refer to the below article:

    SendKeys.Send Method

    http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx

    Also:

    http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/14db808c-d128-416f-a5d8-1bed13dc4131

    Regards,

    Yan Li


    Yan Li

    TechNet Community Support

    Yan, thanks for the link - someone else suggested that to me as well.  Here is my updated script:

    add-type -AssemblyName microsoft.VisualBasic
    [Microsoft.VisualBasic.Interaction]::AppActivate("TestWindow")
    add-type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.SendKeys]::SendWait("%{F4}")

    I tried the script on a test server (Win2k3) on the application I'm testing with and it didn't work.   So then I tried Alt+F4 manually to see if the app would accept the cmd and nothing happened.   I then tried the script with a regular CMD prompt on my wkstn (Win7) and that didn't work either, via script or manually.

    Shahab

    Tuesday, November 13, 2012 2:15 PM
  • alt-F4 and then ctrl-F4 have never been able to close a cmd.exe window, or a powershell window, for that matter.

    When you tried sending the string "EXIT" to the application, did it appear as if you had typed that from the keyboard?

    If your answer is YES, then all you need to do is to send "EXIT~" instead of just "EXIT" to send the enter key to cause the exit command to be executed.

    If your answer is NO, then the application itself did not exit and return control to cmd.exe. The only way to close the application would then be to click on the "X" with your mouse, or to programmatically determine which process the application was running in and close it using stop-process.

    Individual processes can be identified by the name of the executable that was run to start them (.name or .path) or by what appears in the title bar (.MainWindowTitle). For a demonstration:

    • start two instances of cmd.exe
    • in one of the cmd.exe windows , type this command:
    •      title process_to_stop
    • in a powershell window, type this command:
    •      Get-Process | where {$_.mainwindowtitle -like "process_to_stop"} | stop-process

    This should close only the window whose title you changed.

    now all you have to do is to find a way to identify your individual application windows by their title, or by some other means. If the applications are started from a batch file, you could perhaps have the batch file create a unique title with the title command.

    Of course, if you are trying to fully automate the process, you will also need to find a way to determine which applications are in a state where they should be closed.

    I am not sure if the applications in question trap the window close event to do some processing before they actually exit, or, if they do, whether or not using stop-process will have exactly the same effect. Perhaps you can find this out from the company you got these applications from.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Tuesday, November 13, 2012 4:37 PM
  • alt-F4 and then ctrl-F4 have never been able to close a cmd.exe window, or a powershell window, for that matter.

    When you tried sending the string "EXIT" to the application, did it appear as if you had typed that from the keyboard?

    If your answer is YES, then all you need to do is to send "EXIT~" instead of just "EXIT" to send the enter key to cause the exit command to be executed.

    If your answer is NO, then the application itself did not exit and return control to cmd.exe. The only way to close the application would then be to click on the "X" with your mouse, or to programmatically determine which process the application was running in and close it using stop-process.

    Individual processes can be identified by the name of the executable that was run to start them (.name or .path) or by what appears in the title bar (.MainWindowTitle). For a demonstration:

    • start two instances of cmd.exe
    • in one of the cmd.exe windows , type this command:
    •      title process_to_stop
    • in a powershell window, type this command:
    •      Get-Process | where {$_.mainwindowtitle -like "process_to_stop"} | stop-process

    This should close only the window whose title you changed.

    now all you have to do is to find a way to identify your individual application windows by their title, or by some other means. If the applications are started from a batch file, you could perhaps have the batch file create a unique title with the title command.

    Of course, if you are trying to fully automate the process, you will also need to find a way to determine which applications are in a state where they should be closed.

    I am not sure if the applications in question trap the window close event to do some processing before they actually exit, or, if they do, whether or not using stop-process will have exactly the same effect. Perhaps you can find this out from the company you got these applications from.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Al,

    EXIT~ worked for the CMD prompt, but  not for my application.   I will followup with our developers to find out what the correct exit code is, thanks for the help - I appreciate it.

    Shahab

    Tuesday, November 13, 2012 6:30 PM
  • If this is like other applications I worked with long ago, there will be no "exit code", as closing the window is, as you put it, is the "correct" way to close the application.

    If these apps were developed or maintained in-house, I would ask the developers:

    • if stopping the process is just as good as closing the window. If yes, see my above reply for the solution.
    • if they could manage to find some way to close the application that could be implemented in powershell.

    I find it odd to see applications designed in such an old-fashioned way (i.e. dating back to the DOS days) running on a windows server that is advanced enough to run powershell.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Tuesday, November 13, 2012 10:03 PM
  • Hi Al,

    I had a question regarding part of your earlier post, you mentioned: 

    • in a powershell window, type this command:     Get-Process | where {$_.mainwindowtitle -like "process_to_stop"} | stop-process

    I'm trying something similar to close a specific Notepad window.  Typing in the full title is cumbersome, so I want to be able to search for part of the name:

    add-type -AssemblyName microsoft.VisualBasic
    add-type -AssemblyName System.Windows.Forms
    Get-Process | Where-Object {$_.MainWindowTitle -like "*Untitled*"} | Select-Object MainWindowTitle   #Select Notepad window titled #"Untitled -Notepad"

    [System.Windows.Forms.SendKeys]::SendWait("%{F4}")

    When I run this script it closes my powershell ise window.  I've tried using "-contains" as well and it does the same thing, i.e. kills the powershell window rather than Notepad

    Shahab

    Wednesday, November 21, 2012 4:44 PM
  • My example script worked because it was highly unlikely that any other process would have "process_to_stop" as a window title. Apparently notepad processes are not the only ones likely to have "untitled" in their window title.

    The problem with sendkeys is that the window that it operates on is the one currently having the focus. you may have used my trick to identify the process you wanted to operate on, but you have done nothing to give its window the focus. In vbscript this is done like this:

    Set WshShell = CreateObject("WScript.Shell")
    WshShell.AppActivate "notepad" 
    WshShell.SendKeys "Hello World!"
    WshShell.SendKeys "{ENTER}"

    Unfortunately, appactivate seems to lack the sophistication of powershell, as it can only specify the application to activate by giving its name.

    I would strongly recommend against relying on something as flaky an unreliable as sendkeys to manage applications on a server.

    What did the developers say when you asked them the questions I suggested?


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Wednesday, November 21, 2012 7:23 PM
  • I see you used appactivate previously:

        [Microsoft.VisualBasic.Interaction]::AppActivate("TestProcessor")

    Unless it has additional options to activate an app based on some other identifier, this will suffer the same consequences I noted above - unless you can ensure each such application runs with its own unique name. I have, in the past, accomplished this by running multiple instances of robocopy by making copies of robocopy.exe, i.e.: robo-server1.exe, robo-server2.exe, etc. Ugly, and would not work for all possible applications.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Wednesday, November 21, 2012 7:30 PM
  • Al,

    I am using AppActivate for some applications where the name is short and simple.  On others, the name is much longer with spaces in btwn words.  I didn't think that I could do a search with AppActivate so was trying Ge-process instead.  I thought that would activate the window.

    would something like this work : [Microsoft.VisualBasic.Interaction]::AppActivate("Untitled *") ?

    Shahab

    Wednesday, November 21, 2012 7:33 PM
  • get-process gets processes, not all of which have windows capable of becoming "activated" (i.e. getting the focus). There is nothing in the help text for get-process that indicates that it does anything other than to get information about processes. I'd suggest you use the help command to confirm your expectations about such things.

    whether or not appactivate can work with wildcards is something you should be able to test. I doubt that it would work, however. And considering that two processes can have the same "name", while at most only one can recieve the focus, using wildcards seems like asking for trouble.

    On top of that, appactivate exists mainly to provide rudimentary support for older non-scriptable applications. it is, as I have tried to explain, quite unreliable, especially in an environment where events out of your control (receipt of message, assorted popups, etc) can steal the focus before any keys can be sent.

    For these reasons it is my opinion that it should not be used to manage mission critical systems, or, indeed, any application running on servers that are also running mission critical systems.

    once more, and for the last time, if you have a need to automate the closing of these application windows, your best bet is to request a change of functionality from the developers or confirm that it is OK to use Stop-Process (which can be done much more reliably and consistently). If they do not make that change and cannot confirm Stop-Porcess as being OK, then you should revert to what you have referred to as: "the correct procedure to close them", and just live with the inconvenience that has been foisted upon you by the application.


    Al Dunbar -- remember to 'mark or propose as answer' or 'vote as helpful' as appropriate.

    Wednesday, November 21, 2012 11:11 PM
  • this was my answer to this question on powershell.com forum. hope someone will find it useful here. 

    I don't think this is the most robust approach. the alt+f4 won't work for cmdline window and sending alt+space c is dependent on system localization. Or maybe not even possible using sendwait.

    you can use windows API for this purpose as shown here:

    http://www.codeproject.com/Articles/22257/Find-and-Close-the-Window-using-Win-API

    and here I adapted this call for powershell:

    Add-Type -Name ConsoleUtils -Namespace WPIA -MemberDefinition @'
    [DllImport("user32.dll")]
            public static extern int FindWindow(string lpClassName,string lpWindowName);
            [DllImport("user32.dll")]
            public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
                
            public const int WM_SYSCOMMAND = 0x0112;
            public const int SC_CLOSE = 0xF060;
    
    '@
    #find console window with tile "test" and close it. 
              
    [int]$handle = [WPIA.ConsoleUtils]::FindWindow('ConsoleWindowClass','test')
    if ($handle -gt 0)
    {
        [void][WPIA.ConsoleUtils]::SendMessage($handle, [WPIA.ConsoleUtils]::WM_SYSCOMMAND, [WPIA.ConsoleUtils]::SC_CLOSE, 0)
    }  
    

    Thursday, November 22, 2012 10:48 AM
  • WASP is a PowerShell snapin for Windows Automation tasks like selecting windows and controls and sending mouse and keyboard events. We have automation cmdlets like Select-Window, Select-Control, Send-Keys, Send-Click, Get-WindowPosition, Set-WindowPosition, Set-WindowActive, Remove-Window ... etc.

    http://wasp.codeplex.com/


    Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
    Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
    My PowerShell Blog http://www.admin-source.info
    [string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
    German ? Come to German PowerShell Forum!

    Thursday, November 22, 2012 3:10 PM
  • Thanks for the additional information Al.   I will pursue further with our developers.

    Shahab

    Monday, November 26, 2012 6:14 PM