Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 104 additions & 12 deletions src/code/PSScriptRequires.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,36 @@ public sealed class PSScriptRequires
#region Properties

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

/// <summary>
/// Specifies if this script requires elevated privileges, specified like: #requires -RunAsAdministrator
/// </summary>
public bool IsElevationRequired { get; private set; }

/// <summary>
/// The application id this script requires, specified like: #requires -Shellid Shell
/// </summary>
public string RequiredApplicationId { get; private set; }

/// <summary>
/// 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"
/// </summary>
public string[] RequiredAssemblies { get; private set; } = Utils.EmptyStrArray;

/// <summary>
/// The PowerShell Edition this script requires, specified like: #requires -PSEdition Desktop
/// </summary>
public string[] RequiredPSEditions { get; private set; } = Utils.EmptyStrArray;

/// <summary>
/// The PowerShell version this script requires, specified like: #requires -Version 3
/// </summary>
public Version RequiredPSVersion { get; private set; }

#endregion

#region Constructor
Expand Down Expand Up @@ -72,15 +97,15 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error
requiresComment,
out Token[] tokens,
out ParseError[] parserErrors);

if (parserErrors.Length > 0)
{
foreach (ParseError err in parserErrors)
{
errorsList.Add(new ErrorRecord(
new InvalidOperationException($"Could not requires comments as valid PowerShell input due to {err.Message}."),
err.ErrorId,
ErrorCategory.ParserError,
new InvalidOperationException($"Could not requires comments as valid PowerShell input due to {err.Message}."),
err.ErrorId,
ErrorCategory.ParserError,
null));
}

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

if (parsedScriptRequirements != null && parsedScriptRequirements.RequiredModules != null)
if (parsedScriptRequirements != null)
{
RequiredModules = parsedScriptRequirements.RequiredModules.ToArray();
// System.Management.Automation.Language.ScriptRequirements properties are listed here:
// https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.language.scriptrequirements?view=powershellsdk-7.4.0

if (parsedScriptRequirements.IsElevationRequired)
{
IsElevationRequired = true;
}

if (parsedScriptRequirements.RequiredApplicationId != null)
{
RequiredApplicationId = parsedScriptRequirements.RequiredApplicationId;
}

if (parsedScriptRequirements.RequiredAssemblies != null)
{
RequiredAssemblies = parsedScriptRequirements.RequiredAssemblies.ToArray();
}

if (parsedScriptRequirements.RequiredModules != null)
{
RequiredModules = parsedScriptRequirements.RequiredModules.ToArray();
}

if (parsedScriptRequirements.RequiredPSEditions != null)
{
RequiredPSEditions = parsedScriptRequirements.RequiredPSEditions.ToArray();
}

if (parsedScriptRequirements.RequiredPSVersion != null)
{
RequiredPSVersion = parsedScriptRequirements.RequiredPSVersion;
}
}
}
catch (Exception e)
{
errorsList.Add(new ErrorRecord(
new ArgumentException($"Parsing RequiredModules failed due to {e.Message}"),
"requiredModulesAstParseThrewError",
ErrorCategory.ParserError,
new ArgumentException($"Parsing RequiredModules failed due to {e.Message}"),
"requiredModulesAstParseThrewError",
ErrorCategory.ParserError,
null));
errors = errorsList.ToArray();

return false;
}

