SendKeys

This topic contains 9 replies, has 4 voices, and was last updated by Profile photo of Charles Bates Charles Bates 1 year, 9 months ago.

  • Author
    Posts
  • #21954
    Profile photo of
    Anonymous

    Hi Team,
    I wan to maximize one window by using send keys in powershell. The below code is not working. Please help me asap pls.
    **
    $wshShell = new-object -com wscript.shell
    $wshShell.SendKeys("%{space}x") #not working...

    $wshShell.SendKeys("% x") #not working... 🙁

  • #21955
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Using SendKeys is always a pretty fragile operation (since it depends on the correct window having the active focus). If you do need to do some GUI automation of that sort, I'd highly recommend that you check out AutoIT sometime; it has a nice scripting language, a COM interface, and can be written to interact with specific windows and user controls without depending on keystrokes or focus.

    As far as I know, your second usage of SendKeys should be correct, so long as the window that you want to maximize has focus. It worked for me when I pasted it into a file in the ISE and ran it, at any rate (the ISE was maximized.)

  • #21956
    Profile photo of Tim Pringle
    Tim Pringle
    Participant

    Hey Vidya,

    SendKeys is really best left as a last resort when all else fails. Mention of it has been known to cause some programmers and scripters to collapse in shock at hearing such bad language. 😉

    It's a bit more involved than using SendKeys, but the Win32API has several funtions we can combine to achieve this. I've put together a couple of cmdlets that can be combined to get what you need. Run them, and you can then use the cmdlet like the example below.

    What it does is get the MainWindowHandle value for the process you specify from Get-Process. This is then fed into the two API functions, which perform the operations required. First, it brings the window to the front, and then maximizes it. You can find out a bit more about these functions on MSDN.

    It will fail for if you specify a process to the cmdlet that has more than one instance open (e.g. notepad running twice), but you can easily add extra validation for this if you want to take that into account.

    Example use :

    Set-WindowMaximized -Name notepad
    
    Function Get-Hwnd
    {
      [CmdletBinding()]
        
      Param
      (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [string] $ProcessName
      )
        
      Process
      { $ErrorActionPreference = 'Stop'
        Try 
        {
          $hwnd = Get-Process -Name $ProcessName | Select-Object -ExpandProperty MainWindowHandle
        }
        Catch 
        {
          $hwnd = $null
        }
        $hash = @{
          ProcessName = $ProcessName
          Hwnd        = $hwnd
        }
            
        New-Object -TypeName PsObject -Property $hash
      }
    }
    
    function Set-WindowMaximized
    {
      [CmdletBinding()]
        
      Param
      (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [string] $Name
       
            
      )
        
      Process
      {
        $memberDefinition = @'
        [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll", SetLastError = true)] public static extern bool SetForegroundWindow(IntPtr hWnd);
    
    '@
    
        Add-Type -MemberDefinition $memberDefinition -Name Api -Namespace User32
        $hwnd = Get-Hwnd -ProcessName $Name | Select-Object -ExpandProperty Hwnd
        If ($hwnd) 
        {
          $onTop = New-Object -TypeName System.IntPtr -ArgumentList (0)
          [User32.Api]::SetForegroundWindow($hwnd)
          [User32.Api]::ShowWindow($hwnd, 3)
        }
        Else 
        {
          [string] $hwnd = 'N/A'
        }
    
        $hash = @{
          Process = $Name
          Hwnd    = $hwnd
        }
            
        New-Object -TypeName PsObject -Property $hash
      }
    }
    
    
  • #21967
    Profile photo of
    Anonymous

    Hi Tim Pringle,
    That was a mind blowing job. Honestly I am in vain to understand the code but you given is the perfect solution of my requirement and that worked fine for me.
    But still I am not clear why "$wshShell.SendKeys("% x")" is not working for powershell.exe (but fine for ISE)? any reason?

  • #21977
    Profile photo of Tim Pringle
    Tim Pringle
    Participant

    I'm happy to give extra information on the script if you want on it mate,no worries.

    I'm been playing around with SendKeys for the last 15 minutes or so, and experiencing exactly the same situation. It almost seems like ALT is not processed at all. The SendKeys equivalent of ALT+SPACE does not work for example. Also tried it with .NET's [System.Windows.Forms.SendKeys]::Send method and get similar results.

    All I can think of at the moment is that the behavior is different at some level because it is command line based. In vbscript previously for example, you would normally use cscript.exe for running vbs files within a command prompt session, and wscript.exe for form based apps. Thats me just thinking aloud there though, nothing to confirm this is why.

    Will keep digging though, it's an interesting one. 🙂

  • #21979
    Profile photo of
    Anonymous

    Hey Tim,
    I just modified your code as per my requirement. The below code is working very fine but the issue is after running the command it is echoing the Boolean values which I don't want. Can you tell me how to avoid this?
    ****
    function Set-WindowMaximized
    {
    Process
    {
    $temp_PSCal1=$Host.UI.RawUI.MaxPhysicalWindowSize
    $temp_PSCal1.Width-=3
    $temp_PSCal1.Height=9999
    $Host.UI.RawUI.BufferSize=$temp_PSCal1
    $temp_PSCal2=$Host.UI.RawUI.WindowSize
    $temp_PSCal2.Width=$temp_PSCal1.Width-=3
    $Host.UI.RawUI.WindowSize=$temp_PSCal2
    $memberDefinition = @'
    [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("user32.dll", SetLastError = true)] public static extern bool SetForegroundWindow(IntPtr hWnd);

    '@

    Add-Type -MemberDefinition $memberDefinition -Name Api -Namespace User32
    [int]$hwnd = Get-Process -Id $PID | Select-Object -ExpandProperty MainWindowHandle
    If ($hwnd)
    {
    $onTop = New-Object -TypeName System.IntPtr -ArgumentList (0)
    [User32.Api]::SetForegroundWindow($hwnd)
    [User32.Api]::ShowWindow($hwnd, 3)
    }
    }
    }

  • #21983
    Profile photo of Tim Pringle
    Tim Pringle
    Participant

    Yes, that'll be the API functions, forgot about that.

    Try this :

    $null = [User32.Api]::SetForegroundWindow($hwnd)
    $null = [User32.Api]::ShowWindow($hwnd, 3)
    
  • #21985
    Profile photo of
    Anonymous

    great. that worked bro for me. Thanks a lot.

  • #21986
    Profile photo of
    Anonymous

    Tim, I am very interested to learn about this sort of coding. what language is this?

    [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow)

    any resourced to learn pls?

  • #23079
    Profile photo of Charles Bates
    Charles Bates
    Participant

    Great topic! While I'm out digging on my own, I'm hoping you can point towards the modules/functions that would allow me to write to the console command line.
    (I'm trying to build a facility to allow recall and editing of previous commands. I have a version working with SendKeys, but it is pretty wobbly with almost all shifted keystrokes — '$', for instance.)

    Thanks —

You must be logged in to reply to this topic.