CI/Install.ps1
<#
.SYNOPSIS Installs module from Git clone or directly from GitHub. File must not have BOM for GitHub deploy to work. #> [CmdletBinding(DefaultParameterSetName = 'Default')] param( # Path to install the module to, if not provided -Scope used. [Parameter(Mandatory, ParameterSetName = 'ModulePath')] [ValidateNotNullOrEmpty()] [String]$ModulePath, # Path to install the module to, PSModulePath "CurrentUser" or "AllUsers", if not provided "CurrentUser" used. [Parameter(Mandatory, ParameterSetName = 'Scope')] [ValidateSet('CurrentUser', 'AllUsers')] [string] $Scope = 'CurrentUser', # Get module from GitHub instead of local Git clone, for example "https://raw.githubusercontent.com/ili101/Module.Template/master/Install.ps1" [ValidateNotNullOrEmpty()] [Uri]$FromGitHub ) # Set Files and Folders patterns to Include/Exclude. $IncludeFiles = @( 'EPPlus.dll', '*.psd1', '*.psm1', '*.ps1' 'Charting', 'en-US', 'Examples', 'Public', 'Private', 'images', 'InferData', 'InternalFunctions', 'Pivot', 'spikes', 'Testimonials', 'README.md', 'LICENSE.txt' ) $ExcludeFiles = @( 'Install.ps1', 'InstallModule.ps1', 'PublishToGallery.PS1' ) function Invoke-MultiLike { [alias("LikeAny")] [CmdletBinding()] param ( $InputObject, [Parameter(Mandatory)] [String[]]$Filters, [Switch]$Not ) $FiltersRegex = foreach ($Filter In $Filters) { $Filter = [regex]::Escape($Filter) if ($Filter -match "^\\\*") { $Filter = $Filter.Remove(0, 2) } else { $Filter = '^' + $Filter } if ($Filter -match "\\\*$") { $Filter = $Filter.Substring(0, $Filter.Length - 2) } else { $Filter = $Filter + '$' } $Filter } if ($Not) { $InputObject -notmatch ($FiltersRegex -join '|').replace('\*', '.*').replace('\?', '.') } else { $InputObject -match ($FiltersRegex -join '|').replace('\*', '.*').replace('\?', '.') } } Push-Location "$PSScriptRoot\.." try { Write-Verbose -Message "Module installation started. Installing from $PWD" if (!$ModulePath) { if ($Scope -eq 'CurrentUser') { $ModulePathIndex = 0 } else { $ModulePathIndex = 1 } if ($IsLinux -or $IsMacOS) { $ModulePathSeparator = ':' } else { $ModulePathSeparator = ';' } $ModulePath = ($env:PSModulePath -split $ModulePathSeparator)[$ModulePathIndex] } Write-Verbose -Message "Installing to $ModulePath" # Get $ModuleName, $TargetPath, [$Links] if ($FromGitHub) { # Fix Could not create SSL/TLS secure channel #$SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol #[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $WebClient = [System.Net.WebClient]::new() $GitUri = $FromGitHub.AbsolutePath.Split('/')[1, 2] -join '/' $GitBranch = $FromGitHub.AbsolutePath.Split('/')[3] $Links = (Invoke-RestMethod -Uri "https://api.github.com/repos/$GitUri/contents" -Body @{ref = $GitBranch }) | Where-Object { (LikeAny $_.name $IncludeFiles) -and (LikeAny $_.name $ExcludeFiles -Not) } $ModuleName = [System.IO.Path]::GetFileNameWithoutExtension(($Links | Where-Object { $_.name -like '*.psm1' }).name) $ModuleVersion = (. ([Scriptblock]::Create((Invoke-WebRequest -Uri ($Links | Where-Object { $_.name -eq "$ModuleName.psd1" }).download_url)))).ModuleVersion } else { $ModuleName = [System.IO.Path]::GetFileNameWithoutExtension((Get-ChildItem -File -Filter *.psm1 -Name -Path $PWD)) $ModuleVersion = (. ([Scriptblock]::Create((Get-Content -Path (Join-Path $PWD "$ModuleName.psd1") | Out-String)))).ModuleVersion } $TargetPath = Join-Path -Path $ModulePath -ChildPath $ModuleName $TargetPath = Join-Path -Path $TargetPath -ChildPath $ModuleVersion # Create Directory if (-not (Test-Path -Path $TargetPath)) { $null = New-Item -Path $TargetPath -ItemType Directory -ErrorAction Stop Write-Verbose -Message ('Created module folder: "{0}"' -f $TargetPath) } # Copy Files if ($FromGitHub) { foreach ($Link in $Links) { $TargetPathItem = Join-Path -Path $TargetPath -ChildPath $Link.name if ($Link.type -ne 'dir') { $WebClient.DownloadFile($Link.download_url, $TargetPathItem) Write-Verbose -Message ('Installed module file: "{0}"' -f $Link.name) } else { if (-not (Test-Path -Path $TargetPathItem)) { $null = New-Item -Path $TargetPathItem -ItemType Directory -ErrorAction Stop Write-Verbose -Message 'Created module folder: "{0}"' -f $TargetPathItem } $SubLinks = (Invoke-RestMethod -Uri $Link.git_url -Body @{recursive = '1' }).tree foreach ($SubLink in $SubLinks) { $TargetPathSub = Join-Path -Path $TargetPathItem -ChildPath $SubLink.path if ($SubLink.'type' -EQ 'tree') { if (-not (Test-Path -Path $TargetPathSub)) { $null = New-Item -Path $TargetPathSub -ItemType Directory -ErrorAction Stop Write-Verbose -Message 'Created module folder: "{0}"' -f $TargetPathSub } } else { $WebClient.DownloadFile( ('https://raw.githubusercontent.com/{0}/{1}/{2}/{3}' -f $GitUri, $GitBranch, $Link.name, $SubLink.path), $TargetPathSub ) } } } } } else { Get-ChildItem -Path $PWD -Exclude $ExcludeFiles | Where-Object { LikeAny $_.Name $IncludeFiles } | ForEach-Object { if ($_.Attributes -ne 'Directory') { Copy-Item -Path $_ -Destination $TargetPath Write-Verbose -Message ('Installed module file "{0}"' -f $_) } else { Copy-Item -Path $_ -Destination $TargetPath -Recurse -Force Write-Verbose -Message ('Installed module folder "{0}"' -f $_) } } } # Import Module Write-Verbose -Message "$ModuleName module installation successful to $TargetPath" Import-Module -Name $ModuleName -Force Write-Verbose -Message "Module installed" } catch { throw ('Failed installing module "{0}". Error: "{1}" in Line {2}' -f $ModuleName, $_, $_.InvocationInfo.ScriptLineNumber) } finally { #if ($FromGitHub) { # [Net.ServicePointManager]::SecurityProtocol = $SecurityProtocol #} Write-Verbose -Message 'Module installation end' Pop-Location } |