This project is read-only.

Send-Keys: Send a sequence of keys to an application window based on Window Title

Topics: Archive - Toolkit Extensions
Developer
Jul 10, 2014 at 12:13 AM
I am using a custom logging function posted on another thread in this forum. Write-ErrorStack function is also posted to another thread in this forum.
Function Send-Keys
{
<#
    .SYNOPSIS
        Send a sequence of keys to an application window
    
    .DESCRIPTION
        This Send-Keys script send a sequence of keys to an application window. 
    
    .PARAMETER WindowTitle
        The title of the application window. This can be a partial title.
    
    .PARAMETER Keys
        The sequence of keys to send
    
    .PARAMETER WaitSeconds
        An optional number of seconds to wait after the sending of the keys
    
    .EXAMPLE
        Send-Keys "foobar - Notepad" "Hello world"
    
    Send the sequence of keys "Hello world" to the application titled "foobar - Notepad".
    
    .EXAMPLE
        Send-Keys "foobar - Notepad" "Hello world" -WaitSeconds 5
    
        Send the sequence of keys "Hello world" to the application titled "foobar - Notepad" and wait 5 seconds.
    
    .EXAMPLE
        New-Item foobar.txt -ItemType File
        notepad foobar.txt
        Send-Keys "foobar - Notepad" "Hello world{ENTER}Ciao mondo{ENTER}" -WaitSeconds 1
        Send-Keys "foobar - Notepad" "^s"

        This command sequence creates a new text file called foobar.txt, opens the file using notepad.exe,
        writes some text, and saves the file using notepad.
    
    .LINK
        http://msdn.microsoft.com/en-us/library/System.Windows.Forms.SendKeys(v=vs.100).aspx
#>
    
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,Position=1)]
        [string]$WindowTitle,

        [Parameter(Mandatory=$true,Position=2)]
        [string]$Keys,

        [Parameter(Mandatory=$false)]
        [int]$WaitSeconds
    )
    
    Begin
    {
        ${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        $PSParameters = New-Object -TypeName PSObject -Property $PSBoundParameters
        
        Write-Log -Message "Function Start" -Component ${CmdletName} -Severity 1
        If (-not [string]::IsNullOrEmpty($PSParameters))
        {
            Write-Log -Message "Function invoked with bound parameters [$PSParameters]" -Component ${CmdletName} -Severity 1
        }
        Else
        {
            Write-Log -Message "Function invoked without any bound parameters" -Component ${CmdletName} -Severity 1
        }
    }
    Process
    {
        Try
        {
            # Load assembly containing class System.Windows.Forms.SendKeys
            Add-Type -AssemblyName System.Windows.Forms -ErrorAction 'Stop'
            
            # Add a C# class to access the WIN32 API SetForegroundWindow
            $SetForegroundWindow = @"
                using System;
                using System.Runtime.InteropServices;
                public class WINDOW
                {
                    [DllImport("user32.dll")]
                    [return: MarshalAs(UnmanagedType.Bool)]
                    public static extern bool SetForegroundWindow(IntPtr hWnd);
                }
"@
            If (-not ([System.Management.Automation.PSTypeName]'WINDOW').Type)
            {
                Add-Type $SetForegroundWindow -ErrorAction 'Stop'
            }
            
            # Get the process with the specified window title
            $Process = Get-Process -ErrorAction 'Stop' | Where-Object { $_.MainWindowTitle.Contains($WindowTitle) }
            If ($Process)
            {
                # Get the window handle of the first process only if there is more than one process returned
                $ProcessHandle = $Process[0].MainWindowHandle
                
                # Bring the process to the foreground
                $ActivateWindow = [WINDOW]::SetForegroundWindow($ProcessHandle)
                
                # Send the Key sequence
                # Info on Key input at: http://msdn.microsoft.com/en-us/library/System.Windows.Forms.SendKeys(v=vs.100).aspx
                If ($ActivateWindow)
                {
                    [System.Windows.Forms.SendKeys]::SendWait($Keys)
                }
                Else
                {
                    # Failed to bring the window to the foreground. Do nothing.
                }
                
                If ($WaitSeconds)
                {
                    Start-Sleep -Seconds $WaitSeconds
                }
            }
        }
        Catch
        {
            Write-Log -Message "Failed to Send Keys `n$(Write-ErrorStack)" -Component ${CmdletName} -Severity 3
            Exit
        }
    }
    End
    {
        Write-Log -Message "Function End" -Component ${CmdletName} -Severity 1
    }
}
Coordinator
Aug 2, 2014 at 2:01 PM
This is a function we think could be very useful so if it's OK with you we're going to make a few tweaks and add it in to the core toolkit.

Thanks for the excellent contributions!

Thanks,
Sean
Developer
Aug 3, 2014 at 2:26 AM
Absolutely, go for it.