Steff Steff - 3 years ago 159
C# Question

Powershell/selenium Send keys to pop up window

I have written a code that opens a pop up window where i have to select the file path in order to upload it.See link to view popup screen

Now I want this script to run in the background. However, this is not possible with the Wshell command I have used.

Is there a way I can replace the Wshell command?

#go to the uploadtab
#---------------------
$searchBtnIris2 = $driver.FindElementByXPath('//*[@id="menuFormHome:j_id44_body"]/ul[3]/li[4]/a')
Write-Host "Den ID van de zoekknop is $seachBtnIris2"
$searchBtnIris2.Click();

Start-Sleep -s 15


#click add button and select file to upload
#-------------------------------------------
$searchBtnIris3 = $driver.FindElementByXPath('//*[@id="uploadFormPanel:upload:flashContainer"]')
Write-Host "Den ID van de zoekknop is $seachBtnIris3"
$searchBtnIris3.Click();

Start-Sleep -s 1

$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('title of the application window')
Sleep 1
$wshell.SendKeys('C:\Users\SVan37\Documents\test\EDI_IRIS_UPLOAD.xlsx');

$wshell.SendKeys('~')

Start-Sleep -s 1



Answer Source

Here's a quick and dirty method. Paste the entire code block below into your script and call it like so:

Set-OpenFileDialogPath -Path 'C:\Users\SVan37\Documents\test\EDI_IRIS_UPLOAD.xlsx' -OwnerBinaryFileName 'chrome.exe'

<#
.SYNOPSIS
Sets the path of all open file dialogs, optionally filtered by binary file name.

.PARAMETER Path
The file path to use.

.PARAMETER OwnerBinaryFileName
The binary file name to filter by, such as chrome.exe.

.OUTPUTS
System.Boolean. True if at least one open file dialog was found and updated; false otherwise.
#>

function Set-OpenFileDialogPath
{
    Param(
        [Parameter(Mandatory = $true)]
        [string]
        $Path,

        [string]
        $OwnerBinaryFileName
    )

    # Add Win32 window functions, ignoring the exception if they've already been added
    try
    {
        $user32 = Add-Type -Name 'user32' -Namespace 'Win32' -PassThru -MemberDefinition @'
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
'@
    }
    catch
    {
    }

    $foundOne = $false
    $lastOpenDialogHwnd = [IntPtr]::Zero

    # Loop over all open file dialogs
    while ($true)
    {
        # Find the open file dialog
        $lastOpenDialogHwnd = $user32::FindWindowEx([IntPtr]::Zero, $lastOpenDialogHwnd, '#32770', 'Open')
        if ($lastOpenDialogHwnd -eq [IntPtr]::Zero)
        {
            break
        }

        # If a binary filter was specified and the found open file dialog doesn't belong, look for the next dialog
        if (![string]::IsNullOrEmpty($OwnerBinaryFileName))
        {
            $processId = 0
            $user32::GetWindowThreadProcessId($lastOpenDialogHwnd, [ref]$processId) | Out-Null
            $process = [Diagnostics.Process]::GetProcessById($processId -as [int])
            if ([IO.Path]::GetFileName($process.MainModule.FileName) -ine $OwnerBinaryFileName)
            {
                continue
            }
            $process.Dispose()
        }

        # Find the Open button
        $buttonHwnd = $user32::FindWindowEx($lastOpenDialogHwnd, [IntPtr]::Zero, 'Button', '&Open')

        # Find the open file dialog's file name textbox
        $comboBoxExHwnd = $user32::FindWindowEx($lastOpenDialogHwnd, [IntPtr]::Zero, 'ComboBoxEx32', $null)
        if ($comboBoxExHwnd -ne [IntPtr]::Zero -and $buttonHwnd -ne [IntPtr]::Zero)
        {
            $comboBoxHwnd = $user32::FindWindowEx($comboBoxExHwnd, [IntPtr]::Zero, 'ComboBox', $null)
            if ($comboBoxHwnd -ne [IntPtr]::Zero)
            {
                $editHwnd = $user32::FindWindowEx($comboBoxHwnd, [IntPtr]::Zero, 'Edit', $null)
                if ($editHwnd -ne [IntPtr]::Zero)
                {
                    # Set the open file dialog's file name textbox to the desired path
                    $user32::SendMessage($editHwnd, 12, [IntPtr]::Zero, $Path) | Out-Null

                    # Click "Open"
                    $user32::SendMessage($buttonHwnd, 245, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null

                    $foundOne = $true
                }
            }
        }
    }

    return $foundOne
}

(For clarity given its length, the above code is licensed under the Unlicense license, meaning it's free for any kind of use and modification and has no attribution or license inclusion requirements.)

Notes

  • The function uses SendMessage rather than SendKeys, so it will work regardless of whether the open file dialog is hidden or inactive. (In fact, it will work even if you're actively typing in another window while it runs.)
  • Calling the function with chrome.exe as the OwnerBinaryFileName causes it to update the file name textboxes of all open file dialogs that belong to chrome.exe. Thus, if there's the possibility that multiple instances of chrome.exe could be displaying open file dialogs at the same time, you should add a couple lines that check whether the tab name of the dialog's owning process window matches the one you're targeting.
  • If you need to do more dialog automation through PowerShell in the future, I'd recommend checking out WASP (Windows Automation Snapin for PowerShell). Unfortunately, it's hosted on soon-to-be-defunct CodePlex, and it doesn't seem to have a presence on GitHub yet, so hopefully someone will pick it up before December 15, 2017 (CodePlex's planned date for total shutdown).
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download