Skip to content

Commit 6bbdc0c

Browse files
authored
Bugfix: Update-PSScriptFileInfo should populate all #Requires lines/properties (#1863)
1 parent 1884d13 commit 6bbdc0c

File tree

3 files changed

+186
-12
lines changed

3 files changed

+186
-12
lines changed

src/code/PSScriptRequires.cs

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,36 @@ public sealed class PSScriptRequires
1919
#region Properties
2020

2121
/// <summary>
22-
/// The list of modules required by the script.
22+
/// The modules this script requires, specified like: #requires -Module NetAdapter#requires -Module @{Name="NetAdapter"; Version="1.0.0.0"}
2323
/// Hashtable keys: GUID, MaxVersion, ModuleName (Required), RequiredVersion, Version.
2424
/// </summary>
2525
public ModuleSpecification[] RequiredModules { get; private set; } = Array.Empty<ModuleSpecification>();
2626

27+
/// <summary>
28+
/// Specifies if this script requires elevated privileges, specified like: #requires -RunAsAdministrator
29+
/// </summary>
30+
public bool IsElevationRequired { get; private set; }
31+
32+
/// <summary>
33+
/// The application id this script requires, specified like: #requires -Shellid Shell
34+
/// </summary>
35+
public string RequiredApplicationId { get; private set; }
36+
37+
/// <summary>
38+
/// The assemblies this script requires, specified like: #requires -Assembly path\to\foo.dll#requires -Assembly "System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
39+
/// </summary>
40+
public string[] RequiredAssemblies { get; private set; } = Utils.EmptyStrArray;
41+
42+
/// <summary>
43+
/// The PowerShell Edition this script requires, specified like: #requires -PSEdition Desktop
44+
/// </summary>
45+
public string[] RequiredPSEditions { get; private set; } = Utils.EmptyStrArray;
46+
47+
/// <summary>
48+
/// The PowerShell version this script requires, specified like: #requires -Version 3
49+
/// </summary>
50+
public Version RequiredPSVersion { get; private set; }
51+
2752
#endregion
2853

2954
#region Constructor
@@ -72,15 +97,15 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error
7297
requiresComment,
7398
out Token[] tokens,
7499
out ParseError[] parserErrors);
75-
100+
76101
if (parserErrors.Length > 0)
77102
{
78103
foreach (ParseError err in parserErrors)
79104
{
80105
errorsList.Add(new ErrorRecord(
81-
new InvalidOperationException($"Could not requires comments as valid PowerShell input due to {err.Message}."),
82-
err.ErrorId,
83-
ErrorCategory.ParserError,
106+
new InvalidOperationException($"Could not requires comments as valid PowerShell input due to {err.Message}."),
107+
err.ErrorId,
108+
ErrorCategory.ParserError,
84109
null));
85110
}
86111

@@ -92,20 +117,51 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error
92117
ScriptRequirements parsedScriptRequirements = ast.ScriptRequirements;
93118
ReadOnlyCollection<ModuleSpecification> parsedModules = new List<ModuleSpecification>().AsReadOnly();
94119

95-
if (parsedScriptRequirements != null && parsedScriptRequirements.RequiredModules != null)
120+
if (parsedScriptRequirements != null)
96121
{
97-
RequiredModules = parsedScriptRequirements.RequiredModules.ToArray();
122+
// System.Management.Automation.Language.ScriptRequirements properties are listed here:
123+
// https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.language.scriptrequirements?view=powershellsdk-7.4.0
124+
125+
if (parsedScriptRequirements.IsElevationRequired)
126+
{
127+
IsElevationRequired = true;
128+
}
129+
130+
if (parsedScriptRequirements.RequiredApplicationId != null)
131+
{
132+
RequiredApplicationId = parsedScriptRequirements.RequiredApplicationId;
133+
}
134+
135+
if (parsedScriptRequirements.RequiredAssemblies != null)
136+
{
137+
RequiredAssemblies = parsedScriptRequirements.RequiredAssemblies.ToArray();
138+
}
139+
140+
if (parsedScriptRequirements.RequiredModules != null)
141+
{
142+
RequiredModules = parsedScriptRequirements.RequiredModules.ToArray();
143+
}
144+
145+
if (parsedScriptRequirements.RequiredPSEditions != null)
146+
{
147+
RequiredPSEditions = parsedScriptRequirements.RequiredPSEditions.ToArray();
148+
}
149+
150+
if (parsedScriptRequirements.RequiredPSVersion != null)
151+
{
152+
RequiredPSVersion = parsedScriptRequirements.RequiredPSVersion;
153+
}
98154
}
99155
}
100156
catch (Exception e)
101157
{
102158
errorsList.Add(new ErrorRecord(
103-
new ArgumentException($"Parsing RequiredModules failed due to {e.Message}"),
104-
"requiredModulesAstParseThrewError",
105-
ErrorCategory.ParserError,
159+
new ArgumentException($"Parsing RequiredModules failed due to {e.Message}"),
160+
"requiredModulesAstParseThrewError",
161+
ErrorCategory.ParserError,
106162
null));
107163
errors = errorsList.ToArray();
108-
164+
109165
return false;
110166
}
111167

