(#3344) Adds ParameterBlock Handling to Chocolatey Script Runner
Description Of Changes
This PR introduces the ability for ChocolateyInstall, ChocolateyBeforeModify, and ChocolateyUninstall scripts to have and utilise PowerShell param() blocks to handle parameters.
It does this by adding a function (Get-PackageScriptParameters), which calculates what parameters a script has and passes any parameters found by the existing function Get-PackageParameters that match the parameter names to the script. Optionally, we could handle aliases, but this implementation does not yet.
The new function is called within the ChocolateyScriptRunner before invoking the script, and the resultant hashtable is "splatted" with the call. When no matching parameters are found (on the script and in packageparameters), this results in no change to behaviour.
It's worth noting that though this does allow for usage of parameter attributes and validation, such as [Parameter(Mandatory)], [ValidateSet()] and the like, Chocolatey can currently swallow some useful output (e.g. with SomeString being a mandatory parameter):
vs the PowerShell default:
This could possibly be improved in the future.
It adds the functionality, but doesn't remove the existing parameter handling - so all existing packages will continue working.
SMA Update
As a part of this, because of the use of the System.Management.Automation.Language to assess the param block, the System.Management.Automation assembly present in the lib/powershell folder was updated from a version matching the version shipped with PowerShell 2.0 (best guess) to a version from our earliest currently supported version of Windows - 2012.
This DLL isn't shipped in any of our builds; it's just used to ensure our code uses methods et al that are supported by the specific DLL we have embedded in the repository.
Specifically, I grabbed this from the uncertain/fun provenance of a Windows Server 2012 VM, in the folder C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35. There's not a similar version on nuget.org, annoyingly, which only has versions from 2018 onwards starting at 6.0.4.
There is an argument that this is a breaking change, as it may no longer work on machines we don't support - but that "break" has already happened. We do not support Windows versions prior to 2012 (and that only in Azure). Everything else is additive-only, and backwards compatible via a "lovely" new extension I'm looking to publish.
Motivation and Context
This allows for standardisation of how package maintainers handle parameters within their scripts, and helps Chocolatey Community Repository users and moderators to more easily understand what parameters can be used, what default values are used, and what (if any) validation is in place.
Testing
- Grab https://chocolatey.org/install.ps1 and the modified version of the Chocolatey nupkg package, copy them to your test environment.
-
Set-ExecutionPolicy RemoteSigned Process -Forceand Install with.\Install.ps1 -ChocolateyDownloadUrl .\Path\To\chocolatey.nupkg - Optional: install a random package without parameters to ensure I've not broken the existing functionality
choco install cloudflared --confirm - Optional: install a random package with parameters to ensure I've not broken the existing functionality
choco install Temurin21jre --params="/ADDLOCAL=FeatureMain,FeatureEnvironment,FeatureJarFileRunWith,FeatureJavaHome" --confirm - Grab a package with param blocks available, e.g. testextension.1.0.0.zip (attached as a zip, as nupkg is not a supported file type) and copy it to the test environment (or have it in a repository)
-
choco install testextension --params='/SomeString:A String Value' --confirm(some massaging required for source)
NB: testextension will fail to install if the PowerShell parameter value "SomeString" provided doesn't match the package parameter found by
Get-PackageParameters. The install script is partially shown below:
param(
[string]$SomeString
)
$PackageParameters = Get-PackageParameters
if ($PackageParameters.SomeString -ne $SomeString) {
throw "'$SomeString' was not equal to '$($PackageParameters.SomeString)'"
}
Operating Systems Testing
- Windows Server 2012
- Windows Server 2022
- Windows 11 (Sandbox)
I also have an extension package that adds the same functionality to any other extension-supporting version of Chocolatey CLI. This hopefully means that this can be an acceptable thing to use for Community packages.
I am very excited about this, despite the code being utterly despicable.
I have had to slightly revise my backwards compatibility happiness - it doesn't work with the earliest mention of Chocolatey extensions (0.9.10) because Get-PackageParameters doesn't exist at that point. I could fix this by packing a backup version fo the function in the extension, but I feel like supporting back to the 0.10.8 is enough for any unreasonable expectation:
Change Types Made
- ~[ ] Bug fix (non-breaking change).~
- [x] Feature / Enhancement (non-breaking change).
- ~[ ] Breaking change (fix or feature that could cause existing functionality to change).~ See SMA update.
- ~[ ] Documentation changes.~
- [x] PowerShell code changes.
Change Checklist
- ~[ ] Requires a change to the documentation.~
- ~[ ] Documentation has been updated.~
- [x] Tests to cover my changes, have been added.
- [x] All new and existing tests passed?
- [x] PowerShell code changes: PowerShell v3 compatibility checked?
Related Issue
Resolves #3344