Expand All @@ -118,14 +174,50 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error
internal string[] EmitContent()
{
List<string> psRequiresLines = new List<string>();
if (IsElevationRequired)
{
psRequiresLines.Add(String.Empty);
psRequiresLines.Add("#Requires -RunAsAdministrator");
}

if (!String.IsNullOrEmpty(RequiredApplicationId))
{
psRequiresLines.Add(String.Empty);
psRequiresLines.Add(String.Format("#Requires -ShellId {0}", RequiredApplicationId));
}

if (RequiredAssemblies.Length > 0)
{
psRequiresLines.Add(String.Empty);
foreach (string assembly in RequiredAssemblies)
{
psRequiresLines.Add(String.Format("#Requires -Assembly {0}", assembly));
}
}

if (RequiredPSEditions.Length > 0)
{
psRequiresLines.Add(String.Empty);
foreach (string psEdition in RequiredPSEditions)
{
psRequiresLines.Add(String.Format("#Requires -PSEdition {0}", psEdition));
}
}

if (RequiredPSVersion != null)
{
psRequiresLines.Add(String.Empty);
psRequiresLines.Add(String.Format("#Requires -Version {0}", RequiredPSVersion.ToString()));
}

if (RequiredModules.Length > 0)
{
psRequiresLines.Add(String.Empty);
foreach (ModuleSpecification moduleSpec in RequiredModules)
{
psRequiresLines.Add(String.Format("#Requires -Module {0}", moduleSpec.ToString()));
}

psRequiresLines.Add(String.Empty);
}

Expand Down
28 changes: 28 additions & 0 deletions test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,34 @@ Describe "Test Update-PSScriptFileInfo" -tags 'CI' {
$results -like "*#Requires*ModuleName*Version*" | Should -BeTrue
}

It "update script file with varying Required properties (IsElevationRequired, RequiredApplicationId, RequiredAssembliesRequiredPSEditions, RequiredPSVersion) should retain those Require statements" {
$testScriptWithRequiredProperties = Join-Path -Path $script:testScriptsFolderPath -ChildPath "ScriptWithAllRequiresProperties.ps1"
Update-PSScriptFileInfo -Path $testScriptWithRequiredProperties -Version "2.0.0.0"
Test-PSScriptFileInfo $testScriptWithRequiredProperties | Should -Be $true

$requiredApplicationId = "Shell"
$requiredAssemblies = @("path\to\foo.dll")
$requiredPSEditions = @("Desktop")
$requiredPSVersion = "5.1"

Test-Path -Path $testScriptWithRequiredProperties | Should -BeTrue
$results = Get-Content -Path $testScriptWithRequiredProperties -Raw
$results.Contains("#Requires -RunAsAdministrator") | Should -BeTrue
$results -like "*#Requires -ShellId*" | Should -BeTrue
$results -like "*#Requires*Assembly*" | Should -BeTrue
$results -like "*#Requires*PSEdition*" | Should -BeTrue
$results -like "*#Requires*Version*" | Should -BeTrue

$scriptFileObj = Get-PSScriptFileInfo -Path $testScriptWithRequiredProperties
$scriptFileObj.ScriptRequiresComment.RequiredModules[0] | Should -Be "Microsoft.PowerShell.PSResourceGet"
$scriptFileObj.ScriptRequiresComment.IsElevationRequired | Should -Be $true
$scriptFileObj.ScriptRequiresComment.RequiredApplicationId | Should -Be $requiredApplicationId
$scriptFileObj.ScriptRequiresComment.RequiredAssemblies | Should -Be $requiredAssemblies
$scriptFileObj.ScriptRequiresComment.RequiredPSEditions | Should -Be $requiredPSEditions
$scriptFileObj.ScriptRequiresComment.RequiredPSVersion | Should -Be $requiredPSVersion
$scriptFileObj.ScriptMetadataComment.Version | Should -Be "2.0.0.0"
}

It "update script file RequiredScripts property" {
$requiredScript1 = "RequiredScript1"
$requiredScript2 = "RequiredScript2"
Expand Down
54 changes: 54 additions & 0 deletions test/testFiles/testScripts/ScriptWithAllRequiresProperties.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<#PSScriptInfo

.VERSION 2.0.0.0

.GUID 3951be04-bd06-4337-8dc3-a620bf539fbd

.AUTHOR annavied

.COMPANYNAME

.COPYRIGHT

.TAGS

.LICENSEURI

.PROJECTURI

.ICONURI

.EXTERNALMODULEDEPENDENCIES

.REQUIREDSCRIPTS

.EXTERNALSCRIPTDEPENDENCIES

.RELEASENOTES


.PRIVATEDATA


#>

#Requires -RunAsAdministrator

#Requires -ShellId Shell

#Requires -Assembly path\to\foo.dll

#Requires -PSEdition Desktop

#Requires -Version 5.1

#Requires -Module Microsoft.PowerShell.PSResourceGet

<#

.DESCRIPTION
This is a test script

.SYNOPSIS
Test the Update-PSScriptFileInfo cmdlet
#>
Loading