Using PowerShell and Selenium for Browser Automation

Selenium is a portable software-testing framework for web applications.  It’s pretty cool (in a geeky way) and is primarily used to test web applications. In this instance we’re using it to launch Internet Explorer, load a web-based helpdesk dashboard on the intranet, log into it and click a few buttons to customise the view. Using PowerShell and Selenium for browser automation is a great way to perform both functional and performance testing.

Using PowerShell and Selenium for Browser Automation

You’ll need to download IEDriverServer.exe.  Go to this location:

http://selenium-release.storage.googleapis.com/index.html

Choose the folder for the most recent version, and download IEDriverServer_Win32_[version].zip

Then download Selenium.WebDriver Nuget package from here: https://www.nuget.org/packages/Selenium.WebDriver/

and Selenium.Support Nuget package from here: https://www.nuget.org/packages/Selenium.Support/

Rename the extensions of each file from .nupkg to .zip, and extract them as you would normally.  If you then look in the Lib folder of each archive you will find:

WebDriver.dll and WebDriver.Support.dll.

An Example of Browser Automation

Thi example demonstrates Internet Explorer browser automation since it’s probably the most prevalent browser in corporate environments.  However Selenium does have libraries for Firefox and Chrome too.

So for this example, put IEDriverServer.exe, WebDriver.dll, WebDriver.Support.dll and this PS1 file all in the same folder.  Read the inline comments in the script for an explanation.  To get the website element IDs you’ll need to use the DOM explorer of the browser, but I won’t go into detail of how to do that here.

#add references to the Selenium DLLs 
$WebDriverPath = Resolve-Path "$PSScriptRoot\WebDriver.dll"
#I unblock it because when you download a DLL from a remote source it is often blocked by default
Unblock-File $WebDriverPath
Add-Type -Path $WebDriverPath

$WebDriverSupportPath = Resolve-Path "$PSScriptRoot\WebDriver.Support.dll"
Unblock-File $WebDriverSupportPath
Add-Type -Path $WebDriverSupportPath

#before we start, we must ensure all zones are running either in protected mode, or not.  They need to all be the same.
#(we might be able to negate the requirement for some of these using InternetExplorerOptions.IntroduceInstabilityByIgnoringProtectedModeSettings)

#set protected
#local
New-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0" -Name "2500" -Value 0 -PropertyType DWORD -Force | Out-Null
#internet
New-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1" -Name "2500" -Value 0 -PropertyType DWORD -Force | Out-Null
#intranet
New-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\2" -Name "2500" -Value 0 -PropertyType DWORD -Force | Out-Null
#trusted
New-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3" -Name "2500" -Value 0 -PropertyType DWORD -Force | Out-Null
#restricted
New-ItemProperty "hkcu:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\4" -Name "2500" -Value 0 -PropertyType DWORD -Force | Out-Null

#fix to run in kiosk mode (to use ForceCreateProcessApi this must be 0. ForceCreateProcessApi is required to use BrowserCommandLineArguments)
New-ItemProperty "hkcu:\Software\Microsoft\Internet Explorer\Main" -Name "TabProcGrowth" -Value 0 -PropertyType DWORD -Force | Out-Null

#Set zoom 100%.  Again, we can probably use InternetExplorerOptions.IgnoreZoomSetting as an alternative
New-ItemProperty "hkcu:\Software\Microsoft\Internet Explorer\Zoom" -Name "ZoomFactor" -Value 100000 -PropertyType DWORD -Force | Out-Null

#can pass this stuff in when we instantiate driver if needs be (if we want a chromeless browser for example)
$seleniumOptions = New-Object OpenQA.Selenium.IE.InternetExplorerOptions
#open this URL when Internet Explorer launches
$seleniumOptions.InitialBrowserUrl = "https://localhost:8080";
#we require this option to run in kiosk mode
$seleniumOptions.ForceCreateProcessApi = $true
#open Internet Explorer in kiosk mode
$seleniumOptions.BrowserCommandLineArguments = "-k"
#untested - ignore zoom options, negating the registry fix above
#$seleniumOptions.IgnoreZoomSetting = $true

#now we create a default service so we can run Selenium without the black debug command prompt appearing
#pre-PowerShell 5 we can do it like so
New-Variable -Name IEDS -Value ([OpenQA.Selenium.IE.InternetExplorerDriverService]) -Force
$defaultservice = $IEDS::CreateDefaultService()

#PowerShell 5 we can do it like so
#$defaultservice = [OpenQA.Selenium.IE.InternetExplorerDriverService]::CreateDefaultService()

#hide command prompt
$defaultservice.HideCommandPromptWindow = $true;

#provide our default service and selenium options to the Internett Explorer driver (calling this opens the IE session)
$seleniumDriver = New-Object OpenQA.Selenium.IE.InternetExplorerDriver -ArgumentList @($defaultservice, $seleniumOptions)

#now we start clicking elements on the web page.  We do this by finding the ID of the element we want to interact with.

#enter a username into login prompt
$seleniumWait = New-Object -TypeName OpenQA.Selenium.Support.UI.WebDriverWait($seleniumDriver, (New-TimeSpan -Seconds 10))
$seleniumWait.Until([OpenQA.Selenium.Support.UI.ExpectedConditions]::ElementIsVisible([OpenQA.Selenium.By]::Id("textfield-1011-inputEl")))
$seleniumDriver.FindElementById("username_text").SendKeys("exampleusernname")

#enter a password into login prompt
$seleniumWait = New-Object -TypeName OpenQA.Selenium.Support.UI.WebDriverWait($seleniumDriver, (New-TimeSpan -Seconds 10))
$seleniumWait.Until([OpenQA.Selenium.Support.UI.ExpectedConditions]::ElementIsVisible([OpenQA.Selenium.By]::Id("textfield-1012-inputEl")))
$seleniumDriver.FindElementById("password_text").SendKeys("examplepassword")

#click 'login' button
$seleniumWait = New-Object -TypeName OpenQA.Selenium.Support.UI.WebDriverWait($seleniumDriver, (New-TimeSpan -Seconds 10))
$seleniumWait.Until([OpenQA.Selenium.Support.UI.ExpectedConditions]::ElementIsVisible([OpenQA.Selenium.By]::Id("loginButton")))
$seleniumDriver.FindElementById("loginButton").Click()

#when logged in, click another button
$seleniumWait = New-Object -TypeName OpenQA.Selenium.Support.UI.WebDriverWait($seleniumDriver, (New-TimeSpan -Seconds 10))
$seleniumWait.Until([OpenQA.Selenium.Support.UI.ExpectedConditions]::ElementIsVisible([OpenQA.Selenium.By]::Id("button-1025")))
$seleniumDriver.FindElementById("random_button").Click()

#we don't close it in this instance because we want to keep the browser open as a dashboard view
#$seleniumDriver.Close()
#$seleniumDriver.Dispose()
#$seleniumDriver.Quit()