blob: 2f51d23e50fbccdcc3ac704c26191383043d232c [file] [log] [blame]
Ales Komarek1b373112017-08-08 08:48:56 +02001<#
2.SYNOPSIS
3 A simple Powershell script to download and install a salt minion on windows.
4
5.DESCRIPTION
6 The script will download the official salt package from saltstack. It will
7 install a specific package version and accept parameters for the master and
8 minion ids. Finally, it can stop and set the windows service to "manual" for
9 local testing.
10
11.EXAMPLE
12 ./bootstrap-salt.ps1
13 Runs without any parameters. Uses all the default values/settings.
14
15.EXAMPLE
16 ./bootstrap-salt.ps1 -version 2015.4.1-3
17 Specifies a particular version of the installer.
18
19.EXAMPLE
20 ./bootstrap-salt.ps1 -runservice false
21 Specifies the salt-minion service to stop and be set to manual. Useful for
22 testing locally from the command line with the --local switch
23
24.EXAMPLE
25 ./bootstrap-salt.ps1 -minion minion-box -master master-box
26 Specifies the minion and master ids in the minion config. Defaults to the
27 installer values of host name for the minion id and "salt" for the master.
28
29.EXAMPLE
30 ./bootstrap-salt.ps1 -minion minion-box -master master-box -version 2015.5.2 -runservice false
31 Specifies all the optional parameters in no particular order.
32
33.PARAMETER version
34 Default version defined in this script.
35
36.PARAMETER runservice
37 Boolean flag to start or stop the minion service. True will start the minion
38 service. False will stop the minion service and set it to "manual". The
39 installer starts it by default.
40
41.PARAMETER minion
42 Name of the minion being installed on this host. Installer defaults to the
43 host name.
44
45.PARAMETER master
46 Name or IP of the master server. Installer defaults to "salt".
47
48.PARAMETER repourl
49 URL to the windows packages. Default is "https://repo.saltstack.com/windows"
50
51.NOTES
52 All of the parameters are optional. The default should be the latest
53 version. The architecture is dynamically determined by the script.
54
55.LINK
56 Bootstrap GitHub Project (script home) - https://github.com/saltstack/salt-windows-bootstrap
57 Original Vagrant Provisioner Project -https://github.com/saltstack/salty-vagrant
58 Vagrant Project (utilizes this script) - https://github.com/mitchellh/vagrant
59 SaltStack Download Location - https://repo.saltstack.com/windows/
60#>
61
62#===============================================================================
63# Commandlet Binding
64#===============================================================================
65[CmdletBinding()]
66Param(
67 [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
68 # Doesn't support versions prior to "YYYY.M.R-B"
69 [ValidatePattern('^201\d\.\d{1,2}\.\d{1,2}(\-\d{1})?|(rc\d)$')]
70 [string]$version = '',
71
72 [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
73 [ValidateSet("true","false")]
74 [string]$runservice = "true",
75
76 [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
77 [string]$minion = "not-specified",
78
79 [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
80 [string]$master = "not-specified",
81
82 [Parameter(Mandatory=$false,ValueFromPipeline=$true)]
83 [string]$repourl= "https://repo.saltstack.com/windows"
84)
85
86#===============================================================================
87# Script Functions
88#===============================================================================
89function Get-IsAdministrator
90{
91 $Identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
92 $Principal = New-Object System.Security.Principal.WindowsPrincipal($Identity)
93 $Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
94}
95
96function Get-IsUacEnabled
97{
98 (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System).EnableLua -ne 0
99}
100
101#===============================================================================
102# Check for Elevated Privileges
103#===============================================================================
104If (!(Get-IsAdministrator)) {
105 If (Get-IsUacEnabled) {
106 # We are not running "as Administrator" - so relaunch as administrator
107 # Create a new process object that starts PowerShell
108 $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
109
110 # Specify the current script path and name as a parameter`
111 $parameters = ""
112 If($minion -ne "not-specified") {$parameters = "-minion $minion"}
113 If($master -ne "not-specified") {$parameters = "$parameters -master $master"}
114 If($runservice -eq $false) {$parameters = "$parameters -runservice false"}
115 If($version -ne '') {$parameters = "$parameters -version $version"}
116 $newProcess.Arguments = $myInvocation.MyCommand.Definition, $parameters
117
118 # Specify the current working directory
119 $newProcess.WorkingDirectory = "$script_path"
120
121 # Indicate that the process should be elevated
122 $newProcess.Verb = "runas";
123
124 # Start the new process
125 [System.Diagnostics.Process]::Start($newProcess);
126
127 # Exit from the current, unelevated, process
128 Exit
129 }
130 Else {
131 Throw "You must be administrator to run this script"
132 }
133}
134
135#===============================================================================
136# Verify Parameters
137#===============================================================================
138Write-Verbose "Parameters passed in:"
139Write-Verbose "version: $version"
140Write-Verbose "runservice: $runservice"
141Write-Verbose "master: $master"
142Write-Verbose "minion: $minion"
143Write-Verbose "repourl: $repourl"
144
145If ($runservice.ToLower() -eq "true") {
146 Write-Verbose "Windows service will be set to run"
147 [bool]$runservice = $True
148}
149ElseIf ($runservice.ToLower() -eq "false") {
150 Write-Verbose "Windows service will be stopped and set to manual"
151 [bool]$runservice = $False
152}
153Else {
154 # Param passed in wasn't clear so defaulting to true.
155 Write-Verbose "Windows service defaulting to run automatically"
156 [bool]$runservice = $True
157}
158
159#===============================================================================
160# Ensure Directories are present, copy Vagrant Configs if found
161#===============================================================================
162# Create C:\tmp\
163New-Item C:\tmp\ -ItemType directory -Force | Out-Null
164
165# Copy Vagrant Files to their proper location. Vagrant files will be placed
166# in C:\tmp
167# Check if minion keys have been uploaded, copy to correct location
168If (Test-Path C:\tmp\minion.pem) {
169 New-Item C:\salt\conf\pki\minion\ -ItemType Directory -Force | Out-Null
170 # Copy minion keys & config to correct location
171 cp C:\tmp\minion.pem C:\salt\conf\pki\minion\
172 cp C:\tmp\minion.pub C:\salt\conf\pki\minion\
173}
174
175# Check if minion config has been uploaded
176# This should be done before the installer is run so that it can be updated with
177# id: and master: settings when the installer runs
178If (Test-Path C:\tmp\minion) {
179 New-Item C:\salt\conf\ -ItemType Directory -Force | Out-Null
180 Copy-Item -Path C:\tmp\minion -Destination C:\salt\conf\ -Force | Out-Null
181}
182
183#===============================================================================
184# Detect architecture
185#===============================================================================
186If ([IntPtr]::Size -eq 4) {
187 $arch = "x86"
188}
189Else {
190 $arch = "AMD64"
191}
192
193#===============================================================================
194# Figure out the latest version if no version is passed
195#===============================================================================
196# If version isn't supplied, use latest.
197If (!$version) {
198 # Find latest version of Salt Minion
199 $repo = Invoke-Restmethod "$repourl"
200 $regex = "<\s*a\s*[^>]*?href\s*=\s*[`"']*([^`"'>]+)[^>]*?>"
201 $returnMatches = New-Object System.Collections.ArrayList
202 $resultingMatches = [Regex]::Matches($repo, $regex, "IgnoreCase")
203 foreach($match in $resultingMatches) {
204 $cleanedMatch = $match.Groups[1].Value.Trim()
205 [void] $returnMatches.Add($cleanedMatch)
206 }
207 If ($arch -eq 'x86') {
208 $returnMatches = $returnMatches | Where {$_ -like "Salt-Minion*x86-Setup.exe"}
209 }
210 Else {
211 $returnMatches = $returnMatches | Where {$_ -like "Salt-Minion*AMD64-Setup.exe"}
212 }
213
214 $version = $(($returnMatches | Sort-Object -Descending)[0]).Split(("n-","-A","-x"),([System.StringSplitOptions]::RemoveEmptyEntries))[1]
215}
216
217#===============================================================================
218# Download minion setup file
219#===============================================================================
220$saltExe = "Salt-Minion-$version-$arch-Setup.exe"
221Write-Output "Downloading Salt minion installer $saltExe"
222$webclient = New-Object System.Net.WebClient
223$url = "$repourl/$saltExe"
224$file = "C:\Windows\Temp\$saltExe"
225$webclient.DownloadFile($url, $file)
226
227#===============================================================================
228# Set the parameters for the installer
229#===============================================================================
230# Unless specified, use the installer defaults
231# - id: <hostname>
232# - master: salt
233# - Start the service
234$parameters = ""
235If($minion -ne "not-specified") {$parameters = "/minion-name=$minion"}
236If($master -ne "not-specified") {$parameters = "$parameters /master=$master"}
237If($runservice -eq $false) {$parameters = "$parameters /start-service=0"}
238
239#===============================================================================
240# Install minion silently
241#===============================================================================
242#Wait for process to exit before continuing.
243Write-Output "Installing Salt minion"
244Start-Process C:\Windows\Temp\$saltExe -ArgumentList "/S $parameters" -Wait -NoNewWindow -PassThru | Out-Null
245
246#===============================================================================
247# Configure the minion service
248#===============================================================================
249# Wait for salt-minion service to be registered before trying to start it
250$service = Get-Service salt-minion -ErrorAction SilentlyContinue
251While (!$service) {
252 Start-Sleep -s 2
253 $service = Get-Service salt-minion -ErrorAction SilentlyContinue
254}
255
256If($runservice) {
257 # Start service
258 Start-Service -Name "salt-minion" -ErrorAction SilentlyContinue
259
260 # Check if service is started, otherwise retry starting the
261 # service 4 times.
262 $try = 0
263 While (($service.Status -ne "Running") -and ($try -ne 4)) {
264 Start-Service -Name "salt-minion" -ErrorAction SilentlyContinue
265 $service = Get-Service salt-minion -ErrorAction SilentlyContinue
266 Start-Sleep -s 2
267 $try += 1
268 }
269
270 # If the salt-minion service is still not running, something probably
271 # went wrong and user intervention is required - report failure.
272 If ($service.Status -eq "Stopped") {
273 Write-Output -NoNewline "Failed to start salt minion"
274 exit 1
275 }
276}
277Else {
278 Write-Output -NoNewline "Stopping salt minion and setting it to 'Manual'"
279 Set-Service "salt-minion" -StartupType "Manual"
280 Stop-Service "salt-minion"
281}
282
283#===============================================================================
284# Script Complete
285#===============================================================================
286Write-Output "Salt minion successfully installed"