1 #==============================================================================
2 # You may need to change the execution policy in order to run this script
3 # Run the following in powershell:
4 #
5 # Set-ExecutionPolicy RemoteSigned
6 #
7 #==============================================================================
8 #
9 #          FILE: dev_env.ps1
10 #
11 #   DESCRIPTION: Development Environment Installation for Windows
12 #
13 #          BUGS: https://github.com/saltstack/salt-windows-bootstrap/issues
14 #
15 #     COPYRIGHT: (c) 2012-2017 by the SaltStack Team, see AUTHORS.rst for more
16 #                details.
17 #
18 #       LICENSE: Apache 2.0
19 #  ORGANIZATION: SaltStack (saltstack.org)
20 #       CREATED: 03/10/2017
21 #==============================================================================
22 
23 # Load parameters
24 param(
25     [switch]$Silent,
26     [switch]$NoPipDependencies
27 )
28 
29 #==============================================================================
30 # Get the Directory of actual script
31 #==============================================================================
32 $script_path = dir "$($myInvocation.MyCommand.Definition)"
33 $script_path = $script_path.DirectoryName
34 
35 #==============================================================================
36 # Get the name of actual script
37 #==============================================================================
38 $script_name = $MyInvocation.MyCommand.Name
39 
40 Write-Output "================================================================="
41 Write-Output ""
42 Write-Output "               Development Environment Installation"
43 Write-Output ""
44 Write-Output "               - Installs All Salt Dependencies"
45 Write-Output "               - Detects 32/64 bit Architectures"
46 Write-Output ""
47 Write-Output "               To run silently add -Silent"
48 Write-Output "               eg: ${script_name} -Silent"
49 Write-Output ""
50 Write-Output "               To run skip installing pip dependencies add -NoPipDependencies"
51 Write-Output "               eg: ${script_name} -NoPipDependencies"
52 Write-Output ""
53 Write-Output "================================================================="
54 Write-Output ""
55 
56 #==============================================================================
57 # Import Modules
58 #==============================================================================
59 Import-Module $script_path\Modules\download-module.psm1
60 Import-Module $script_path\Modules\get-settings.psm1
61 Import-Module $script_path\Modules\uac-module.psm1
62 Import-Module $script_path\Modules\zip-module.psm1
63 Import-Module $script_path\Modules\start-process-and-test-exitcode.psm1
64 #==============================================================================
65 # Check for Elevated Privileges
66 #==============================================================================
67 If (!(Get-IsAdministrator)) {
68     If (Get-IsUacEnabled) {
69         # We are not running "as Administrator" - so relaunch as administrator
70         # Create a new process object that starts PowerShell
71         $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
72 
73         # Specify the current script path and name as a parameter
74         $newProcess.Arguments = $myInvocation.MyCommand.Definition
75 
76         # Specify the current working directory
77         $newProcess.WorkingDirectory = "$script_path"
78 
79         # Indicate that the process should be elevated
80         $newProcess.Verb = "runas";
81 
82         # Start the new process
83         [System.Diagnostics.Process]::Start($newProcess);
84 
85         # Exit from the current, unelevated, process
86         Exit
87     } Else {
88         Throw "You must be administrator to run this script"
89     }
90 }
91 
92 #------------------------------------------------------------------------------
93 # Load Settings
94 #------------------------------------------------------------------------------
95 $ini = Get-Settings
96 
97 #------------------------------------------------------------------------------
98 # Create Directories
99 #------------------------------------------------------------------------------
100 $p = New-Item $ini['Settings']['DownloadDir'] -ItemType Directory -Force
101 $p = New-Item "$($ini['Settings']['DownloadDir'])\64" -ItemType Directory -Force
102 $p = New-Item "$($ini['Settings']['DownloadDir'])\32" -ItemType Directory -Force
103 $p = New-Item $ini['Settings']['SaltDir'] -ItemType Directory -Force
104 
105 #------------------------------------------------------------------------------
106 # Determine Architecture (32 or 64 bit) and assign variables
107 #------------------------------------------------------------------------------
108 If ([System.IntPtr]::Size -ne 4) {
109     Write-Output "Detected 64bit Architecture..."
110 
111     $bitDLLs     = "64bitDLLs"
112     $bitPaths    = "64bitPaths"
113     $bitPrograms = "64bitPrograms"
114     $bitFolder   = "64"
115 } Else {
116     Write-Output "Detected 32bit Architecture"
117     $bitDLLs     = "32bitDLLs"
118     $bitPaths    = "32bitPaths"
119     $bitPrograms = "32bitPrograms"
120     $bitFolder   = "32"
121 }
122 
123 #------------------------------------------------------------------------------
124 # Check for installation of NSIS
125 #------------------------------------------------------------------------------
126 Write-Output " - Checking for NSIS installation . . ."
127 If (Test-Path "$($ini[$bitPaths]['NSISDir'])\NSIS.exe") {
128     # Found NSIS, do nothing
129     Write-Output " - NSIS Found . . ."
130 } Else {
131     # NSIS not found, install
132     Write-Output " - NSIS Not Found . . ."
133     Write-Output " - Downloading $($ini['Prerequisites']['NSIS']) . . ."
134     $file = "$($ini['Prerequisites']['NSIS'])"
135     $url  = "$($ini['Settings']['SaltRepo'])/$file"
136     $file = "$($ini['Settings']['DownloadDir'])\$file"
137     DownloadFileWithProgress $url $file
138 
139     # Install NSIS
140     Write-Output " - Installing $($ini['Prerequisites']['NSIS']) . . ."
141     $file = "$($ini['Settings']['DownloadDir'])\$($ini['Prerequisites']['NSIS'])"
142     $p    = Start-Process $file -ArgumentList '/S' -Wait -NoNewWindow -PassThru
143 }
144 
145 #------------------------------------------------------------------------------
146 # Check for installation of NSIS NxS Unzip Plug-in
147 #------------------------------------------------------------------------------
148 Write-Output " - Checking for NSIS NxS Unzip (ansi) Plug-in installation . . ."
149 If (Test-Path "$( $ini[$bitPaths]['NSISPluginsDirA'] )\nsisunz.dll") {
150     # Found NSIS NxS Unzip Plug-in, do nothing
151     Write-Output " - NSIS NxS Unzip Plugin (ansi) Found . . ."
152 } Else
153 {
154     # NSIS NxS Unzip Plug-in (ansi) not found, install
155     Write-Output " - NSIS NxS Unzip Plugin (ansi) Not Found . . ."
156     # Ansi Plugin
157     Write-Output " - Downloading $( $ini['Prerequisites']['NSISPluginUnzipA'] ) . . ."
158     $file = "$( $ini['Prerequisites']['NSISPluginUnzipA'] )"
159     $url  = "$( $ini['Settings']['SaltRepo'] )/$file"
160     $file = "$( $ini['Settings']['DownloadDir'] )\$file"
161     DownloadFileWithProgress $url $file
162 
163     # Extract Ansi Zip file
164     Write-Output " - Extracting . . ."
165     Expand-ZipFile $file $ini['Settings']['DownloadDir']
166 
167     # Copy dll to plugins directory
168     Write-Output " - Copying dll to plugins directory . . ."
169     Move-Item "$( $ini['Settings']['DownloadDir'] )\nsisunz\Release\nsisunz.dll" "$( $ini[$bitPaths]['NSISPluginsDirA'] )\nsisunz.dll" -Force
170 
171     # Remove temp files
172     Remove-Item "$( $ini['Settings']['DownloadDir'] )\nsisunz" -Force -Recurse
173     Remove-Item "$file" -Force
174 }
175 
176 Write-Output " - Checking for NSIS NxS Unzip (unicode) Plug-in installation . . ."
177 If (Test-Path "$( $ini[$bitPaths]['NSISPluginsDirU'] )\nsisunz.dll") {
178     # Found NSIS NxS Unzip Plug-in (unicode), do nothing
179     Write-Output " - NSIS NxS Unzip Plugin (unicode) Found . . ."
180 } Else {
181     # Unicode Plugin
182     Write-Output " - Downloading $( $ini['Prerequisites']['NSISPluginUnzipU'] ) . . ."
183     $file = "$( $ini['Prerequisites']['NSISPluginUnzipU'] )"
184     $url  = "$( $ini['Settings']['SaltRepo'] )/$file"
185     $file = "$( $ini['Settings']['DownloadDir'] )\$file"
186     DownloadFileWithProgress $url $file
187 
188     # Extract Unicode Zip file
189     Write-Output " - Extracting . . ."
190     Expand-ZipFile $file $ini['Settings']['DownloadDir']
191 
192     # Copy dll to plugins directory
193     Write-Output " - Copying dll to plugins directory . . ."
194     Move-Item "$( $ini['Settings']['DownloadDir'] )\NSISunzU\Plugin unicode\nsisunz.dll" "$( $ini[$bitPaths]['NSISPluginsDirU'] )\nsisunz.dll" -Force
195 
196     # Remove temp files
197     Remove-Item "$( $ini['Settings']['DownloadDir'] )\NSISunzU" -Force -Recurse
198     Remove-Item "$file" -Force
199 }
200 
201 #------------------------------------------------------------------------------
202 # Check for installation of EnVar Plugin for NSIS
203 #------------------------------------------------------------------------------
204 Write-Output " - Checking for EnVar Plugin of NSIS installation  . . ."
205 If ( (Test-Path "$($ini[$bitPaths]['NSISPluginsDirA'])\EnVar.dll") -and (Test-Path "$($ini[$bitPaths]['NSISPluginsDirU'])\EnVar.dll") ) {
206     # Found EnVar Plugin for NSIS, do nothing
207     Write-Output " - EnVar Plugin for NSIS Found . . ."
208 } Else {
209     # EnVar Plugin for NSIS not found, install
210     Write-Output " - EnVar Plugin for NSIS Not Found . . ."
211     Write-Output " - Downloading $($ini['Prerequisites']['NSISPluginEnVar']) . . ."
212     $file = "$($ini['Prerequisites']['NSISPluginEnVar'])"
213     $url  = "$($ini['Settings']['SaltRepo'])/$file"
214     $file = "$($ini['Settings']['DownloadDir'])\$file"
215     DownloadFileWithProgress $url $file
216 
217     # Extract Zip File
218     Write-Output " - Extracting . . ."
219     Expand-ZipFile $file "$($ini['Settings']['DownloadDir'])\nsisenvar"
220 
221     # Copy dlls to plugins directory (both ANSI and Unicode)
222     Write-Output " - Copying dlls to plugins directory . . ."
223     Move-Item "$( $ini['Settings']['DownloadDir'] )\nsisenvar\Plugins\x86-ansi\EnVar.dll" "$( $ini[$bitPaths]['NSISPluginsDirA'] )\EnVar.dll" -Force
224     Move-Item "$( $ini['Settings']['DownloadDir'] )\nsisenvar\Plugins\x86-unicode\EnVar.dll" "$( $ini[$bitPaths]['NSISPluginsDirU'] )\EnVar.dll" -Force
225 
226     # Remove temp files
227     Remove-Item "$( $ini['Settings']['DownloadDir'] )\nsisenvar" -Force -Recurse
228     Remove-Item "$file" -Force
229 }
230 
231 #------------------------------------------------------------------------------
232 # Check for installation of AccessControl Plugin for NSIS
233 #------------------------------------------------------------------------------
234 Write-Output " - Checking for AccessControl Plugin installation  . . ."
235 If ( (Test-Path "$($ini[$bitPaths]['NSISPluginsDirA'])\AccessControl.dll") -and (Test-Path "$($ini[$bitPaths]['NSISPluginsDirU'])\AccessControl.dll") ) {
236     # Found AccessControl Plugin, do nothing
237     Write-Output " - AccessControl Plugin Found . . ."
238 } Else {
239     # AccessControl Plugin not found, install
240     Write-Output " - AccessControl Plugin Not Found . . ."
241     Write-Output " - Downloading $($ini['Prerequisites']['NSISPluginAccessControl']) . . ."
242     $file = "$($ini['Prerequisites']['NSISPluginAccessControl'])"
243     $url  = "$($ini['Settings']['SaltRepo'])/$file"
244     $file = "$($ini['Settings']['DownloadDir'])\$file"
245     DownloadFileWithProgress $url $file
246 
247     # Extract Zip File
248     Write-Output " - Extracting . . ."
249     Expand-ZipFile $file "$($ini['Settings']['DownloadDir'])\nsisaccesscontrol"
250 
251     # Copy dlls to plugins directory (both ANSI and Unicode)
252     Write-Output " - Copying dlls to plugins directory . . ."
253     Move-Item "$( $ini['Settings']['DownloadDir'] )\nsisaccesscontrol\Plugins\i386-ansi\AccessControl.dll" "$( $ini[$bitPaths]['NSISPluginsDirA'] )\AccessControl.dll" -Force
254     Move-Item "$( $ini['Settings']['DownloadDir'] )\nsisaccesscontrol\Plugins\i386-unicode\AccessControl.dll" "$( $ini[$bitPaths]['NSISPluginsDirU'] )\AccessControl.dll" -Force
255 
256     # Remove temp files
257     Remove-Item "$( $ini['Settings']['DownloadDir'] )\nsisaccesscontrol" -Force -Recurse
258     Remove-Item "$file" -Force
259 }
260 
261 #------------------------------------------------------------------------------
262 # Check for installation of the MoveFileFolder Library for NSIS
263 #------------------------------------------------------------------------------
264 Write-Output " - Checking for MoveFileFolder Library installation . . ."
265 If ( Test-Path "$($ini[$bitPaths]['NSISDir'])\Include\MoveFileFolder.nsh" ) {
266     # Found MoveFileFolder Library for NSIS, do nothing
267     Write-Output " - MoveFileFolder Library for NSIS Found . . ."
268 } Else {
269     # MoveFileFolder Library for NSIS not found, install
270     Write-Output " - MoveFileFolder Library for NSIS Not Found . . ."
271     Write-Output " - Downloading $($ini['Prerequisites']['NSISLibMoveFileFolder']) . . ."
272     $file = "$($ini['Prerequisites']['NSISLibMoveFileFolder'])"
273     $url  = "$($ini['Settings']['SaltRepo'])/$file"
274     $file = "$($ini['Settings']['DownloadDir'])\$file"
275     DownloadFileWithProgress $url $file
276 
277     # Move libary to the include directory
278     Write-Output " - Copying library to include directory . . ."
279     Move-Item "$file" "$( $ini[$bitPaths]['NSISDir'] )\Include\MoveFileFolder.nsh" -Force
280 }
281 
282 #------------------------------------------------------------------------------
283 # Check for installation of Microsoft Visual Studio 2015 Build Tools
284 #------------------------------------------------------------------------------
285 Write-Output " - Checking for Microsoft Visual Studio 2015 Build Tools installation . . ."
286 If (Test-Path "$($ini[$bitPaths]['VS2015BuildToolsDir'])\cl.exe") {
287     # Found Microsoft Visual Studio 2015 Build Tools, do nothing
288     Write-Output " - Microsoft Visual Studio 2015 Build Tools Found . . ."
289 } Else {
290     # Microsoft Visual Studio 2015 Build Tools not found, install
291     Write-Output " - Microsoft Visual Studio 2015 Build Tools Not Found . . ."
292     Write-Output " - Downloading $($ini['Prerequisites']['VS2015BuildTools']) . . ."
293     $file = "$($ini['Prerequisites']['VS2015BuildTools'])"
294     $url  = "$($ini['Settings']['SaltRepo'])/$file"
295     $file = "$($ini['Settings']['DownloadDir'])\$file"
296     DownloadFileWithProgress $url $file
297 
298     # Extract Zip File
299     Write-Output " - Extracting . . ."
300     Expand-ZipFile $file "$($ini['Settings']['DownloadDir'])\vs2015buildtools"
301 
302     # Install Microsoft Visual C++ Build Tools
303     Write-Output " - Installing $($ini['Prerequisites']['VS2015BuildTools']) . . ."
304     $file = "$($ini['Settings']['DownloadDir'])\vs2015buildtools\install.bat"
305     $p    = Start-Process $file -Wait -NoNewWindow -PassThru
306 }
307 
308 #------------------------------------------------------------------------------
309 # Install Python
310 #------------------------------------------------------------------------------
311 Write-Output " - Checking for Python 3 installation . . ."
312 If (Test-Path "$($ini['Settings']['Python3Dir'])\python.exe") {
313     # Found Python 3, do nothing
314     Write-Output " - Python 3 Found . . ."
315 } Else {
316     Write-Output " - Downloading $($ini[$bitPrograms]['Python3']) . . ."
317     $file = "$($ini[$bitPrograms]['Python3'])"
318     $url  = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
319     $file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
320     DownloadFileWithProgress $url $file
321 
322     Write-Output " - $script_name :: Installing $($ini[$bitPrograms]['Python3']) . . ."
323     $p    = Start-Process $file -ArgumentList "/Quiet InstallAllUsers=1 TargetDir=`"$($ini['Settings']['Python3Dir'])`" Include_doc=0 Include_tcltk=0 Include_test=0 Include_launcher=1 PrependPath=1 Shortcuts=0" -Wait -NoNewWindow -PassThru
324 }
325 
326 #------------------------------------------------------------------------------
327 # Install VCRedist
328 #------------------------------------------------------------------------------
329 If (Test-Path "$($ini[$bitPrograms]['VCRedistReg'])") {
330     # Found VCRedist 2013, do nothing
331     Write-Output " - VCRedist 2013 Found . . ."
332 } Else {
333     Write-Output " - Downloading $($ini[$bitPrograms]['VCRedist']) . . ."
334     $file = "$($ini[$bitPrograms]['VCRedist'])"
335     $url  = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
336     $file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$file"
337     DownloadFileWithProgress $url $file
338 
339     Write-Output " - $script_name :: Installing $($ini[$bitPrograms]['VCRedist']) . . ."
340     $p    = Start-Process $file -ArgumentList "/install /quiet /norestart" -Wait -NoNewWindow -PassThru
341 }
342 
343 #------------------------------------------------------------------------------
344 # Update Environment Variables
345 #------------------------------------------------------------------------------
346 Write-Output " - Updating Environment Variables . . ."
347 $Path = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path
348 If (!($Path.ToLower().Contains("$($ini['Settings']['Scripts3Dir'])".ToLower()))) {
349     $newPath  = "$($ini['Settings']['Scripts3Dir']);$Path"
350     Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath
351     $env:Path = $newPath
352 }
353 
354 #==============================================================================
355 # Update PIP and SetupTools
356 #==============================================================================
357 Write-Output " ----------------------------------------------------------------"
358 Write-Output " - $script_name :: Updating PIP, SetupTools, and Wheel . . ."
359 Write-Output " ----------------------------------------------------------------"
360 Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -U pip setuptools wheel" "update pip"
361 
362 
363 #==============================================================================
364 # Install pypi resources using pip
365 #==============================================================================
366 If ($NoPipDependencies -eq $false) {
367   Write-Output " ----------------------------------------------------------------"
368   Write-Output " - $script_name :: Installing pypi resources using pip . . ."
369   Write-Output " ----------------------------------------------------------------"
370   Start_Process_and_test_exitcode "cmd" "/c $($ini['Settings']['Python3Dir'])\python.exe -m pip --disable-pip-version-check --no-cache-dir install -r $($ini['Settings']['SrcDir'])\requirements\static\pkg\py$($ini['Settings']['PyVerMajor']).$($ini['Settings']['PyVerMinor'])\windows.txt" "pip install"
371 }
372 
373 If (Test-Path "$($ini['Settings']['SitePkgs3Dir'])\pywin32_system32" -PathType Container )
374 {
375     #==============================================================================
376     # Cleaning Up PyWin32
377     #==============================================================================
378     Write-Output " ----------------------------------------------------------------"
379     Write-Output " - $script_name :: Cleaning Up PyWin32 . . ."
380     Write-Output " ----------------------------------------------------------------"
381 
382     # Move DLL's to Python Root
383     # The dlls have to be in Python directory and the site-packages\win32 directory
384     Write-Output " - $script_name :: Moving PyWin32 DLLs . . ."
385     Copy-Item "$( $ini['Settings']['SitePkgs3Dir'] )\pywin32_system32\*.dll" "$( $ini['Settings']['Python3Dir'] )" -Force
386     Move-Item "$( $ini['Settings']['SitePkgs3Dir'] )\pywin32_system32\*.dll" "$( $ini['Settings']['SitePkgs3Dir'] )\win32" -Force
387 
388     # Create gen_py directory
389     Write-Output " - $script_name :: Creating gen_py Directory . . ."
390     New-Item -Path "$( $ini['Settings']['SitePkgs3Dir'] )\win32com\gen_py" -ItemType Directory -Force | Out-Null
391 
392     # Remove pywin32_system32 directory
393     Write-Output " - $script_name :: Removing pywin32_system32 Directory . . ."
394     Remove-Item "$( $ini['Settings']['SitePkgs3Dir'] )\pywin32_system32"
395 
396     # Remove PyWin32 PostInstall and testall Scripts
397     Write-Output " - $script_name :: Removing PyWin32 scripts . . ."
398     Remove-Item "$( $ini['Settings']['Scripts3Dir'] )\pywin32_*" -Force -Recurse
399 }
400 
401 #==============================================================================
402 # Copy DLLs to Python Directory
403 #==============================================================================
404 Write-Output " ----------------------------------------------------------------"
405 Write-Output "   - $script_name :: Copying DLLs . . ."
406 Write-Output " ----------------------------------------------------------------"
407 # Architecture Specific DLL's
408 ForEach($key in $ini[$bitDLLs].Keys) {
409     Write-Output "   - $key . . ."
410     $file = "$($ini[$bitDLLs][$key])"
411     $url  = "$($ini['Settings']['SaltRepo'])/$bitFolder/$file"
412     $file = "$($ini['Settings']['DownloadDir'])\$bitFolder\$($file.Split("/")[-1])"
413     DownloadFileWithProgress $url $file
414     Copy-Item $file -destination $($ini['Settings']['Python3Dir'])
415 }
416 
417 #------------------------------------------------------------------------------
418 # Script complete
419 #------------------------------------------------------------------------------
420 Write-Output "================================================================="
421 Write-Output " $script_name :: Salt Stack Dev Environment Script Complete"
422 Write-Output "================================================================="
423 Write-Output ""
424 
425 If (-Not $Silent) {
426     Write-Output "Press any key to continue ..."
427     $p = $HOST.UI.RawUI.Flushinputbuffer()
428     $p = $HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
429 }
430 
431 #------------------------------------------------------------------------------
432 # Remove the temporary download directory
433 #------------------------------------------------------------------------------
434 Write-Output " ----------------------------------------------------------------"
435 Write-Output " - $script_name :: Cleaning up downloaded files"
436 Write-Output " ----------------------------------------------------------------"
437 Write-Output ""
438 Remove-Item $($ini['Settings']['DownloadDir']) -Force -Recurse
439