Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vavavr00m/c74f2039a9b97a0003eb4e1b694a05f9 to your computer and use it in GitHub Desktop.
Save vavavr00m/c74f2039a9b97a0003eb4e1b694a05f9 to your computer and use it in GitHub Desktop.
PowerShell script to download major browser WebDriver drivers for Selenium.
[Net.ServicePointManager]::SecurityProtocol = "Ssl3, Tls, Tls11, Tls12";
$currentDir = (Get-Item -Path "./").FullName;
$driversDirName = Join-Path $currentDir ".drivers";
$isWindows = [System.Boolean](Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction SilentlyContinue);
$webClient = New-Object System.Net.WebClient;
function Get-ChromeInstalledVersion {
$chromeRegistryKey = "HKCU:Software\Google\Chrome\BLBeacon"
try {
# Try to get the registry property for Chrome version
$global:latest_chrome = (Get-ItemProperty -Path $chromeRegistryKey -ErrorAction Stop).version
# Output the result
if (-not [string]::IsNullOrWhiteSpace($global:latest_chrome)) {
Write-Host "Chrome installed version: $global:latest_chrome"
} else {
Write-Error "Failed to retrieve a valid version."
$global:latest_chrome = $null
}
} catch {
Write-Error "Failed to retrieve Chrome version: $_"
$global:latest_chrome = $null
}
}
function Get-ChromeDriverLatestVersion {
try {
$jsonUrl = "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json"
$response = Invoke-RestMethod -Uri $jsonUrl -UseBasicParsing
$global:latest_chromedriver = $response.channels.stable.version
# Output the result
if (-not [string]::IsNullOrWhiteSpace($global:latest_chrome)) {
Write-Host "Latest ChromeDriver version: $global:latest_chromedriver"
} else {
Write-Error "Failed to retrieve a valid version."
$global:latest_chromedriver = $null
}
} catch {
Write-Error "Failed to get latest stable ChromeDriver version: $_"
$global:latest_chromedriver = $null
}
}
function Get-GeckoDriverLatestVersion {
param ()
$url = "https://api.github.com/repos/mozilla/geckodriver/releases/latest"
try {
$response = Invoke-RestMethod -Uri $url -UseBasicParsing
$global:latest_geckodriver = $response.tag_name
# Output the result
if (-not [string]::IsNullOrWhiteSpace($global:latest_geckodriver)) {
Write-Host "Latest GeckoDriver version: $global:latest_geckodriver"
} else {
Write-Error "Failed to retrieve a valid version."
$global:latest_geckodriver = $null
}
} catch {
Write-Error "Failed to retrieve latest Geckodriver version: $_"
$global:latest_geckodriver = $null
}
}
Function Clean-NormalizeVersion {
param (
[string]$versionString
)
# Remove unwanted BOM or special characters (like "ÿþ") and any spaces
$cleanedVersion = $versionString -replace '[^\d\.]', '' # Only keep digits and periods
# Normalize multiple spaces (if any) between version numbers (though spaces should be mostly removed)
$normalizedVersion = $cleanedVersion -replace '\s+', '.' # Replace any internal spaces with dots
# Trim leading/trailing spaces
$normalizedVersion = $normalizedVersion.Trim()
# Return the cleaned and normalized version
return $normalizedVersion
}
Function Get-MSEdgeDriverLatestVersion {
param ()
$url = "https://msedgedriver.azureedge.net/LATEST_STABLE"
try {
# Retrieve the latest stable version from the URL
$latestVersion = Invoke-RestMethod -Uri $url
# Clean and normalize the retrieved version string
$global:latest_msedge = Clean-NormalizeVersion -versionString $latestVersion
# Ensure the version is cleaned and output the result
if (-not [string]::IsNullOrWhiteSpace($global:latest_msedge)) {
Write-Host "Latest MSEdgeDriver version: $global:latest_msedge"
} else {
Write-Error "Failed to retrieve a valid version."
$global:latest_msedge = $null
}
} catch {
Write-Error "Failed to retrieve the latest MSEdgeDriver version: $_"
$global:latest_msedge = $null
}
}
function Get-IEDriverServerLatestVersion {
param (
[string]$RepoApiUrl = "https://api.github.com/repos/SeleniumHQ/selenium/releases",
[string]$AssetPattern = "^IEDriverServer_Win32_(?<version>[\d\.]+)\.zip$"
)
$headers = @{ 'User-Agent' = 'PowerShell' }
$global:latest_iedriver = $null
try {
$releases = Invoke-RestMethod -Uri $RepoApiUrl -Headers $headers
foreach ($release in $releases) {
foreach ($asset in $release.assets) {
if ($asset.name -match $AssetPattern) {
$version = $Matches['version']
$global:latest_iedriver = $version
$result = [PSCustomObject]@{
Name = $asset.name
Version = $version
Url = $asset.browser_download_url
PublishedAt = $release.published_at
}
Write-Host "Latest IEDriverServer version: $global:latest_iedriver"
return $result | Out-Null; return $result
}
}
}
Write-Warning "No matching IEDriver asset found."
return $null
} catch {
Write-Error "Error fetching IEDriver version: $_"
return $null
}
}
function Ensure-Driver-Updates($browserName, $exeName, $download, $zipName) {
$localExeName = Join-Path $driversDirName $exeName;
if (Test-Path $localExeName) {
Write-Host "${browserName}: driver already located at $localExeName." -f DarkGray
Remove-Item $localExeName -Force
if (-not (Test-Path $localExeName)) {
Write-Host "${browserName}: existing driver deleted." -f DarkGray
} else {
Write-Warning "${browserName}: failed to delete $localExeName!"
return
}
}
if ($zipName -eq $null) {
$localDownloadLocation = Join-Path $driversDirName $exeName;
} else {
$download = "$download/$zipName";
$localDownloadLocation = Join-Path $driversDirName $zipName;
}
Write-Host "${browserName}: downloading driver from $download." -f DarkGray;
$webClient.downloadFile($download, $localDownloadLocation);
if (!($zipName -eq $null)) {
Write-Host "${browserName}: extracting driver from $localDownloadLocation." -f DarkGray;
Expand-Archive -DestinationPath $driversDirName -Path $localDownloadLocation -Force;
Remove-Item $localDownloadLocation;
}
Write-Host "${browserName}: driver placed in $localExeName." -f DarkGray;
}
function Ensure-Chrome-Driver() {
Ensure-Driver-Updates "Chrome" "chromedriver.exe" "https://storage.googleapis.com/chrome-for-testing-public/$($global:latest_chromedriver)/win32" "chromedriver-win32.zip"
}
function Ensure-Gecko-Driver() {
Ensure-Driver-Updates "Gecko (Firefox)" "geckodriver.exe" "https://github.com/mozilla/geckodriver/releases/download/$($global:latest_geckodriver)" "geckodriver-$($global:latest_geckodriver)-win32.zip";
}
function Ensure-Internet-Explorer-Driver() {
if ($isWindows) {
Ensure-Driver-Updates "Internet Explorer" "IEDriverServer.exe" "https://github.com/SeleniumHQ/selenium/releases/download/selenium-$($global:latest_iedriver)" "IEDriverServer_Win32_$($global:latest_iedriver).zip"
}
}
function Ensure-MSEdge-Driver() {
if ($isWindows) {
Ensure-Driver-Updates "MSEdge" "msedgedriver.exe" "https://msedgedriver.azureedge.net/$($global:latest_msedge)" "edgedriver_win32.zip"
}
}
function Ensure-Edge-Driver() {
if ($isWindows) {
Ensure-Driver-Updates "Edge" "MicrosoftWebDriver.exe" "https://download.microsoft.com/download/F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD/MicrosoftWebDriver.exe"
}
}
function Flatten-DriversDirectory {
if (-not (Test-Path $driversDirName)) {
Write-Error "Path does not exist: $driversDirName"
return
}
$rootPath = (Get-Item $driversDirName).FullName
# Move only files not already in root, overwriting any duplicates
Get-ChildItem -Path $driversDirName -Recurse -File | Where-Object {
$_.Directory.FullName -ne $rootPath
} | ForEach-Object {
$destination = Join-Path -Path $rootPath -ChildPath $_.Name
if (Test-Path $destination) {
Remove-Item $destination -Force
}
Move-Item -Path $_.FullName -Destination $destination -Force
}
# Remove all empty directories
Get-ChildItem -Path $driversDirName -Recurse -Directory | Sort-Object FullName -Descending | ForEach-Object {
if (-not (Get-ChildItem -Path $_.FullName -Force)) {
Remove-Item -Path $_.FullName -Force
}
}
}
function Replace-SeleniumAssembliesExe {
$sourceDir = $driversDirName
$seleniumModulesPath = 'C:\Program Files\WindowsPowerShell\Modules\Selenium'
try {
if (-not (Test-Path $sourceDir)) {
throw "Source directory not found: $sourceDir"
}
if (-not (Test-Path $seleniumModulesPath)) {
throw "Selenium modules path not found: $seleniumModulesPath"
}
$exeSources = Get-ChildItem -Path $sourceDir -Filter *.exe -File -ErrorAction Stop
if ($exeSources.Count -eq 0) {
Write-Host "No .exe files found in $sourceDir" -ForegroundColor Yellow
return
}
$assembliesDirs = Get-ChildItem -Path "$seleniumModulesPath\*\assemblies" -Directory -ErrorAction Stop
if ($assembliesDirs.Count -eq 0) {
throw "No assemblies directories found under $seleniumModulesPath"
}
foreach ($dir in $assembliesDirs) {
try {
$existingExes = Get-ChildItem -Path $dir.FullName -Filter *.exe -File -ErrorAction Stop
foreach ($exe in $existingExes) {
try {
Remove-Item $exe.FullName -Force -ErrorAction Stop
Write-Host "Deleted: $($exe.FullName)" -ForegroundColor DarkGray
} catch {
Write-Host "ERROR:" -ForegroundColor Red -NoNewline
Write-Host " Failed to delete $($exe.FullName): $_"
}
}
} catch {
Write-Host "ERROR:" -ForegroundColor Red -NoNewline
Write-Host " Error while scanning $($dir.FullName) for existing .exe files: $_"
continue
}
foreach ($exe in $exeSources) {
$targetPath = Join-Path $dir.FullName $exe.Name
try {
Move-Item -Path $exe.FullName -Destination $targetPath -Force -ErrorAction Stop
Write-Host "Moved: $($exe.Name) → $($dir.FullName)" -ForegroundColor Cyan
} catch {
Write-Host "ERROR:" -ForegroundColor Red -NoNewline
Write-Host " Failed to move $($exe.Name) to $($dir.FullName): $_"
}
}
}
} catch {
Write-Host "ERROR:" -ForegroundColor Red -NoNewline
Write-Host " Fatal error in Replace-SeleniumAssembliesExe: $_"
}
}
function Ensure-Admin {
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Host "Elevation required. Relaunching as administrator..." -ForegroundColor Yellow
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = "powershell"
$psi.Arguments = "-ExecutionPolicy Bypass -File `"$PSCommandPath`""
$psi.Verb = "runas"
try {
[System.Diagnostics.Process]::Start($psi) | Out-Null
} catch {
Write-Host "User canceled the UAC prompt or access was denied." -ForegroundColor Red
}
exit
}
}
New-Item -Force -ItemType directory -Path $driversDirName > $null;
Ensure-Admin
Get-ChromeInstalledVersion
Get-ChromeDriverLatestVersion
Ensure-Chrome-Driver;
Get-IEDriverServerLatestVersion
Ensure-Internet-Explorer-Driver;
Get-GeckoDriverLatestVersion
Ensure-Gecko-Driver;
Get-MSEdgeDriverLatestVersion
Ensure-MSEdge-Driver;
Ensure-Edge-Driver;
Flatten-DriversDirectory
Replace-SeleniumAssembliesExe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment