Skip to content

Commit f60bd70

Browse files
committed
(#3344) Convert Get-PackageScriptParameter to helper cmdlet
It was pointed out that this PR should be targeted at including new helper functions into the C# conversion efforts. This converts Get-PackageParameter to use a helper class (shared between this and the new cmdlet) and adds Get-PackageScriptParameters to the Chocolatey.PowerShell compiled module.
1 parent ae1f629 commit f60bd70

File tree

5 files changed

+193
-235
lines changed

5 files changed

+193
-235
lines changed

src/Chocolatey.PowerShell/Chocolatey.PowerShell.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@
6161
<Compile Include="Commands\GetEnvironmentVariableCommand.cs" />
6262
<Compile Include="Commands\GetEnvironmentVariableNamesCommand.cs" />
6363
<Compile Include="Commands\GetPackageParameterCommand.cs" />
64+
<Compile Include="Commands\GetPackageScriptParametersCommand.cs" />
6465
<Compile Include="Commands\InstallChocolateyPathCommand.cs" />
6566
<Compile Include="Commands\SetEnvironmentVariableCommand.cs" />
6667
<Compile Include="Commands\TestProcessAdminRightsCommand.cs" />
6768
<Compile Include="Commands\UninstallChocolateyPathCommand.cs" />
6869
<Compile Include="Commands\UpdateSessionEnvironmentCommand.cs" />
6970
<Compile Include="Helpers\Elevation.cs" />
7071
<Compile Include="Helpers\EnvironmentHelper.cs" />
72+
<Compile Include="Helpers\PackageParameter.cs" />
7173
<Compile Include="Helpers\Paths.cs" />
7274
<Compile Include="Helpers\ProcessInformation.cs" />
7375
<Compile Include="Helpers\PSHelper.cs" />
Lines changed: 29 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,182 +1,43 @@
1-
using Chocolatey.PowerShell.Shared;
2-
using System;
3-
using System.Collections;
4-
using System.Collections.Generic;
5-
using System.Management.Automation;
6-
using System.Text;
7-
using System.Text.RegularExpressions;
8-
1+
// Copyright © 2017 - 2025 Chocolatey Software, Inc
2+
// Copyright © 2011 - 2017 RealDimensions Software, LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
//
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
using Chocolatey.PowerShell.Shared;
18+
using System.Collections;
19+
using System.Management.Automation;
20+
using Chocolatey.PowerShell.Helpers;
21+
922
namespace Chocolatey.PowerShell.Commands
10-
{
23+
{
24+
/// <summary>
25+
/// Parses a string and returns a hash table array of those values for use in package scripts.
26+
/// </summary>
27+
/// <param name="Parameters">A string containing parameters to be parsed.</param>
28+
/// <returns>A hashtable of parameters that have been passed to <paramref name="Parameters"> and parsed.</returns>
1129
[Cmdlet(VerbsCommon.Get, "PackageParameter")]
30+
[Alias("Get-PackageParameters")]
1231
[OutputType(typeof(Hashtable))]
1332
public class GetPackageParameterCommand : ChocolateyCmdlet
1433
{
15-
/*
16-
.SYNOPSIS
17-
Parses a string and returns a hash table array of those values for use
18-
in package scripts.
19-
20-
.DESCRIPTION
21-
This looks at a string value and parses it into a hash table array for
22-
use in package scripts. By default this will look at
23-
`$env:ChocolateyPackageParameters` (`--params="'/ITEM:value'"`) and
24-
`$env:ChocolateyPackageParametersSensitive`
25-
(`--package-parameters-sensitive="'/PASSWORD:value'"` in commercial
26-
editions).
27-
28-
Learn more about using this at https://docs.chocolatey.org/en-us/guides/create/parse-packageparameters-argument
29-
30-
.NOTES
31-
If you need compatibility with older versions of Chocolatey,
32-
take a dependency on the `chocolatey-core.extension` package which
33-
also provides this functionality. If you are pushing to the community
34-
package repository (https://community.chocolatey.org/packages), you are required
35-
to take a dependency on the core extension until January 2018. How to
36-
do this is explained at https://docs.chocolatey.org/en-us/guides/create/parse-packageparameters-argument#step-3---use-core-community-extension.
37-
38-
The differences between this and the `chocolatey-core.extension` package
39-
functionality is that the extension function can only do one string at a
40-
time and it only looks at `$env:ChocolateyPackageParameters` by default.
41-
It also only supports splitting by `:`, with this function you can
42-
either split by `:` or `=`. For compatibility with the core extension,
43-
build all docs with `/Item:Value`.
44-
45-
.INPUTS
46-
None
47-
48-
.OUTPUTS
49-
[HashTable]
50-
51-
.PARAMETER Parameters
52-
OPTIONAL - Specify a string to parse. If not set, will use
53-
`$env:ChocolateyPackageParameters` and
54-
`$env:ChocolateyPackageParametersSensitive` to parse values from.
55-
56-
Parameters should be passed as "/NAME:value" or "/NAME=value". For
57-
compatibility with `chocolatey-core.extension`, use `:`.
58-
59-
For example `-Parameters "/ITEM1:value /ITEM2:value with spaces"
60-
61-
To maintain compatibility with the prior art of the chocolatey-core.extension
62-
function by the same name, quotes and apostrophes surrounding
63-
parameter values will be removed. When the param is used, those items
64-
can be added back if desired, but it's most important to ensure that
65-
existing packages are compatible on upgrade.
66-
67-
.PARAMETER IgnoredArguments
68-
Allows splatting with arguments that do not apply and future expansion.
69-
Do not use directly.
70-
71-
.EXAMPLE
72-
>
73-
# The default way of calling, uses `$env:ChocolateyPackageParameters`
74-
# and `$env:ChocolateyPackageParametersSensitive` - this is typically
75-
# how things are passed in from choco.exe
76-
$pp = Get-PackageParameters
77-
78-
.EXAMPLE
79-
>
80-
# see https://docs.chocolatey.org/en-us/guides/create/parse-packageparameters-argument
81-
# command line call: `choco install <pkg_id> --params "'/LICENSE:value'"`
82-
$pp = Get-PackageParameters
83-
# Read-Host, PromptForChoice, etc are not blocking calls with Chocolatey.
84-
# Chocolatey has a custom PowerShell host that will time these calls
85-
# after 30 seconds, allowing headless operation to continue but offer
86-
# prompts to users to ask questions during installation.
87-
if (!$pp['LICENSE']) { $pp['LICENSE'] = Read-Host 'License key?' }
88-
# set a default if not passed
89-
if (!$pp['LICENSE']) { $pp['LICENSE'] = '1234' }
90-
91-
.EXAMPLE
92-
>
93-
$pp = Get-PackageParameters
94-
if (!$pp['UserName']) { $pp['UserName'] = "$env:UserName" }
95-
if (!$pp['Password']) { $pp['Password'] = Read-Host "Enter password for $($pp['UserName']):" -AsSecureString}
96-
# fail the install/upgrade if not value is not determined
97-
if (!$pp['Password']) { throw "Package needs Password to install, that must be provided in params or in prompt." }
98-
99-
.EXAMPLE
100-
>
101-
# Pass in your own values
102-
Get-PackageParameters -Parameters "/Shortcut /InstallDir:'c:\program files\xyz' /NoStartup" | set r
103-
if ($r.Shortcut) {... }
104-
Write-Host $r.InstallDir
105-
106-
.LINK
107-
Install-ChocolateyPackage
108-
109-
.LINK
110-
Install-ChocolateyInstallPackage
111-
112-
.LINK
113-
Install-ChocolateyZipPackage
114-
*/
115-
116-
private const string PackageParameterPattern = @"(?:^|\s+)\/(?<ItemKey>[^\:\=\s)]+)(?:(?:\:|=){1}(?:\''|\""){0,1}(?<ItemValue>.*?)(?:\''|\""){0,1}(?:(?=\s+\/)|$))?";
117-
private static readonly Regex _packageParameterRegex = new Regex(PackageParameterPattern, RegexOptions.Compiled);
118-
11934
[Parameter(Position = 0)]
12035
[Alias("Params")]
12136
public string Parameters { get; set; } = string.Empty;
12237

12338
protected override void End()
12439
{
125-
var paramStrings = new List<string>();
126-
var logParams = true;
127-
128-
if (!string.IsNullOrEmpty(Parameters))
129-
{
130-
paramStrings.Add(Parameters);
131-
}
132-
else
133-
{
134-
WriteDebug("Parsing $env:ChocolateyPackageParameters and $env:ChocolateyPackageParametersSensitive for parameters");
135-
136-
var packageParams = EnvironmentVariable(EnvironmentVariables.ChocolateyPackageParameters);
137-
if (!string.IsNullOrEmpty(packageParams))
138-
{
139-
paramStrings.Add(packageParams);
140-
}
141-
142-
var sensitiveParams = EnvironmentVariable(EnvironmentVariables.ChocolateyPackageParametersSensitive);
143-
if (!string.IsNullOrEmpty(sensitiveParams))
144-
{
145-
logParams = false;
146-
WriteDebug("Sensitive parameters detected, no logging of parameters.");
147-
paramStrings.Add(sensitiveParams);
148-
}
149-
}
150-
151-
var paramHash = new Hashtable(StringComparer.OrdinalIgnoreCase);
152-
153-
foreach (var param in paramStrings)
154-
{
155-
foreach (Match match in _packageParameterRegex.Matches(param))
156-
{
157-
var name = match.Groups["ItemKey"].Value.Trim();
158-
var valueGroup = match.Groups["ItemValue"];
159-
160-
object value;
161-
if (valueGroup.Success)
162-
{
163-
value = valueGroup.Value.Trim();
164-
}
165-
else
166-
{
167-
value = (object)true;
168-
}
169-
170-
if (logParams)
171-
{
172-
WriteDebug($"Adding package param '{name}'='{value}'");
173-
}
174-
175-
paramHash[name] = value;
176-
}
177-
}
178-
179-
WriteObject(paramHash);
40+
WriteObject(PackageParameter.GetParameters(this, Parameters));
18041
}
18142
}
18243
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright © 2017 - 2025 Chocolatey Software, Inc
2+
// Copyright © 2011 - 2017 RealDimensions Software, LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
//
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
using System;
18+
using System.Collections;
19+
using System.Collections.Generic;
20+
using System.Linq;
21+
using System.Management.Automation;
22+
using System.Management.Automation.Language;
23+
using Chocolatey.PowerShell.Helpers;
24+
using Chocolatey.PowerShell.Shared;
25+
26+
namespace Chocolatey.PowerShell.Commands
27+
{
28+
/// <summary>
29+
/// Parses a script and returns a hash table of parameters that are present in the package params, along with their values.
30+
/// </summary>
31+
/// <param name="ScriptPath">A path to a script to parse parameters from.</param>
32+
/// <param name="Parameters">A string containing parameters to be parsed.</param>
33+
/// <returns>A hashtable of parameters present in <paramref name="ScriptPath"> and also in <paramref name="Parameters"> (or the envvar).</returns>
34+
[Cmdlet(VerbsCommon.Get, "PackageScriptParameters")]
35+
[OutputType(typeof(Hashtable))]
36+
public class GetScriptParametersCommand : ChocolateyCmdlet
37+
{
38+
[Parameter(Mandatory = true, Position = 0)]
39+
public string ScriptPath { get; set; }
40+
41+
[Parameter(Mandatory = false, Position = 1)]
42+
public string Parameters { get; set; } = string.Empty;
43+
44+
protected override void End()
45+
{
46+
var packageParameters = PackageParameter.GetParameters(this, Parameters);
47+
var splatHash = new Hashtable(StringComparer.OrdinalIgnoreCase);
48+
49+
// Check what parameters the script has
50+
Token[] tokensRef = null;
51+
ParseError[] errorsRef = null;
52+
var parsedAst = Parser.ParseFile(ScriptPath, out tokensRef, out errorsRef);
53+
var scriptParameters = parsedAst.ParamBlock != null ? parsedAst.ParamBlock.Parameters.Select(p => p.Name.VariablePath.UserPath.ToString()).ToList() : new List<string>();
54+
WriteVerbose($"Found {scriptParameters.Count()} parameter(s) in '{ScriptPath}'");
55+
56+
// For each of those in PackageParameters, add it to the splat
57+
foreach (var parameter in scriptParameters)
58+
{
59+
if (packageParameters.ContainsKey(parameter))
60+
{
61+
splatHash.Add(parameter, packageParameters[parameter]);
62+
}
63+
}
64+
65+
// Return the splat
66+
WriteObject(splatHash);
67+
}
68+
}
69+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright © 2017 - 2025 Chocolatey Software, Inc
2+
// Copyright © 2011 - 2017 RealDimensions Software, LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
//
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
using System;
18+
using System.Collections;
19+
using System.Collections.Generic;
20+
using System.Management.Automation;
21+
using System.Text.RegularExpressions;
22+
23+
namespace Chocolatey.PowerShell.Helpers
24+
{
25+
public static class PackageParameter
26+
{
27+
private const string PackageParameterPattern = @"(?:^|\s+)\/(?<ItemKey>[^\:\=\s)]+)(?:(?:\:|=){1}(?:\'|\""){0,1}(?<ItemValue>.*?)(?:\'|\""){0,1}(?:(?=\s+\/)|$))?";
28+
private static readonly Regex _packageParameterRegex = new Regex(PackageParameterPattern, RegexOptions.Compiled);
29+
30+
public static Hashtable GetParameters(PSCmdlet cmdlet, string parameters)
31+
{
32+
var paramStrings = new List<string>();
33+
var logParams = true;
34+
35+
if (!string.IsNullOrEmpty(parameters))
36+
{
37+
paramStrings.Add(parameters);
38+
}
39+
else
40+
{
41+
var packageParameters = EnvironmentHelper.GetVariable(
42+
cmdlet,
43+
"ChocolateyPackageParameters",
44+
EnvironmentVariableTarget.Process);
45+
if (!string.IsNullOrEmpty(packageParameters))
46+
{
47+
paramStrings.Add(packageParameters);
48+
}
49+
50+
// This should possibly only be implemented in the CLE codebase
51+
var sensitivePackageParameters = EnvironmentHelper.GetVariable(
52+
cmdlet,
53+
"ChocolateyPackageParametersSensitive",
54+
EnvironmentVariableTarget.Process);
55+
if (!string.IsNullOrEmpty(sensitivePackageParameters))
56+
{
57+
logParams = false;
58+
paramStrings.Add(sensitivePackageParameters);
59+
}
60+
}
61+
62+
var paramHash = new Hashtable(StringComparer.OrdinalIgnoreCase);
63+
64+
foreach (var param in paramStrings)
65+
{
66+
foreach (Match match in _packageParameterRegex.Matches(param))
67+
{
68+
var name = match.Groups["ItemKey"].Value.Trim();
69+
var valueGroup = match.Groups["ItemValue"];
70+
71+
object value;
72+
if (valueGroup.Success)
73+
{
74+
value = valueGroup.Value.Trim();
75+
}
76+
else
77+
{
78+
value = (object)true;
79+
}
80+
81+
if (logParams)
82+
{
83+
cmdlet.WriteDebug($"Adding package param '{name}'='{value}'");
84+
}
85+
86+
paramHash[name] = value;
87+
}
88+
}
89+
90+
return paramHash;
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)