Automate update of Selenium Web Driver (PowerShell)

Warning - Selenium Web Driver is outdated

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…”.

Automate update of Selenium Web Driver with PowerShell when you see this error!

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:

Warning - Selenium Web Driver is outdated

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:

Browser;s 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.

Missing exe version in Chrome's web driver

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:

List of MS Edge Selenium Web Drivers available for download

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

Wiktor Mrówczyński

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top