Templates/Build/Resolve-Dependency.ps1
[CmdletBinding()] param ( [Parameter()] [String] $DependencyFile = 'RequiredModules.psd1', [Parameter()] [String] # Path for PSDepend to be bootstrapped and save other dependencies. # Can also be CurrentUser or AllUsers if you wish to install the modules in such scope # Default to $PWD.Path/output/modules $PSDependTarget = (Join-Path $PSScriptRoot './output/RequiredModules'), [Parameter()] [uri] # URI to use for Proxy when attempting to Bootstrap PackageProvider & PowerShellGet $Proxy, [Parameter()] # Credential to contact the Proxy when provided [PSCredential]$ProxyCredential, [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] [String] # Scope to bootstrap the PackageProvider and PSGet if not available $Scope = 'CurrentUser', [Parameter()] [String] # Gallery to use when bootstrapping PackageProvider, PSGet and when calling PSDepend (can be overridden in Dependency files) $Gallery = 'PSGallery', [Parameter()] [PSCredential] # Credentials to use with the Gallery specified above $GalleryCredential, [Parameter()] [switch] # Allow you to use a locally installed version of PowerShellGet older than 1.6.0 (not recommended, default to $False) $AllowOldPowerShellGetModule, [Parameter()] [String] # Allow you to specify a minimum version fo PSDepend, if you're after specific features. $MinimumPSDependVersion, [Parameter()] [Switch] $AllowPrerelease, [Parameter()] [Switch] $WithYAML ) # Load Defaults for parameters values from Resolve-Dependency.psd1 if not provided as parameter try { if ($PSversionTable.PSversion.Major -le 5) { if (!(Get-Command -name Import-PowerShellDataFile -ErrorAction SilentlyContinue)) { Import-Module Microsoft.PowerShell.Utility -RequiredVersion 3.1.0.0 } # Making sure the Imported PackageManagement module is not from PS7 module path # The vscode PS extension is changing the $Env:PSModulePath and prioritise the PS7 path # This is an issue with PowerShellGet because it loads an old version if available (or fail to load latest) Get-Module -ListAvailable PackageManagement | Where-Object ModuleBase -notmatch 'powershell.7' | Select-Object -First 1 | Import-Module -Force } Write-Verbose -Message "Importing Bootstrap default parameters from '$PSScriptRoot/Resolve-Dependency.psd1'." $ResolveDependencyDefaults = Import-PowerShellDataFile -Path (Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1' -Resolve -ErrorAction Stop) $ParameterToDefault = $MyInvocation.MyCommand.ParameterSets.Where{ $_.Name -eq $PSCmdlet.ParameterSetName }.Parameters.Keys if ($ParameterToDefault.Count -eq 0) { $ParameterToDefault = $MyInvocation.MyCommand.Parameters.Keys } # Set the parameters available in the Parameter Set, or it's not possible to choose yet, so all parameters are an option foreach ($ParamName in $ParameterToDefault) { if (-Not $PSBoundParameters.Keys.Contains($ParamName) -and $ResolveDependencyDefaults.ContainsKey($ParamName)) { Write-Verbose -Message "Setting $ParamName with $($ResolveDependencyDefaults[$ParamName])" try { $variableValue = $ResolveDependencyDefaults[$ParamName] if ($variableValue -is [string]) { $variableValue = $ExecutionContext.InvokeCommand.ExpandString($variableValue) } $PSBoundParameters.Add($ParamName, $variableValue) Set-Variable -Name $ParamName -value $variableValue -Force -ErrorAction SilentlyContinue } catch { Write-Verbose -Message "Error adding default for $ParamName : $($_.Exception.Message)" } } } } catch { Write-Warning -Message "Error attempting to import Bootstrap's default parameters from $(Join-Path $PSScriptRoot '.\Resolve-Dependency.psd1'): $($_.Exception.Message)." } Write-Progress -Activity "Bootstrap:" -PercentComplete 0 -CurrentOperation "NuGet Bootstrap" if (!(Import-Module -Name PowerShellGet -MinimumVersion 2.0 -ErrorAction SilentlyContinue -PassThru ) -and !(Get-PackageProvider -Name NuGet -ForceBootstrap -ErrorAction SilentlyContinue)) { $providerBootstrapParams = @{ Name = 'nuget' force = $true ForceBootstrap = $true ErrorAction = 'Stop' } switch ($PSBoundParameters.Keys) { 'Proxy' { $providerBootstrapParams.Add('Proxy', $Proxy) } 'ProxyCredential' { $providerBootstrapParams.Add('ProxyCredential', $ProxyCredential) } 'Scope' { $providerBootstrapParams.Add('Scope', $Scope) } } if ($AllowPrerelease) { $providerBootstrapParams.Add('AllowPrerelease', $true) } Write-Information "Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed)" $null = Install-PackageProvider @providerBootstrapParams $latestNuGetVersion = (Get-PackageProvider -Name NuGet -ListAvailable | Select-Object -First 1).Version.ToString() Write-Information "Bootstrap: Importing NuGet Package Provider version $latestNuGetVersion to current session." $Null = Import-PackageProvider -Name NuGet -RequiredVersion $latestNuGetVersion -Force } Write-Progress -Activity "Bootstrap:" -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" # Fail if the given PSGallery is not Registered $Policy = (Get-PSRepository $Gallery -ErrorAction Stop).InstallationPolicy Set-PSRepository -Name $Gallery -InstallationPolicy Trusted -ErrorAction Ignore try { Write-Progress -Activity "Bootstrap:" -PercentComplete 25 -CurrentOperation "Checking PowerShellGet" # Ensure the module is loaded and retrieve the version you have $PowerShellGetVersion = (Import-Module PowerShellGet -PassThru -ErrorAction SilentlyContinue).Version Write-Verbose "Bootstrap: The PowerShellGet version is $PowerShellGetVersion" # Versions below 2.0 are considered old, unreliable & not recommended if (!$PowerShellGetVersion -or ($PowerShellGetVersion -lt [System.version]'2.0' -and !$AllowOldPowerShellGetModule)) { Write-Progress -Activity "Bootstrap:" -PercentComplete 40 -CurrentOperation "Installing newer version of PowerShellGet" $InstallPSGetParam = @{ Name = 'PowerShellGet' Force = $True SkipPublisherCheck = $true AllowClobber = $true Scope = $Scope Repository = $Gallery } switch ($PSBoundParameters.Keys) { 'Proxy' { $InstallPSGetParam.Add('Proxy', $Proxy) } 'ProxyCredential' { $InstallPSGetParam.Add('ProxyCredential', $ProxyCredential) } 'GalleryCredential' { $InstallPSGetParam.Add('Credential', $GalleryCredential) } } Install-Module @InstallPSGetParam Remove-Module PowerShellGet -force -ErrorAction SilentlyContinue Remove-Module PackageManagement -Force $PSGetImport = Import-Module PowerShellGet -Force -PassThru $NewLoadedVersion = $PSGetImport.Version.ToString() Write-Information "Bootstrap: PowerShellGet version loaded is $NewLoadedVersion" Write-Progress -Activity "Bootstrap:" -PercentComplete 60 -CurrentOperation "Installing newer version of PowerShellGet" } # Try to import the PSDepend module from the available modules try { $ImportPSDependParam = @{ Name = 'PSDepend' ErrorAction = 'Stop' Force = $true } if ($MinimumPSDependVersion) { $ImportPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) } $null = Import-Module @ImportPSDependParam } catch { # PSDepend module not found, installing or saving it if ($PSDependTarget -in 'CurrentUser', 'AllUsers') { Write-Debug "PSDepend module not found. Attempting to install from Gallery $Gallery" Write-Warning "Installing PSDepend in $PSDependTarget Scope" $InstallPSDependParam = @{ Name = 'PSDepend' Repository = $Gallery Force = $true Scope = $PSDependTarget SkipPublisherCheck = $true AllowClobber = $true } if ($MinimumPSDependVersion) { $InstallPSDependParam.add('MinimumVersion', $MinimumPSDependVersion) } Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Installing PSDepend from $Gallery" Install-Module @InstallPSDependParam } else { Write-Debug "PSDepend module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" $SaveModuleParam = @{ Name = 'PSDepend' Repository = $Gallery Path = $PSDependTarget } if ($MinimumPSDependVersion) { $SaveModuleParam.add('MinimumVersion', $MinimumPSDependVersion) } Write-Progress -Activity "Bootstrap:" -PercentComplete 75 -CurrentOperation "Saving & Importing PSDepend from $Gallery to $Scope" Save-Module @SaveModuleParam } } finally { Write-Progress -Activity "Bootstrap:" -PercentComplete 100 -CurrentOperation "Loading PSDepend" # We should have successfully bootstrapped PSDepend. Fail if not available Import-Module PSDepend -ErrorAction Stop } if ($WithYAML) { if (-Not (Get-Module -ListAvailable -Name 'PowerShell-Yaml')) { Write-Verbose "PowerShell-Yaml module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" $SaveModuleParam = @{ Name = 'PowerShell-Yaml' Repository = $Gallery Path = $PSDependTarget } Save-Module @SaveModuleParam Import-Module "PowerShell-Yaml" -ErrorAction Stop } else { Write-Verbose "PowerShell-Yaml is already available" } } Write-Progress -Activity "PSDepend:" -PercentComplete 0 -CurrentOperation "Restoring Build Dependencies" if (Test-Path $DependencyFile) { $PSDependParams = @{ Force = $true Path = $DependencyFile } # TODO: Handle when the Dependency file is in YAML, and -WithYAML is specified Invoke-PSDepend @PSDependParams } Write-Progress -Activity "PSDepend:" -PercentComplete 100 -CurrentOperation "Dependencies restored" -Completed } finally { # Reverting the Installation Policy for the given gallery Set-PSRepository -Name $Gallery -InstallationPolicy $Policy Write-Verbose "Project Bootstrapped, returning to Invoke-Build" } |