backend/e2e/bin/webdriver.ps1 (view raw)
1<#
2Installs and starts Webdriver servers for Edge (New+Legacy) & IE on Windows 10.
3Installs and starts NGINX as reverse proxy for remote Webdriver connections.
4Installs and starts MJPEGServer and FFmpeg for screen recordings.
5Edits registry properties to configure Edge Legacy and IE.
6Updates Windows hosts file with custom entries.
7
8Copyright 2019, Sebastian Tschan
9https://blueimp.net
10
11Licensed under the MIT license:
12https://opensource.org/licenses/MIT
13
14Resources:
15https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
16https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver
17https://nginx.org/en/docs/windows.html
18#>
19
20[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
21 'PSUseShouldProcessForStateChangingFunctions', ''
22)]
23[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
24 'PSAvoidUsingPositionalParameters', ''
25)]
26param()
27
28$ErrorActionPreference = 'Stop' # Stop if a cmdlet fails
29
30$ffmpegOptions = @{
31 fps = '15'
32 quality = '2' # Value between 2 (best) and 31 (worst)
33}
34
35$versions = @{
36 nginx = '1.17.9'
37 IEDriver = '3.150.1'
38 ffmpeg = '4.2.2'
39 MJPEGServer = '1.2.0'
40}
41
42$downloads = @{
43 nginx = 'https://nginx.org/download/nginx-{0}.zip' -f $versions.nginx
44 msedgedriver = 'https://msedgedriver.azureedge.net/{0}/edgedriver_win64.zip'
45 # Using the 32bit IEDriverServer (64bit version has performance issues).
46 # The download URL contains the version number twice.
47 # Once as directory with the major.minor version and once in the file name
48 # with the full version string:
49 IEDriver = ('https://selenium-release.storage.googleapis.com/' +
50 '{0}/IEDriverServer_Win32_{1}.zip') `
51 -f ($versions.IEDriver.split('.')[0..1] -join '.'),$versions.IEDriver
52 ffmpeg = ('https://ffmpeg.zeranoe.com/builds/win64/static/' +
53 'ffmpeg-{0}-win64-static.zip') -f $versions.ffmpeg
54 MJPEGServer = ('https://github.com/blueimp/mjpeg-server/releases/download/' +
55 'v{0}/mjpeg-server-windows-amd64.zip') -f $versions.MJPEGServer
56}
57
58$ffmpegCommand = ('ffmpeg' +
59 ' -loglevel error' +
60 ' -probesize 32' +
61 ' -fpsprobesize 0' +
62 ' -analyzeduration 0' +
63 ' -fflags nobuffer' +
64 ' -f gdigrab' +
65 ' -r {0}' +
66 ' -i desktop' +
67 ' -f mpjpeg' +
68 ' -q {1}' +
69 ' -') -f $ffmpegOptions.fps,$ffmpegOptions.quality
70
71# NGINX configuration as reverse proxy for Edge WebDriver and IEDriverServer:
72$nginxConfig = '
73worker_processes 1;
74events {
75 worker_connections 1024;
76}
77http {
78 server {
79 listen 4445;
80 location / {
81 proxy_pass http://localhost:5555;
82 }
83 }
84 server {
85 listen 4446;
86 location / {
87 proxy_pass http://localhost:17556;
88 }
89 }
90}
91'
92
93# Relative install paths to add to the PATH environment variable:
94$installPaths = @('bin', 'nginx', 'ffmpeg\bin')
95
96# Runs the given command with Administrator privileges:
97function Invoke-AdminCommand {
98 param([String]$command, [String]$params, [String]$reason)
99 Clear-Host
100 'Requesting Administrator privileges {0}...' -f $reason
101 Start-Process $command $params -Verb RunAs -Wait
102}
103
104# Runs the given Powershell command with Administrator privileges:
105function Invoke-PowershellAdminCommand {
106 param([String]$command, [String]$reason)
107 $params = "-ExecutionPolicy ByPass -command $($command -replace '"','\"')"
108 Invoke-AdminCommand powershell $params $reason
109}
110
111# Sets a registry property.
112# Also creates the parent path if it does not exist:
113function Set-RegistryProperty {
114 param([String]$path, [String]$name, [String]$type, $value)
115 $prop = Get-ItemProperty $path $name -ErrorAction SilentlyContinue
116 if (!$prop) {
117 if (!(Test-Path $path)) {
118 # -Force option is required if the parent path does not exist:
119 New-Item $path -Force
120 }
121 New-ItemProperty $path $name -PropertyType $type -Value $value
122 } elseif ($prop.$name -ne $value) {
123 Set-ItemProperty $path -Name $name $value
124 }
125}
126
127# Edits HKEY_CURRENT_USER (HKCU) registry:
128function Edit-CurrentUserRegistry {
129 # Set the same Protected Mode for all Internet Zones by copying the property
130 # from zone 4 (Restricted Sites) of the default settings (HKLM) to zones 1-4
131 # of the user settings (HKCU):
132 #
133 # Zone | Setting
134 # ---- | ---------------------
135 # 0 | My Computer
136 # 1 | Local Intranet Zone
137 # 2 | Trusted sites Zone
138 # 3 | Internet Zone
139 # 4 | Restricted Sites Zone
140 #
141 $path = '\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones'
142 # 2500 is the property key for the Protected Mode setting:
143 $name = '2500'
144 foreach ($zone in @(1, 2, 3, 4)) {
145 Copy-ItemProperty "HKLM:$path\4" -Name $name "HKCU:$path\$zone"
146 }
147 # Enable the driver to maintain a connection to the instance of Internet
148 # Explorer it creates:
149 $path = 'HKCU:\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main' +
150 '\FeatureControl\FEATURE_BFCACHE'
151 Set-RegistryProperty $path iexplore.exe DWord 0
152 # Path to IE user settings:
153 $path = 'HKCU:\Software\Microsoft\Internet Explorer'
154 # Disable IE Compatibility View for Intranet Sites:
155 Set-RegistryProperty "$path\BrowserEmulation" IntranetCompatibilityMode `
156 DWord 0
157 # Disable "Preserve Favorites website data":
158 Set-RegistryProperty "$path\Privacy" UseAllowList DWord 0
159 # Clear IE browsing history on exit:
160 Set-RegistryProperty "$path\Privacy" ClearBrowsingHistoryOnExit DWord 1
161 # Disable the IE first run page:
162 Set-RegistryProperty "$path\Main" DisableFirstRunCustomize DWord 1
163 # Start IE with a blank page:
164 Set-RegistryProperty "$path\Main" 'Start Page' String 'about:blank'
165 # Open new tabs in IE with a blank page:
166 Set-RegistryProperty "$path\TabbedBrowsing" NewTabPageShow DWord 0
167 # Path to Microsoft Edge user settings:
168 $path = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows' +
169 '\CurrentVersion\AppContainer\Storage' +
170 '\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge'
171 # Clear Microsoft Edge browsing history on exit:
172 Set-RegistryProperty "$path\Privacy" ClearBrowsingHistoryOnExit DWord 1
173 # Disable the Microsoft Edge first run page:
174 Set-RegistryProperty "$path\Main" PreventFirstRunPage DWord 1
175 # Disable the Microsoft Edge default browser prompt:
176 Set-RegistryProperty "$path\Main" DisallowDefaultBrowserPrompt DWord 1
177 # Set tbe Microsoft Edge home page to the new tab page:
178 Set-RegistryProperty "$path\Main" HomeButtonPage String 'about:tabs'
179 # Open new tabs in Microsoft Edge with a blank page:
180 Set-RegistryProperty "$path\ServiceUI" NewTabPageDisplayOption DWord 2
181}
182
183# Overwrites the Windows hosts file with the file windows.hosts, if available:
184function Update-HostsFile {
185 $newHostsFile = "$(Get-Location)\windows.hosts"
186 if (Test-Path $newHostsFile) {
187 $hostsFile = "$env:windir\System32\drivers\etc\hosts"
188 if ((Get-FileHash $hostsFile).hash -ne (Get-FileHash $newHostsFile).hash) {
189 $command = 'Copy-Item "{0}" "{1}"' -f $newHostsFile,$hostsFile
190 Invoke-PowershellAdminCommand $command 'to overwrite the hosts file'
191 }
192 }
193}
194
195# Downloads and extracts a ZIP file provided as URL:
196function Invoke-ZipDownload {
197 param([String]$url)
198 $filename = [IO.Path]::GetRandomFileName() + '.zip'
199 Invoke-WebRequest $url -OutFile $filename
200 Expand-Archive $filename .
201 Remove-Item $filename
202}
203
204# Returns the Windows build number:
205function Get-WindowsBuildNumber {
206 (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' `
207 'CurrentBuild').CurrentBuild
208}
209
210# Returns the Edge version number:
211function Get-EdgeVersion {
212 $path = 'HKLM:\SOFTWARE\Wow6432node\Microsoft\Windows\CurrentVersion' +
213 '\Uninstall\Microsoft Edge'
214 Get-ItemProperty $path -ErrorAction SilentlyContinue |
215 ForEach-Object DisplayVersion
216}
217
218# Installs msedgedriver:
219function Install-EdgeDriver {
220 if (!(Test-Path bin\msedgedriver.exe)) {
221 $version = Get-EdgeVersion
222 if ($version) {
223 $url = $downloads.msedgedriver -f $version
224 New-Item bin -ItemType Directory -Force
225 Clear-Host
226 'Installing Microsoft Edge Driver ...'
227 Invoke-ZipDownload $url
228 Move-Item msedgedriver.exe bin
229 Remove-Item Driver_Notes -Recurse
230 }
231 }
232}
233
234# Installs MicrosoftWebDriver (for Edge Legacy) via "Windows Feature on Demand":
235function Install-MicrosoftWebDriver {
236 # Windows versions before build 17763 do not have MicrosoftWebDriver as
237 # "Windows Feature on Demand" and only support older Edge versions.
238 # See https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
239 if ((Get-WindowsBuildNumber) -lt 17763) { return }
240 if (!(Get-Command MicrosoftWebDriver -ErrorAction SilentlyContinue)) {
241 $capabilityName = 'Microsoft.WebDriver~~~~0.0.1.0'
242 Invoke-AdminCommand DISM `
243 "/Online /Add-Capability /CapabilityName:$capabilityName" `
244 'for Edge Legacy WebDriver installation'
245 }
246}
247
248# Installs IEDriverServer:
249function Install-IEDriverServer {
250 if (!(Test-Path bin\IEDriverServer.exe)) {
251 New-Item bin -ItemType Directory -Force
252 Clear-Host
253 'Installing IEDriverServer ...'
254 Invoke-ZipDownload $downloads.IEDriver
255 Move-Item IEDriverServer.exe bin
256 }
257}
258
259# Installs and configures nginx:
260function Install-NGINX {
261 if (!(Test-Path nginx)) {
262 Clear-Host
263 'Installing nginx ...'
264 Invoke-ZipDownload $downloads.nginx
265 Move-Item nginx-* nginx
266 $nginxConfig | Out-File nginx\conf\nginx.conf ASCII
267 }
268}
269
270# Installs ffmpeg:
271function Install-FFmpeg {
272 if (!(Test-Path ffmpeg)) {
273 Clear-Host
274 'Installing ffmpeg ...'
275 Invoke-ZipDownload $downloads.ffmpeg
276 Move-Item ffmpeg-* ffmpeg
277 }
278}
279
280# Installs MJPEGServer:
281function Install-MJPEGServer {
282 if (!(Test-Path bin\MJPEGServer.exe)) {
283 New-Item bin -ItemType Directory -Force
284 Clear-Host
285 'Installing MJPEGServer ...'
286 Invoke-ZipDownload $downloads.MJPEGServer
287 Move-Item MJPEGServer.exe bin
288 }
289}
290
291# Updates the PATH environment variable with the installed program paths:
292function Update-Path {
293 $currentPath = $(Get-Location)
294 $originalEnvPath = $env:Path
295 $pathComponents = $originalEnvPath.TrimEnd(';') -split ';'
296 foreach ($path in $installPaths) {
297 if ($pathComponents -notcontains "$currentPath\$path") {
298 $pathComponents += "$currentPath\$path"
299 }
300 }
301 $env:Path = ($pathComponents -join ';') + ';'
302 if ($env:Path -ne $originalEnvPath) {
303 [Environment]::SetEnvironmentVariable(
304 'Path',
305 $env:Path,
306 [System.EnvironmentVariableTarget]::User
307 )
308 }
309}
310
311# Starts nginx, IEDriverServer and MicrosoftWebDriver (if installed).
312# Waits for IEDriverServer to close, then sends nginx the stop signal:
313function Start-Service {
314 Clear-Host
315 '========================================================'
316 'IMPORTANT: Do not close this window manually.'
317 'It will close automatically when MJPEGServer is stopped.'
318 '========================================================'
319 'Starting servers ...'
320 if (Get-Command msedgedriver -ErrorAction SilentlyContinue) {
321 Start-Process msedgedriver '--port=4444 --whitelisted-ips='
322 }
323 if (Get-Command MicrosoftWebDriver -ErrorAction SilentlyContinue) {
324 Start-Process MicrosoftWebDriver
325 }
326 Start-Process IEDriverServer
327 Start-Process nginx -WorkingDirectory nginx
328 Start-Process MJPEGServer $ffmpegCommand -Wait
329 Start-Process nginx '-s stop' -WorkingDirectory nginx
330}
331
332Edit-CurrentUserRegistry
333Update-HostsFile
334Install-MicrosoftWebDriver
335Install-EdgeDriver
336Install-IEDriverServer
337Install-NGINX
338Install-FFmpeg
339Install-MJPEGServer
340Update-Path
341Start-Service