diff --git a/src/code/PSScriptRequires.cs b/src/code/PSScriptRequires.cs index c9d34105c..b71c3b0cf 100644 --- a/src/code/PSScriptRequires.cs +++ b/src/code/PSScriptRequires.cs @@ -19,11 +19,36 @@ public sealed class PSScriptRequires #region Properties /// - /// 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. /// public ModuleSpecification[] RequiredModules { get; private set; } = Array.Empty(); + /// + /// Specifies if this script requires elevated privileges, specified like: #requires -RunAsAdministrator + /// + public bool IsElevationRequired { get; private set; } + + /// + /// The application id this script requires, specified like: #requires -Shellid Shell + /// + public string RequiredApplicationId { get; private set; } + + /// + /// 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" + /// + public string[] RequiredAssemblies { get; private set; } = Utils.EmptyStrArray; + + /// + /// The PowerShell Edition this script requires, specified like: #requires -PSEdition Desktop + /// + public string[] RequiredPSEditions { get; private set; } = Utils.EmptyStrArray; + + /// + /// The PowerShell version this script requires, specified like: #requires -Version 3 + /// + public Version RequiredPSVersion { get; private set; } + #endregion #region Constructor @@ -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)); } @@ -92,20 +117,51 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error ScriptRequirements parsedScriptRequirements = ast.ScriptRequirements; ReadOnlyCollection parsedModules = new List().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; } @@ -118,6 +174,42 @@ internal bool ParseContentIntoObj(string[] commentLines, out ErrorRecord[] error internal string[] EmitContent() { List psRequiresLines = new List(); + 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); @@ -125,7 +217,7 @@ internal string[] EmitContent() { psRequiresLines.Add(String.Format("#Requires -Module {0}", moduleSpec.ToString())); } - + psRequiresLines.Add(String.Empty); } diff --git a/test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1 b/test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1 index 96776db3d..c7c452a43 100644 --- a/test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1 +++ b/test/PSScriptFileInfoTests/UpdatePSScriptFileInfo.Tests.ps1 @@ -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" diff --git a/test/testFiles/testScripts/ScriptWithAllRequiresProperties.ps1 b/test/testFiles/testScripts/ScriptWithAllRequiresProperties.ps1 new file mode 100644 index 000000000..dcea90b65 --- /dev/null +++ b/test/testFiles/testScripts/ScriptWithAllRequiresProperties.ps1 @@ -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 +#>