@@ -118,14 +174,50 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error
118174
internal string[] EmitContent()
119175
{
120176
List<string> psRequiresLines = new List<string>();
177+
if (IsElevationRequired)
178+
{
179+
psRequiresLines.Add(String.Empty);
180+
psRequiresLines.Add("#Requires -RunAsAdministrator");
181+
}
182+
183+
if (!String.IsNullOrEmpty(RequiredApplicationId))
184+
{
185+
psRequiresLines.Add(String.Empty);
186+
psRequiresLines.Add(String.Format("#Requires -ShellId {0}", RequiredApplicationId));
187+
}
188+
189+
if (RequiredAssemblies.Length > 0)
190+
{
191+
psRequiresLines.Add(String.Empty);
192+
foreach (string assembly in RequiredAssemblies)
193+
{
194+
psRequiresLines.Add(String.Format("#Requires -Assembly {0}", assembly));
195+
}
196+
}
197+
198+
if (RequiredPSEditions.Length > 0)
199+
{
200+
psRequiresLines.Add(String.Empty);
201+
foreach (string psEdition in RequiredPSEditions)
202+
{
203+
psRequiresLines.Add(String.Format("#Requires -PSEdition {0}", psEdition));
204+
}
205+
}
206+
207+
if (RequiredPSVersion != null)
208+
{
209+
psRequiresLines.Add(String.Empty);
210+
psRequiresLines.Add(String.Format("#Requires -Version {0}", RequiredPSVersion.ToString()));
211+
}
212+
121213
if (RequiredModules.Length > 0)
122214
{
123215
psRequiresLines.Add(String.Empty);
124216
foreach (ModuleSpecification moduleSpec in RequiredModules)
125217
{
126218
psRequiresLines.Add(String.Format("#Requires -Module {0}", moduleSpec.ToString()));
127219
}
128-
220+
129221
psRequiresLines.Add(String.Empty);
130222
}
131223

test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,34 @@ Describe "Test Update-PSScriptFileInfo" -tags 'CI' {
264264
$results -like "*#Requires*ModuleName*Version*" | Should -BeTrue
265265
}
266266

267+
It "update script file with varying Required properties (IsElevationRequired, RequiredApplicationId, RequiredAssembliesRequiredPSEditions, RequiredPSVersion) should retain those Require statements" {
268+
$testScriptWithRequiredProperties = Join-Path -Path $script:testScriptsFolderPath -ChildPath "ScriptWithAllRequiresProperties.ps1"
269+
Update-PSScriptFileInfo -Path $testScriptWithRequiredProperties -Version "2.0.0.0"
270+
Test-PSScriptFileInfo $testScriptWithRequiredProperties | Should -Be $true
271+
272+
$requiredApplicationId = "Shell"
273+
$requiredAssemblies = @("path\to\foo.dll")
274+
$requiredPSEditions = @("Desktop")
275+
$requiredPSVersion = "5.1"
276+
277+
Test-Path -Path $testScriptWithRequiredProperties | Should -BeTrue
278+
$results = Get-Content -Path $testScriptWithRequiredProperties -Raw
279+
$results.Contains("#Requires -RunAsAdministrator") | Should -BeTrue
280+
$results -like "*#Requires -ShellId*" | Should -BeTrue
281+
$results -like "*#Requires*Assembly*" | Should -BeTrue
282+
$results -like "*#Requires*PSEdition*" | Should -BeTrue
283+
$results -like "*#Requires*Version*" | Should -BeTrue
284+
285+
$scriptFileObj = Get-PSScriptFileInfo -Path $testScriptWithRequiredProperties
286+
$scriptFileObj.ScriptRequiresComment.RequiredModules[0] | Should -Be "Microsoft.PowerShell.PSResourceGet"
287+
$scriptFileObj.ScriptRequiresComment.IsElevationRequired | Should -Be $true
288+
$scriptFileObj.ScriptRequiresComment.RequiredApplicationId | Should -Be $requiredApplicationId
289+
$scriptFileObj.ScriptRequiresComment.RequiredAssemblies | Should -Be $requiredAssemblies
290+
$scriptFileObj.ScriptRequiresComment.RequiredPSEditions | Should -Be $requiredPSEditions
291+
$scriptFileObj.ScriptRequiresComment.RequiredPSVersion | Should -Be $requiredPSVersion
292+
$scriptFileObj.ScriptMetadataComment.Version | Should -Be "2.0.0.0"
293+
}
294+
267295
It "update script file RequiredScripts property" {
268296
$requiredScript1 = "RequiredScript1"
269297
$requiredScript2 = "RequiredScript2"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<#PSScriptInfo
2+
3+
.VERSION 2.0.0.0
4+
5+
.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd
6+
7+
.AUTHOR annavied
8+
9+
.COMPANYNAME
10+
11+
.COPYRIGHT
12+
13+
.TAGS
14+
15+
.LICENSEURI
16+
17+
.PROJECTURI
18+
19+
.ICONURI
20+
21+
.EXTERNALMODULEDEPENDENCIES
22+
23+
.REQUIREDSCRIPTS
24+
25+
.EXTERNALSCRIPTDEPENDENCIES
26+
27+
.RELEASENOTES
28+
29+
30+
.PRIVATEDATA
31+
32+
33+
#>
34+
35+
#Requires -RunAsAdministrator
36+
37+
#Requires -ShellId Shell
38+
39+
#Requires -Assembly path\to\foo.dll
40+
41+
#Requires -PSEdition Desktop
42+
43+
#Requires -Version 5.1
44+
45+
#Requires -Module Microsoft.PowerShell.PSResourceGet
46+
47+
<#
48+
49+
.DESCRIPTION
50+
This is a test script
51+
52+
.SYNOPSIS
53+
Test the Update-PSScriptFileInfo cmdlet
54+
#>

0 commit comments

Comments
 (0)