PowerCD.bootstrap.ps1
#requires -version 5.1 using namespace System.IO #This bootstraps the invoke-build environment for PowerCD param ( #Specify the version of PowerCD to use. By default it will use the latest available either on this system or on Powershell Gallery [Version]$PowerCDVersion ) $ErrorActionPreference = 'Stop' $GLOBAL:ProgressPreference = 'SilentlyContinue' #Invoke-Build Report style if ($BuildRoot) { Write-Host -fore cyan "Task PowerCD.Bootstrap" $bootstrapTimer = [Diagnostics.Stopwatch]::StartNew() } #First checks for a "metabuild" (PowerCD building PowerCD), then does normal detection try { Write-Debug "Searching for PowerCD MetaBuild in $pwd" #Workaround for running a bootstrap script from the internet $PSModuleBuildScriptPath = if ($PSSCRIPTROOT) {$PSScriptRoot} else {Split-Path $MyInvocation.ScriptName} foreach ($MetaBuildPathItem in @( "$pwd/../PowerCD/PowerCD.psd1" "$pwd/PowerCD/PowerCD.psd1" "$PSModuleBuildScriptPath/../PowerCD/PowerCD.psd1" "$PSModuleBuildScriptPath/PowerCD/PowerCD.psd1" )) { if (Test-Path $MetaBuildPathItem) { #Cannot cast pathinfo output directly to fileinfo, but can use string as an intermediate [IO.FileInfo]$GLOBAL:MetaBuildPath = [String](Resolve-Path $MetaBuildPathItem) Write-Debug "PowerCD Metabuild Detected, importing source module: $MetaBuildPath" Import-Module $MetaBuildPath -Force -WarningAction SilentlyContinue return } } #Normal bootstrap function BootstrapModule { param ( $ModuleSpecification, $Path = (Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'PowerCD') ) $vEnvDir = New-Item -ItemType Directory -Force -Path $Path try { $currentPSModulePath = $env:PSModulePath $env:PSModulePath = $vEnvDir,$env:PSModulePath -join [io.path]::PathSeparator #This is done for performance. If the module is found loaded it won't try to search filesystem $moduleLoaded = (Get-Module -FullyQualifiedName $moduleSpecification -ErrorAction SilentlyContinue) $moduleAvailable = if (-not $moduleLoaded) { (Get-Module -ListAvailable -FullyQualifiedName $moduleSpecification -ErrorAction SilentlyContinue) } else { $true } if (-not $moduleLoaded) { $moduleParams = @{ Name = $moduleSpecification.ModuleName MinimumVersion = $moduleSpecification.ModuleVersion MaximumVersion = $moduleSpecification.MaximumVersion Force = $true ErrorAction = 'Stop' } if (-not $moduleAvailable) { Write-Verbose "$($ModuleSpecification.ModuleName) not found locally. Bootstrapping..." Save-Module @moduleParams -Path $vEnvDir } Import-Module @moduleParams } } catch { throw $PSItem } finally { #Revert PSModulePath $env:PSModulePath = $currentPSModulePath } } $pcdModuleSpec = @{ ModuleName = 'PowerCD' } #Fallback to a minimum PowerCD requirement if ($PowerCDVersion) { $pcdModuleSpec.RequiredVersion = $PowerCDVersion } else { $pcdModuleSpec.ModuleVersion = '0.8.1' } BootstrapModule $pcdModuleSpec } catch { write-host -fore Red "ERROR CAUGHT WHILE BOOTSTRAPPING MODULE: $_" throw $_ } finally { if ($BuildRoot) { Write-Host -fore cyan "Done PowerCD.Bootstrap $([string]$bootstrapTimer.elapsed)" } if ( (Get-Command -Name 'PowerCD.Tasks' -ErrorAction SilentlyContinue) -and (Get-Variable -Name '`*' -ErrorAction SilentlyContinue) ) { . PowerCD.Tasks } } # $pcdModuleParams = @{ # Global = $true # Force = $true # WarningAction = 'SilentlyContinue' # } # if ($PowerCDMetaBuild) { # #Reinitialize # } # if ($PowerCDVersion) { # $candidateModules = Get-Module -Name PowerCD -ListAvailable # if ($PowerCDVersion) { # if ($PowerCDVersion -in $candidateModules.Version) { # Get-Module 'PowerCD' | Remove-Module -Force -ErrorAction Stop 4>$null # Import-Module @pcdModuleParams -RequiredVersion $PowerCDVersion 4>$null # return # } # } # } else { # #Try loading native module if PowerCDVersion was not specified # $CandidateModule = Import-Module @pcdModuleParams -Name PowerCD -ErrorAction SilentlyContinue -PassThru # if ($CandidateModule) {return} # } # function DetectNestedPowershell { # #Fix a bug in case powershell was started in pwsh and it cluttered PSModulePath: https://github.com/PowerShell/PowerShell/issues/9957 # if ($PSEdition -eq 'Desktop' -and ((get-module -Name 'Microsoft.PowerShell.Utility').CompatiblePSEditions -eq 'Core')) { # Write-Verbose 'Powershell 5.1 was started inside of pwsh, removing non-WindowsPowershell paths' # $env:PSModulePath = ($env:PSModulePath -split [Path]::PathSeparator | Where-Object {$_ -match 'WindowsPowershell'}) -join [Path]::PathSeparator # $ModuleToImport = Get-Module Microsoft.Powershell.Utility -ListAvailable | # Where-Object Version -lt 6.0.0 | # Sort-Object Version -Descending | # Select-Object -First 1 # Remove-Module 'Microsoft.Powershell.Utility' # Import-Module $ModuleToImport -Force 4>&1 | Where-Object {$_ -match '^Loading Module.+psd1.+\.$'} | Write-Verbose # } # } #region HelperFunctions # function Install-PSGalleryModule { # <# # .SYNOPSIS # Downloads a module from the Powershell Gallery using direct APIs. This is primarily used to bootstrap # #> # [CmdletBinding()] # param ( # [Parameter(Mandatory)][String]$Name, # [Parameter(Mandatory)][String]$Destination, # [String]$Version # ) # if (-not (Test-Path $Destination)) {throw "Destination $Destination doesn't exist. Please specify a powershell modules directory"} # $downloadURI = "https://www.powershellgallery.com/api/v2/package/$Name" # if ($version) {$downloadURI += "/$Version"}buc # try { # $ErrorActionPreference = 'Stop' # $tempZipName = "mybootstrappedPSGalleryModule.zip" # $tempDirPath = Join-Path ([io.path]::GetTempPath()) "$Name-$(get-random)" # $tempDir = New-Item -ItemType Directory -Path $tempDirPath # $tempFilePath = Join-Path $tempDir $tempZipName # [void][net.webclient]::new().DownloadFile($downloadURI,$tempFilePath) # [void][System.IO.Compression.ZipFile]::ExtractToDirectory($tempFilePath, $tempDir, $true) # $moduleManifest = Get-Content -raw (Join-Path $tempDirPath "$Name.psd1") # $modulePathVersion = if ($moduleManifest -match "ModuleVersion = '([\.\d]+)'") {$matches[1]} else {throw "Could not read Moduleversion from the module manifest"} # $itemsToRemove = @($tempZipName,'_rels','package','`[Content_Types`].xml','*.nuspec').foreach{ # Join-Path $tempdir $PSItem # } # Remove-Item $itemsToRemove -Recurse # $destinationModulePath = Join-Path $destination $Name # $destinationPath = Join-Path $destinationModulePath $modulePathVersion # if (-not (Test-Path $destinationModulePath)) {$null = New-Item -ItemType Directory $destinationModulePath} # if (Test-Path $destinationPath) {Remove-Item $destinationPath -force -recurse} # $null = Move-Item $tempdir -Destination $destinationPath # Set-Location -path ([io.path]::Combine($Destination, $Name, $modulePathVersion)) # #([IO.Path]::Combine($Destination, $Name, $modulePathVersion), $true) # } catch {throw $PSItem} finally { # #Cleanup # if (Test-Path $tempdir) {Remove-Item -Recurse -Force $tempdir} # } # } |