chocolatey / choco

Chocolatey - the package manager for Windows
https://chocolatey.org
Other
10.26k stars 900 forks source link

Unable to install a package that requires PowerShell 6.2.0 min version as Choco uses an older PowerShell Version (5.x) #3403

Closed laura-rodriguez closed 7 months ago

laura-rodriguez commented 7 months ago

Checklist

What You Are Seeing?

I'm preparing a Choco package for a PowerShell module that requires a minimum PS version of 6.2.0. When I try to test/install my Choco package locally, it fails as internally as the module installation uses "Host version is 5.1.22621.2506". I tried using the --use-system-powershell flag, but it doesn't work either for my case. Is there a way to force choco use a specific PowerShell version?

Here's my redacted log:

2024-02-28 11:16:29,354 70600 [DEBUG] -  DEBUG: Host version is 5.1.22621.2506, PowerShell Version is '5.1.22621.2506' and CLR Version is '4.0.30319.42000'.

2024-02-28 11:16:31,091 70600 [ERROR] -  Okta.PowerShell module requires a minimum of PowerShell v6.2.0.
2024-02-28 11:16:31,092 70600 [ERROR] -  At C:\ProgramData\chocolatey\lib\okta.powershell\tools\chocolateyinstall.ps1:17 char:3
2024-02-28 11:16:31,092 70600 [ERROR] -  +   throw "$moduleName module requires a minimum of PowerShell v$minPSV ...
2024-02-28 11:16:31,093 70600 [ERROR] -  +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2024-02-28 11:16:31,093 70600 [ERROR] -      + CategoryInfo          : OperationStopped: (Okta.PowerShell...erShell v6.2.0.:String) [], RuntimeException
2024-02-28 11:16:31,094 70600 [ERROR] -      + FullyQualifiedErrorId : Okta.PowerShell module requires a minimum of PowerShell v6.2.0.

Here's my chocolateyinstall.ps1 script:

$ErrorActionPreference = 'Stop' # stop on all errors
$toolsDir   = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"

$minPSVersion = '6.2.0'
$moduleName = 'Okta.PowerShell'
$moduleVersion = '1.0.0'
$savedParamsPath = Join-Path $toolsDir -ChildPath 'parameters.saved'

if ($PSVersionTable.PSVersion -lt [version]$minPSVersion) {
  throw "$moduleName module requires a minimum of PowerShell v$minPSVersion."
}

# module may already be installed outside of Chocolatey
Remove-Module -Name $moduleName -Force -ErrorAction SilentlyContinue

# remove the saved parameters file if it exists
if (Test-Path -Path $savedParamsPath) {
  Remove-Item -Path $savedParamsPath -Force
}

$sourcePath = Join-Path -Path $toolsDir -ChildPath "$moduleName.zip"

Write-Host "Destination path '$sourcePath'"

$savedParamsPath = Join-Path $toolsDir -ChildPath 'parameters.saved'

Write-Debug "Host version is $($host.Version), PowerShell Version is '$($PSVersionTable.PSVersion)' and CLR Version is '$($PSVersionTable.CLRVersion)'."

$destinationPath += Join-Path -Path $env:ProgramFiles -ChildPath "PowerShell\Modules\"

Write-Host "Destination path '$destinationPath'"

 # check destination path exists and create if not
 if (Test-Path -Path $destinationPath) {
  $null = New-Item -Path $destinationPath -ItemType Directory -Force
}

Write-Verbose "Installing '$modulename' to '$destinationPath'."

Get-ChocolateyUnzip -FileFullPath $sourcePath -Destination $destPath -PackageName $moduleName -Verbose

# save the locations where the module was installed so we can uninstall it
Add-Content -Path $savedParamsPath -Value $destinationPath

# cleanup the module from the Chocolatey $toolsDir folder
Remove-Item -Path $sourcePath -Force -Recurse

What is Expected?

I want my installation script uses a specific PowerShell version if it's available.

How Did You Get This To Happen?

choco install okta.powershell --source ./ --use-system-powershell -y --debug --verbose --force

System Details

Installed Packages

checksum 0.3.1
chocolatey 2.2.2
chocolatey-compatibility.extension 1.0.0
chocolatey-core.extension 1.4.0
chocolatey-dotnetfx.extension 1.0.1
chocolatey-visualstudio.extension 1.11.1
chocolatey-windowsupdate.extension 1.0.5
dotnetfx 4.8.0.20220524
git.install 2.43.0
jq 1.7.1
KB2919355 1.0.20160915
KB2919442 1.0.20160915
KB2999226 1.0.20181019
KB3033929 1.0.5
KB3035131 1.0.3
KB3118401 1.0.5
nuget.commandline 6.7.0
NugetPackageExplorer 6.0.64
okta-aws-cli 2.0.1
powershell-core 7.4.1
python311 3.11.8
vcredist140 14.36.32532
vcredist2015 14.0.24215.20170201
visualstudio2019buildtools 16.11.30
visualstudio2019-workload-vctools 1.0.1
visualstudio-installer 2.0.3
winget.powershell 1.6.3133

