You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have verified this is the correct repository for opening this issue.
I have verified no other issues exist related to my request.
Is Your Feature Request Related To A Problem? Please describe.
As a PowerShell developer, it would be great if we could support the commonly-used param-block usage seen in functions and scripts.
param(
# The path to install to
[string]$InstallDir="C:\Python$($env:ChocolateyPackageVersion-replace"^(\d+\.\d+).*","`$1")"
)
$ErrorActionPreference='Stop'$toolsDir=Split-Path$MyInvocation.MyCommand.Definition-Parent
<# ...Do install things... #>
When writing a PowerShell script, I expect this to work - but there is no nice way to pass arguments into Chocolatey to run scripts like this.
And there are many different ways people can write this handling logic.
Describe The Solution. Why is it needed?
Get-PackageParameters exists, but everyone has to reimplement the handling for parameters in their package, which is less simple than it might be. If we had a first-class handling for param-blocks (or some similar modern method), we could advise folk to handle parameters in a specific way, which would allow us to do potentially interesting things.
For instance, by enabling package maintainers to use param blocks:
They could (possibly) use standard PowerShell parameter validation and other fun attributes
They could add comment help to the parameters
This could then be analyzed and exposed in various ways (e.g. automatically displaying supported parameters and help for them on CCR, or within the CLI).
It leads into a known method and place to handle variables that can be changed, which will help community moderators and users reading install-scripts understand them more easily
It reduces the amount of package maintainers having to rewrite the (parameter handling) wheel every package
It could also ease testing of install scripts, though I am not convinced that is particularly useful at this point for various reasons.
Additional Context
I had a play with adding a very basic transformation attribute to parameters within a chocolateyInstall.ps1 script.
classPackageParameterAttribute : System.Management.Automation.ArgumentTransformationAttribute {
[string]$TargetParameterstatic [string] GetPackageParameterValue ($Name) {
$PP=Get-PackageParametersif ($PP.ContainsKey($Name)) {
return$PP[$Name]
} else {
return$null
}
}
[object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object]$inputData) {
if ([PackageParameterAttribute]::GetPackageParameterValue($this.TargetParameter)) {
return [PackageParameterAttribute]::GetPackageParameterValue($this.TargetParameter)
} else {
return$inputData
}
}
# PackageParameterAttribute() {# # Can't figure out a way to get the name of the parameter, so we currently have to specify one# $this.TargetParameter = "Test"# }
PackageParameterAttribute([string]$Target) {
$this.TargetParameter=$Target
}
}
This seems to work pretty nicely when added to the chocolateyInstaller helper functions, and handles using the default value in a script if a user doesn't pass a matching --package-parameter (whilst overriding it if they do).
As an example, by adding [PackageParameter("NameOfPackageParameter")] to a parameter, we can see the default, the help, and easily have a user provide input:
[CmdletBinding()]
param(
# The path to extract the files to
[PackageParameter("InstallPath")]
$InstallPath=$(Split-Path$MyInvocation.MyCommand.Definition-Parent),# A message to output (completely arbitrary example)
[PackageParameter("Message")]
[ValidateNotNullOrEmpty()]
$MessageOutput="There was no additional message provided."
)
Write-Host"Installing package to '$($InstallPath)'"Write-Host$MessageOutput
It has a few potential disadvantages:
Classes like this are only supported in PowerShell 5+ (but we could use Add-Type to bring it back to PowerShell 3+, or possibly use a compiled module to make it available everywhere?)
Adding parameter attributes like this will cause package scripts to fail if the attribute isn't available, which is obviously rubbish. Adding the attribute does seem to work both from helpers and from extensions, though, so we could have it available in Choco-latest and a compatibility package.
ArgumentTransformation is only triggered on parameters that have a value, it seems, so you need to provide a default value to any parameters that use it. It's possible we could implement this as a different attribute type and still modify the value?
It could be inefficient if someone had an obscene number of parameters (though I think the number would have to be silly, and this could be easily solved - again, this is just some POC fun to inspire discussion, here)
Current lack of handling for, e.g. switch-type parameters (again, POC - this could be handled, just needs thought)
I am unsure this method for implementation would allow use of parameter validation attributes, due to the way it's being passed. May be wrong / may be fixable.
Example of Add-Type equivalent:
Add-Type @'
using System.Management.Automation;
public sealed class PackageParameterAttribute : ArgumentTransformationAttribute {
string _targetParameter;
string _getPackageParameterValueScript {
get {
return string.Format(
@"
$PP = Get-PackageParameters
if ($PP.ContainsKey('{0}')) {{
return $PP['{0}']
}} else {{
return $null
}}
",
_targetParameter
);
}
}
// // This currently doesn't work, as we can't retrieve the ParameterName easily
// public PackageParameterAttribute() {
// _targetParameter = '???'
// }
public PackageParameterAttribute(string packageParameterName) {
_targetParameter = packageParameterName;
}
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) {
var result = engineIntrinsics.InvokeCommand.InvokeScript(_getPackageParameterValueScript)[0];
if (null != result) {
return result;
}
return inputData;
}
}
'@
An alternative to adding an attribute like this would be rewriting the chocolateyScriptRunner.ps1 to pass in parameters where parameters are found, but that would involve a fair bit of calculation (or a requirement for an ignored parameter with ValueFromRemainingArguments to swallow unwanted splatting on all supporting scripts, perhaps?) and I've quite enjoyed this method so far.
Related Issues
No response
The text was updated successfully, but these errors were encountered:
JPRuskin
changed the title
Allow use of param() blocks in Chocolatey* Scripts
Enable use of param() blocks in Chocolatey* Scripts
Oct 13, 2023
Checklist
Is Your Feature Request Related To A Problem? Please describe.
As a PowerShell developer, it would be great if we could support the commonly-used param-block usage seen in functions and scripts.
When writing a PowerShell script, I expect this to work - but there is no nice way to pass arguments into Chocolatey to run scripts like this.
Instead, we have folk using something like this:
And there are many different ways people can write this handling logic.
Describe The Solution. Why is it needed?
Get-PackageParameters
exists, but everyone has to reimplement the handling for parameters in their package, which is less simple than it might be. If we had a first-class handling for param-blocks (or some similar modern method), we could advise folk to handle parameters in a specific way, which would allow us to do potentially interesting things.For instance, by enabling package maintainers to use param blocks:
It could also ease testing of install scripts, though I am not convinced that is particularly useful at this point for various reasons.
Additional Context
I had a play with adding a very basic transformation attribute to parameters within a
chocolateyInstall.ps1
script.This seems to work pretty nicely when added to the
chocolateyInstaller
helper functions, and handles using the default value in a script if a user doesn't pass a matching--package-parameter
(whilst overriding it if they do).As an example, by adding
[PackageParameter("NameOfPackageParameter")]
to a parameter, we can see the default, the help, and easily have a user provide input:It has a few potential disadvantages:
Add-Type
to bring it back to PowerShell 3+, or possibly use a compiled module to make it available everywhere?)Example of Add-Type equivalent:
An alternative to adding an attribute like this would be rewriting the
chocolateyScriptRunner.ps1
to pass in parameters where parameters are found, but that would involve a fair bit of calculation (or a requirement for an ignored parameter with ValueFromRemainingArguments to swallow unwanted splatting on all supporting scripts, perhaps?) and I've quite enjoyed this method so far.Related Issues
No response
The text was updated successfully, but these errors were encountered: