4848[CmdletBinding ()]
4949param (
5050 [Parameter (Mandatory = $false , ValueFromPipeline = $True )]
51- [ValidatePattern (' ^(\d{4}(\.\d{1,2}){0,2}(\-\d{1})?)|(latest)$' , Options= 1 )]
5251 [Alias (" v" )]
5352 # The version of the Salt minion to install. Default is "latest" which will
5453 # install the latest version of Salt minion available. Doesn't support
@@ -153,34 +152,116 @@ function Get-MajorVersion {
153152 return ( $Version -split " \." )[0 ]
154153}
155154
156- function Convert-PSObjectToHashtable {
157- param (
158- [Parameter (ValueFromPipeline )]
159- $InputObject
160- )
161- if ($null -eq $InputObject ) { return $null }
162-
163- $is_enum = $InputObject -is [System.Collections.IEnumerable ]
164- $not_string = $InputObject -isnot [string ]
165- if ($is_enum -and $not_string ) {
166- $collection = @ (
167- foreach ($object in $InputObject ) {
168- Convert-PSObjectToHashtable $object
169- }
170- )
155+ function Get-AvailableVersions {
156+ # Get available versions from a remote location specified in the Source
157+ # Parameter
158+ Write-Verbose " Getting version information from the repo"
159+ Write-Verbose " base_url: $base_url "
160+
161+ $available_versions = [System.Collections.ArrayList ]@ ()
162+
163+ if ( $base_url.StartsWith (" http" ) -or $base_url.StartsWith (" ftp" ) ) {
164+ # We're dealing with HTTP, HTTPS, or FTP
165+ $response = Invoke-WebRequest " $base_url " - UseBasicParsing
166+ try {
167+ $response = Invoke-WebRequest " $base_url " - UseBasicParsing
168+ } catch {
169+ Write-Host " Failed to get version information" - ForegroundColor Red
170+ exit 1
171+ }
171172
172- Write-Host - NoEnumerate $collection
173- } elseif ($InputObject -is [PSObject ]) {
174- $hash = @ {}
173+ if ( $response.StatusCode -ne 200 ) {
174+ Write-Host " There was an error getting version information" - ForegroundColor Red
175+ Write-Host " Error: $ ( $response.StatusCode ) " - ForegroundColor red
176+ exit 1
177+ }
175178
176- foreach ($property in $InputObject.PSObject.Properties ) {
177- $hash [$property.Name ] = Convert-PSObjectToHashtable $property.Value
179+ $response.links | ForEach-Object {
180+ if ( $_.href.Length -gt 8 ) {
181+ Write-Host " The content at this location is unexpected" - ForegroundColor Red
182+ Write-Host " Should be a list of directories where the name is a version of Salt" - ForegroundColor Red
183+ exit 1
184+ }
178185 }
179186
180- $hash
187+ # Getting available versions from response
188+ Write-Verbose " Getting available versions from response"
189+ $filtered = $response.Links | Where-Object - Property href -NE " ../"
190+ $filtered | Select-Object - Property href | ForEach-Object {
191+ $available_versions.Add ($_.href.Trim (" /" )) | Out-Null
192+ }
193+ } elseif ( $base_url.StartsWith (" \\" ) -or $base_url -match " ^[A-Za-z]:\\" ) {
194+ # We're dealing with a local directory or SMB source
195+ Get-ChildItem - Path $base_url - Directory | ForEach-Object {
196+ $available_versions.Add ($_.Name ) | Out-Null
197+ }
181198 } else {
182- $InputObject
199+ Write-Host " Unknown Source Type" - ForegroundColor Red
200+ Write-Host " Must be one of HTTP, HTTPS, FTP, SMB Share, Local Directory" - ForegroundColor Red
201+ exit 1
202+ }
203+
204+ Write-Verbose " Available versions:"
205+ $available_versions | ForEach-Object {
206+ Write-Verbose " - $_ "
207+ }
208+
209+ # Get the latest version, should be the last in the list
210+ Write-Verbose " Getting latest available version"
211+ $latest = $available_versions | Select-Object - Last 1
212+ Write-Verbose " Latest available version: $latest "
213+
214+ # Create a versions table
215+ # This will have the latest version available, the latest version available
216+ # for each major version, and every version available. This makes the
217+ # version lookup logic easier. The contents of the versions table can be
218+ # found by running -Verbose
219+ Write-Verbose " Populating the versions table"
220+ $versions_table = [ordered ]@ {" latest" = $latest }
221+ $available_versions | ForEach-Object {
222+ $versions_table [$ (Get-MajorVersion $_ )] = $_
223+ $versions_table [$_.ToLower ()] = $_.ToLower ()
224+ }
225+
226+ Write-Verbose " Versions Table:"
227+ $versions_table | Sort-Object Name | Out-String | ForEach-Object {
228+ Write-Verbose " $_ "
229+ }
230+
231+ return $versions_table
232+ }
233+
234+ function Get-HashFromArtifactory {
235+ # This function uses the artifactory API to get the SHA265 Hash for the file
236+ # If Source is NOT artifactory, the sha will not be checked
237+ [CmdletBinding ()]
238+ param (
239+ [Parameter (Mandatory = $true )]
240+ [String ] $SaltVersion ,
241+
242+ [Parameter (Mandatory = $true )]
243+ [String ] $SaltFileName
244+ )
245+ if ( $api_url ) {
246+ $full_url = " $api_url /$SaltVersion /$SaltFileName "
247+ Write-Verbose " Querying Artifactory API for hash:"
248+ Write-Verbose $full_url
249+ try {
250+ $response = Invoke-RestMethod $full_url - UseBasicParsing
251+ return $response.checksums.sha256
252+ } catch {
253+ Write-Verbose " Artifactory API Not available or file not"
254+ Write-Verbose " available at specified location"
255+ Write-Verbose " Hash will not be checked"
256+ return " "
257+ }
258+ Write-Verbose " No hash found for this file: $SaltFileName "
259+ Write-Verbose " Hash will not be checked"
260+ return " "
183261 }
262+ Write-Verbose " No artifactory API defined"
263+ Write-Verbose " Hash will not be checked"
264+ return " "
184265}
185266
186267function Get-FileHash {
@@ -313,10 +394,8 @@ if ($majorVersion -lt "3006") {
313394# ===============================================================================
314395$ConfDir = " $RootDir \conf"
315396$PkiDir = " $ConfDir \pki\minion"
316- $RootDir = " $env: ProgramData \Salt Project\Salt"
317- $DfltUrl = " https://packages.broadcom.com/artifactory/saltproject-generic/windows/"
318- $ApiUrl = " https://packages.broadcom.com/artifactory/api/storage/saltproject-generic/windows"
319397
398+ $RootDir = " $env: ProgramData \Salt Project\Salt"
320399# Check for existing installation where RootDir is stored in the registry
321400$SaltRegKey = " HKLM:\SOFTWARE\Salt Project\Salt"
322401if (Test-Path - Path $SaltRegKey ) {
@@ -325,6 +404,18 @@ if (Test-Path -Path $SaltRegKey) {
325404 }
326405}
327406
407+ # Get repo and api URLs. An artifactory URL will have "artifactory" in it
408+ $domain , $target = $RepoUrl -split " /artifactory/"
409+ if ( $target ) {
410+ # Create $base_url and $api_url
411+ $base_url = " $domain /artifactory/$target "
412+ $api_url = " $domain /artifactory/api/storage/$target "
413+ } else {
414+ # This is a non-artifactory url, there is no api
415+ $base_url = $domain
416+ $api_url = " "
417+ }
418+
328419# ===============================================================================
329420# Verify Parameters
330421# ===============================================================================
@@ -335,8 +426,8 @@ Write-Verbose "version: $Version"
335426Write-Verbose " runservice: $RunService "
336427Write-Verbose " master: $Master "
337428Write-Verbose " minion: $Minion "
338- Write-Verbose " repourl: $RepoUrl "
339- Write-Verbose " apiurl: $ApiUrl "
429+ Write-Verbose " repourl: $base_url "
430+ Write-Verbose " apiurl: $api_url "
340431Write-Verbose " ConfDir: $ConfDir "
341432Write-Verbose " RootDir: $RootDir "
342433
@@ -393,98 +484,42 @@ if ( $ConfigureOnly ) {
393484# ===============================================================================
394485# Detect architecture
395486# ===============================================================================
396- if ([IntPtr ]::Size -eq 4 ) {
397- $arch = " x86"
398- } else {
399- $arch = " AMD64"
400- }
487+ if ([IntPtr ]::Size -eq 4 ) { $arch = " x86" } else { $arch = " AMD64" }
401488
402489# ===============================================================================
403490# Getting version information from the repo
404491# ===============================================================================
405- if ( $RepoUrl -eq $DfltUrl ) {
406- Write-Verbose " Getting version information from Artifactory"
407- $response = Invoke-WebRequest $ApiUrl - UseBasicParsing
408- # Convert the output to a powershell object
409- $psobj = $response.ToString () | ConvertFrom-Json
410-
411- # Filter the object for folders
412- $filtered = $psobj.children | Where-Object - Property folder -EQ $true
413-
414- # Get each uri and add it to the list of versions
415- $available_versions = [System.Collections.ArrayList ]@ ()
416- $filtered | Select-Object - Property uri | ForEach-Object {
417- $available_versions.Add ($_.uri.Trim (" /" )) | Out-Null
418- }
492+ $versions = Get-AvailableVersions
419493
420- # Create a versions table, similar to repo.json
421- # This will have the latest version available, the latest version available for
422- # each major version, and every version available. This makes the version
423- # lookup logic easier. You can view the contents of the versions table by
424- # passing the -Verbose command
425- $latest = $available_versions | Select-Object - Last 1
426- $versions_table = [ordered ]@ {" latest" = $latest }
427-
428- $available_versions | ForEach-Object {
429- $versions_table [$ (Get-MajorVersion $_ )] = $_
430- $versions_table [$_.ToLower ()] = $_.ToLower ()
431- }
432-
433- Write-Verbose " Available versions:"
434- $available_versions | ForEach-Object {
435- Write-Verbose " - $_ "
436- }
437- Write-Verbose " Versions Table:"
438- $versions_table | Sort-Object Name | Out-String | Write-Verbose
439-
440- # ===============================================================================
441- # Validate passed version
442- # ===============================================================================
443- if ( $versions_table.Contains ($Version.ToLower ()) ) {
444- $Version = $versions_table [$Version.ToLower ()]
445- } else {
446- Write-Host " Version $Version is not available" - ForegroundColor Red
447- Write-Host " Available versions are:" - ForegroundColor Yellow
448- $available_versions | ForEach-Object { Write-Host " - $_ " - ForegroundColor Yellow }
449- exit 1
450- }
451-
452- # ===============================================================================
453- # Get file url and sha256
454- # ===============================================================================
455- $saltFileName = " Salt-Minion-$Version -Py3-$arch -Setup.exe"
456- $response = Invoke-WebRequest " $ApiUrl /$Version /$saltFileName " - UseBasicParsing
457- $psobj = $response.ToString () | ConvertFrom-Json
458- $saltFileUrl = $psobj.downloadUri
459- $saltSha256 = $psobj.checksums.sha256
460-
461- if ( $saltFileName -and $saltVersion -and $saltSha256 ) {
462- Write-Verbose " Found Name, Version, and Sha"
463- } else {
464- # We will guess the name of the installer
465- Write-Verbose " Failed to get Name, Version, and Sha from Artifactory API"
466- Write-Verbose " We'll try to find the file in standard paths"
467- $saltFileName = " Salt-Minion-$Version -Py3-$arch -Setup.exe"
468- $saltVersion = $Version
469- }
494+ # ===============================================================================
495+ # Validate passed version
496+ # ===============================================================================
497+ Write-Verbose " Looking up version: $Version "
498+ if ( $versions.Contains ($Version.ToLower ()) ) {
499+ $Version = $versions [$Version.ToLower ()]
500+ Write-Verbose " Found version: $Version "
470501} else {
471- # If we're using a custom RepoUrl, we're going to assum that the binary is
472- # in the reoot of the RepoUrl/Version. We will not check the sha on custom
473- # repos
474- $saltFileName = " Salt-Minion-$Version -Py3-$arch -Setup.exe"
475- $saltFileUrl = " $RepoUrl /$Version /$saltFileName "
476- $saltVersion = $Version
477- $saltSha256 = " "
502+ Write-Host " Version $Version is not available" - ForegroundColor Red
503+ Write-Host " Available versions are:" - ForegroundColor Yellow
504+ $versions
505+ exit 1
478506}
479507
508+ # ===============================================================================
509+ # Get file url and sha256
510+ # ===============================================================================
511+ $saltFileName = " Salt-Minion-$Version -Py3-$arch -Setup.exe"
512+ $saltFileUrl = " $base_url /$Version /$saltFileName "
513+ $saltSha256 = Get-HashFromArtifactory - SaltVersion $Version - SaltFileName $saltFileName
514+
480515# ===============================================================================
481516# Download minion setup file
482517# ===============================================================================
483518Write-Host " ===============================================================================" - ForegroundColor Yellow
484519Write-Host " Bootstrapping Salt Minion" - ForegroundColor Green
485520Write-Host " - version: $Version "
486521Write-Host " - file name: $saltFileName "
487- Write-Host " - file url: $saltFileUrl "
522+ Write-Host " - file url : $saltFileUrl "
488523Write-Host " - file hash: $saltSha256 "
489524Write-Host " - master: $Master "
490525Write-Host " - minion id: $Minion "
@@ -498,16 +533,19 @@ Write-Verbose ""
498533Write-Verbose " Salt File URL: $saltFileUrl "
499534Write-Verbose " Local File: $localFile "
500535
501- if ( Test-Path - Path $localFile ) { Remove-Item - Path $localFile - Force}
502- Invoke-WebRequest - Uri $saltFileUrl - OutFile $localFile
536+ # Remove existing local file
537+ if ( Test-Path - Path $localFile ) { Remove-Item - Path $localFile - Force }
503538
539+ # Download the file
540+ Invoke-WebRequest - Uri $saltFileUrl - OutFile $localFile
504541if ( Test-Path - Path $localFile ) {
505542 Write-Host " Success" - ForegroundColor Green
506543} else {
507544 Write-Host " Failed" - ForegroundColor Red
508545 exit 1
509546}
510547
548+ # Compare the hash if there is a hash to compare
511549if ( $saltSha256 ) {
512550 $localSha256 = (Get-FileHash - Path $localFile - Algorithm SHA256).Hash
513551 Write-Host " Comparing Hash: " - NoNewline
@@ -546,13 +584,13 @@ $process = Start-Process $localFile `
546584 - NoNewWindow - PassThru
547585
548586# Sometimes the installer hangs... we'll wait 5 minutes and then kill it
549- Write-Verbose " "
550587Write-Verbose " Waiting for installer to finish"
551588$process | Wait-Process - Timeout 300 - ErrorAction SilentlyContinue
552589$process.Refresh ()
553590
554591if ( ! $process.HasExited ) {
555- Write-Host " Installer Timeout" - ForegroundColor Yellow
592+ Write-Verbose " Installer Timeout"
593+ Write-Host " "
556594 Write-Host " Killing hung installer: " - NoNewline
557595 $process | Stop-Process
558596 $process.Refresh ()
0 commit comments