Output Log

2024-02-28 11:16:29,354 70600 [DEBUG] -  DEBUG: Host version is 5.1.22621.2506, PowerShell Version is '5.1.22621.2506' and CLR Version is '4.0.30319.42000'.

2024-02-28 11:16:31,091 70600 [ERROR] -  Okta.PowerShell module requires a minimum of PowerShell v6.2.0.
2024-02-28 11:16:31,092 70600 [ERROR] -  At C:\ProgramData\chocolatey\lib\okta.powershell\tools\chocolateyinstall.ps1:17 char:3
2024-02-28 11:16:31,092 70600 [ERROR] -  +   throw "$moduleName module requires a minimum of PowerShell v$minPSV ...
2024-02-28 11:16:31,093 70600 [ERROR] -  +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2024-02-28 11:16:31,093 70600 [ERROR] -      + CategoryInfo          : OperationStopped: (Okta.PowerShell...erShell v6.2.0.:String) [], RuntimeException
2024-02-28 11:16:31,094 70600 [ERROR] -      + FullyQualifiedErrorId : Okta.PowerShell module requires a minimum of PowerShell v6.2.0.


### Additional Context

_No response_
pauby commented 7 months ago

Chocolatey CLI only supports Windows PowerShell as an internal host. I'm unsure if --use-system-powershell will use PowerShell Core if it's installed. @gep13 @AdmiringWorm may have the answer to that.

TheCakeIsNaOH commented 7 months ago

I'm unsure if --use-system-powershell will use PowerShell Core if it's installed.

It will not use PowerShell Core, it will only use Windows PowerShell (via powershell.exe) when using system powershell.

Is there a way to force choco use a specific PowerShell version?

In this case, I think the best option would be to call pwsh.exe in chocolateyInstall.ps1 for any specific commands that need to be run in PowerShell Core. Use Start-ChocolateyProcessAsAdmin if the command needs administrator privileges.

pauby commented 7 months ago

The issue with the package appears to be this line:

if ($PSVersionTable.PSVersion -lt [version]$minPSVersion) {
  throw "$moduleName module requires a minimum of PowerShell v$minPSVersion."
}

You're trying to detect the version of the PowerShell host and if it doesn't meet your minimum requirements, throwing an error. However, PowerShell (Core) is an optional install, on the majority of operating systems. But that doesn't stop your package from being installed. Your package doesn't need PowerShell Core. The module Okta.PowerShell does. But you're not running the module in the package. The package is simply the deployment method, so it doesn't matter what version of PowerShell it uses.

I do something like this for packages I maintain that require Java. I don't detect the Java version, but I do say 'This package requires Java' (the reason for this is that there are so many flavours and versions, it would be impossible to get it right all the time). . So I'd suggest the following:

# check PowerShell Core is available
if (Get-Command -Name 'pwsh.exe' -ErrorAction SilentlyContinue) {
    # we've confirmed PowerShell Core is available, retrieve the version of it
    $hostVersion = [Version]((pwsh.exe -Command { $PSVersionTable }).PSVersion)

    # does the version of PowerShell Core installed meet the minimum version we need?
    if ([Version]$hostVersion -lt [version]$minPSVersion) {
        # better to use 'Write-Warning' here
        throw "$moduleName module requires a minimum of PowerShell v$minPSVersion."
    }
}
else {
      # better to use 'Write-Warning' here
      throw "$moduleName module requires a minimum of PowerShell v$minPSVersion."
}

(I've briefly tested this code, and it works, but check it). (note that I wrote this to make it readable rather than concise - you can combine both if statements into one line)

What this does it check that PowerShell Core is installed. If not, it throws the exception. If it is installed, it runs the host and grabs the PSVersion from $PSVersionTable and then compares it to what you need.

A suggestion would be not to throw, but to use Write-Warning. The package can be installed without PowerShell Core installed and you should therefore allow the install, to take place with a warning that the module can't be run without them installing PowerShell Core. You could even help by providing them the command to install PowerShell Core: choco install powershell-core.

Or, the better way, is to simply add a dependency on a minimum version, 6.2.0, of powershell-core as a package dependency. That way you don't need any of the above as it will be taken care of for you.

laura-rodriguez commented 7 months ago

Thanks for all the suggestions here! They're super helpful. I'll give adding powershell-core as a dependency and Pauby's script a try.

laura-rodriguez commented 7 months ago

@pauby I've made the changes you suggested, and the installation works as expected. Thanks a lot!