What’s it all about?
In this post, I’ll show how you can automate the update of Selenium Web Driver with PowerShell.
Selenium is a great tool for web browser automation. It’s widely used for testing, robotic process automation, or just scripting. It can be easily used with PowerShell. The basic building block of Selenium is a Selenium Web Driver. It’s provided by the browser’s vendor and its presence is necessary for any script or application using this framework.
The challenge is that the web browser is often updated – nowadays it happens more-less automatically, even in an enterprise scenario. However, the Selenium Web Driver is treated as a separate component. Thus, it’s not included into the update.
This can cause compatibility issues and your script throwing an error like: “MethodInvocationException: Exception calling ".ctor" with "2" argument(s): "session not created: This version of ChromeDriver only supports Chrome version 87 Current browser version is 102.0.5005.115 with binary path…”
.
What to do?
The solution is to automate the update of the web driver. Even better, merge it with the web browser patching or update process in your environment. Or, in case you don’t have control over that, at least schedule it daily or weekly.
The good thing is that if the web driver version is not too old the script will work – in most cases. You will see a warning: “This version of ChromeDriver has not been tested with Chrome version…”
but it will continue. So, a weekly check is good enough – at least if you accept that this warning is showing up:
Check the browser version
I will focus on web browsers that are used the most in my environment: MS Edge and Chrome. Most probably you can apply a similar approach to other browsers, but I’ve never tried it.
This action is fairly simple. I suggest checking the product version attribute of each application in the registry (there are multiple other ways):
$edgeRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe"
$chromeRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe"
$edgeVersion = (Get-Item (Get-ItemProperty $edgeRegistryPath).'(Default)').VersionInfo.ProductVersion
$chromeVersion = (Get-Item (Get-ItemProperty $chromeRegistryPath).'(Default)').VersionInfo.ProductVersion
As a result, you get two strings with current versions:
Check the driver version
Now you need to know what the version of your driver is. Otherwise, you might unnecessarily overwrite the up-to-date version at each execution.
You need to know the exact path to your drivers (update it accordingly):
$webDriversPath = "C:\Program Files\PowerShell\7\Modules\Selenium\3.0.1\assemblies\"
$edgeDriverPath = "$($webDriversPath)msedgedriver.exe"
$chromeDriverPath = "$($webDriversPath)chromedriver.exe"
The version of Chrome driver isn’t stored in the file’s metadata. However, you can run the driver with the -v
switch to get its version and then parse the output.
Once launched with the -v
switch, the driver behaves like a console application, so you can get its output in a standard way.
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
$processInfo.FileName = $path
$processInfo.RedirectStandardOutput = $true
$processInfo.Arguments = "-v"
$processInfo.UseShellExecute = $false
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $processInfo
$process.Start() | Out-Null
$process.WaitForExit()
$processStOutput = $process.StandardOutput.ReadToEnd()
Here is another difference between both browsers. Chrome returns the version at the 2nd while MS Edge at the 4th place. It used to be the same for both vendors but changed in Spring 2022.
if ($path.Contains("msedgedriver")){
$driverVer = ($processStOutput -split " ")[3]
}
else {
$driverVer = ($processStOutput -split " ")[1]
}
For simplicity I created a function from the above code which is then called in the script:
$edgeDriverVersion = GetDriverVersion -path $edgeDriverPath
$chromeDriverVersion = GetDriverVersion -path $chromeDriverPath
Do you need the update?
You have enough information to check whether the upgrade (possibly downgrade as well) is needed. I decided to skip comparing the last minor version. It doesn’t make much difference. The benefit is that the script doesn’t need to download a new driver too often.
$v1 = $edgeVersion
$v2 = $edgeDriverVersion
$v1.Substring(0, $v1.LastIndexOf(".")) -ne $v2.Substring(0, $v2.LastIndexOf("."))
Do the same for Chrome.
Find the relevant driver – MS Edge
Finding the relevant driver is more difficult. There is no out-of-the-box thing or attribute that you can check. Microsoft has a website that you can visit interactively to download the driver version you need. I haven’t found an API to run against it. But you can get an entire HTML reply from the website and apply some tricks.
Firstly, split the content on each new line, then get only hyperlinks with “win64”
(of course, if your system is 64-bit) phrase:
$edgeDriverWebsite = "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/"
$edgeDriverAvailableVersions = (Invoke-RestMethod $edgeDriverWebsite) -split " " | where {$_ -like "*href=*win64*"} | % {$_.replace("href=","").replace('"','')}
As a result, you have a direct download link for the latest version, plus a few in the past:
Get the link for your version by looking for a matching number:
$downloadLink = $edgeDriverAvailableVersions | where {$_ -like "*/$edgeVersion/*"}
In case you run the script shortly after the new browser release, the corresponding web driver might be unavailable yet. Try to look for any that matches the major version. Usually, it will be good enough to work properly and don’t show warnings.
if (!$downloadLink){
$browserMajorVersion = $edgeVersion.Substring(0, $edgeVersion.IndexOf("."))
$downloadLink = $edgeDriverAvailableVersions | where {$_ -like "*/$browserMajorVersion*"}
}
In case there are more links with the same target, just take any. When you are looking for the major version, there are for sure multiple links:
if($downloadLink.Count -gt 1) {$downloadLink = $downloadLink[0]}
Download driver – MS Edge
Now you have the direct link, it’s time to download the file.
Invoke-WebRequest $downloadLink -OutFile "edgeNewDriver.zip"
Because it’s a ZIP archive, extract it and overwrite the original driver.
Expand-Archive "edgeNewDriver.zip" -DestinationPath "edgeNewDriver\" -Force
Move-Item "edgeNewDriver/msedgedriver.exe" -Destination "$($webDriversPath)\msedgedriver.exe" -Force
In the end, clean up after yourself.
Remove-Item "edgeNewDriver.zip" -Force
Remove-Item "edgeNewDriver" -Recurse -Force
Find the relevant driver – Chrome
Chrome has two different places that you need. One to look for available versions and another to actually download the driver. I haven’t been able to successfully query the download page for the matching version. Instead, I made a workaround. It firstly figures out the available matching version and then builds a link for that specific version to download.
Firstly you need a few new variables:
$chromeDriverWebsite = https://chromedriver.chromium.org/downloads
$chromeDriverUrlBase = "https://chromedriver.storage.googleapis.com"
$chromeDriverUrlEnd = "chromedriver_win32.zip"
$chromeDriverAvailableVersions = (Invoke-RestMethod $chromeDriverWebsite) -split " " | where {$_ -like "*href=*?path=*"} | % {$_.replace("href=","").replace('"','')}
Then check if the version you need is available. If not, look just for the major version (as with MS Edge):
$versionLink = $chromeDriverAvailableVersions | where {$_ -like "*$chromeVersion/*"}
if (!$versionLink){
$browserMajorVersion = $browserVersion.Substring(0, $browserVersion.IndexOf("."))
$versionLink = $chromeDriverAvailableVersions | where {$_ -like "*$browserMajorVersion.*"}
}
There might be multiple links so just take the first one:
if ($versionLink.Count -gt 1){
$versionLink = $versionLink[0]
}
Download driver – Chrome
In the end, build the download link. To do it, get retrieve the version from the previous link and add it to the final URL this way:
$version = ($versionLink -split"=" | where {$_ -like "*.*.*.*/"}).Replace('/','')
$downloadLink = "$chromeDriverUrlBase/$version/$chromeDriverUrlEnd"
Download process is the same as with MS Edge:
Invoke-WebRequest $downloadLink -OutFile "chromeNewDriver.zip"
Expand-Archive "chromeNewDriver.zip" -DestinationPath "chromeNewDriver\" -Force
Move-Item "chromeNewDriver/chromedriver.exe" -Destination "$($webDriversPath)\chromedriver.exe" -Force
Remove-Item "chromeNewDriver.zip" -Force
Remove-Item "chromeNewDriver" -Recurse -Force
Summary
In this post, I described how to Automate the update of Selenium Web Driver with PowerShell. I hope it will be helpful for you. I encourage you to leave comments 🙂
Here is a link to a full code on GitHub: https://github.com/wiktormrowczynski/PowerShell/tree/main/Automate%20Update%20of%20Selenium%20Web%20Driver
- Use PowerShell to integrate OpenAI GPT with context menu - October 25, 2023
- Let OpenAI improve and correct your PowerShell code - October 11, 2023
- Create Web Link with PowerShell in Intune - September 27, 2023