mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Fix parameter completion when script requirements fail (#17687)
This commit is contained in:
@@ -1198,7 +1198,7 @@ namespace System.Management.Automation.Language
|
||||
string commandName = null;
|
||||
try
|
||||
{
|
||||
processor = PrepareFromAst(context, out commandName) ?? context.CreateCommand(commandName, dotSource);
|
||||
processor = PrepareFromAst(context, out commandName) ?? context.CreateCommand(commandName, dotSource, forCompletion:true);
|
||||
}
|
||||
catch (RuntimeException)
|
||||
{
|
||||
|
||||
@@ -262,6 +262,9 @@ namespace System.Management.Automation
|
||||
/// False if not. Null if command discovery should default to something reasonable
|
||||
/// for the command discovered.
|
||||
/// </param>
|
||||
/// <param name="forCompletion">
|
||||
/// True if this for parameter completion and script requirements should be ignored.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// </returns>
|
||||
/// <exception cref="CommandNotFoundException">
|
||||
@@ -271,14 +274,15 @@ namespace System.Management.Automation
|
||||
/// If the security manager is preventing the command from running.
|
||||
/// </exception>
|
||||
internal CommandProcessorBase LookupCommandProcessor(string commandName,
|
||||
CommandOrigin commandOrigin, bool? useLocalScope)
|
||||
CommandOrigin commandOrigin, bool? useLocalScope, bool forCompletion = false)
|
||||
{
|
||||
CommandProcessorBase processor = null;
|
||||
CommandInfo commandInfo = LookupCommandInfo(commandName, commandOrigin);
|
||||
|
||||
if (commandInfo != null)
|
||||
{
|
||||
processor = LookupCommandProcessor(commandInfo, commandOrigin, useLocalScope, null);
|
||||
processor = LookupCommandProcessor(commandInfo, commandOrigin, useLocalScope, null, forCompletion);
|
||||
|
||||
// commandInfo.Name might be different than commandName - restore the original invocation name
|
||||
processor.Command.MyInvocation.InvocationName = commandName;
|
||||
}
|
||||
@@ -286,7 +290,7 @@ namespace System.Management.Automation
|
||||
return processor;
|
||||
}
|
||||
|
||||
internal static void VerifyRequiredModules(ExternalScriptInfo scriptInfo, ExecutionContext context)
|
||||
internal static void VerifyRequiredModules(ExternalScriptInfo scriptInfo, ExecutionContext context, bool forCompletion = false)
|
||||
{
|
||||
// Check Required Modules
|
||||
if (scriptInfo.RequiresModules != null)
|
||||
@@ -301,7 +305,7 @@ namespace System.Management.Automation
|
||||
moduleManifestPath: null,
|
||||
manifestProcessingFlags: ModuleCmdletBase.ManifestProcessingFlags.LoadElements | ModuleCmdletBase.ManifestProcessingFlags.WriteErrors,
|
||||
error: out error);
|
||||
if (error != null)
|
||||
if (!forCompletion && error is not null)
|
||||
{
|
||||
ScriptRequiresException scriptRequiresException =
|
||||
new ScriptRequiresException(
|
||||
@@ -316,9 +320,9 @@ namespace System.Management.Automation
|
||||
}
|
||||
}
|
||||
|
||||
private CommandProcessorBase CreateScriptProcessorForSingleShell(ExternalScriptInfo scriptInfo, ExecutionContext context, bool useLocalScope, SessionStateInternal sessionState)
|
||||
private CommandProcessorBase CreateScriptProcessorForSingleShell(ExternalScriptInfo scriptInfo, ExecutionContext context, bool useLocalScope, SessionStateInternal sessionState, bool forCompletion = false)
|
||||
{
|
||||
VerifyScriptRequirements(scriptInfo, Context);
|
||||
VerifyScriptRequirements(scriptInfo, Context, forCompletion);
|
||||
|
||||
if (!string.IsNullOrEmpty(scriptInfo.RequiresApplicationID))
|
||||
{
|
||||
@@ -340,12 +344,18 @@ namespace System.Management.Automation
|
||||
// #Requires -PSVersion
|
||||
// #Requires -PSEdition
|
||||
// #Requires -Module
|
||||
internal static void VerifyScriptRequirements(ExternalScriptInfo scriptInfo, ExecutionContext context)
|
||||
internal static void VerifyScriptRequirements(ExternalScriptInfo scriptInfo, ExecutionContext context, bool forCompletion = false)
|
||||
{
|
||||
VerifyElevatedPrivileges(scriptInfo);
|
||||
VerifyPSVersion(scriptInfo);
|
||||
VerifyPSEdition(scriptInfo);
|
||||
VerifyRequiredModules(scriptInfo, context);
|
||||
// When completing script parameters we don't care if these requirements are met.
|
||||
// VerifyRequiredModules will attempt to load the required modules which is useful for completion (so the correct types are loaded).
|
||||
if (!forCompletion)
|
||||
{
|
||||
VerifyElevatedPrivileges(scriptInfo);
|
||||
VerifyPSVersion(scriptInfo);
|
||||
VerifyPSEdition(scriptInfo);
|
||||
}
|
||||
|
||||
VerifyRequiredModules(scriptInfo, context, forCompletion);
|
||||
}
|
||||
|
||||
internal static void VerifyPSVersion(ExternalScriptInfo scriptInfo)
|
||||
@@ -426,6 +436,9 @@ namespace System.Management.Automation
|
||||
/// False if not. Null if command discovery should default to something reasonable
|
||||
/// for the command discovered.
|
||||
/// </param>
|
||||
/// <param name="forCompletion">
|
||||
/// True if this for parameter completion and script requirements should be ignored.
|
||||
/// </param>
|
||||
/// <param name="sessionState">The session state the commandInfo should be run in.</param>
|
||||
/// <returns>
|
||||
/// </returns>
|
||||
@@ -436,7 +449,7 @@ namespace System.Management.Automation
|
||||
/// If the security manager is preventing the command from running.
|
||||
/// </exception>
|
||||
internal CommandProcessorBase LookupCommandProcessor(CommandInfo commandInfo,
|
||||
CommandOrigin commandOrigin, bool? useLocalScope, SessionStateInternal sessionState)
|
||||
CommandOrigin commandOrigin, bool? useLocalScope, SessionStateInternal sessionState, bool forCompletion = false)
|
||||
{
|
||||
CommandProcessorBase processor = null;
|
||||
|
||||
@@ -482,7 +495,7 @@ namespace System.Management.Automation
|
||||
scriptInfo.SignatureChecked = true;
|
||||
try
|
||||
{
|
||||
processor = CreateScriptProcessorForSingleShell(scriptInfo, Context, useLocalScope ?? true, sessionState);
|
||||
processor = CreateScriptProcessorForSingleShell(scriptInfo, Context, useLocalScope ?? true, sessionState, forCompletion);
|
||||
}
|
||||
catch (ScriptRequiresSyntaxException reqSyntaxException)
|
||||
{
|
||||
|
||||
@@ -477,7 +477,6 @@ namespace System.Management.Automation
|
||||
/// The assemblies that have been loaded for this runspace.
|
||||
/// </summary>
|
||||
internal Dictionary<string, Assembly> AssemblyCache { get; private set; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Engine State
|
||||
@@ -634,12 +633,13 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
/// <param name="command">The name of the command to lookup.</param>
|
||||
/// <param name="dotSource"></param>
|
||||
/// <param name="forCompletion"></param>
|
||||
/// <returns>The command processor object.</returns>
|
||||
internal CommandProcessorBase CreateCommand(string command, bool dotSource)
|
||||
internal CommandProcessorBase CreateCommand(string command, bool dotSource, bool forCompletion = false)
|
||||
{
|
||||
CommandOrigin commandOrigin = this.EngineSessionState.CurrentScope.ScopeOrigin;
|
||||
CommandProcessorBase commandProcessor =
|
||||
CommandDiscovery.LookupCommandProcessor(command, commandOrigin, !dotSource);
|
||||
CommandDiscovery.LookupCommandProcessor(command, commandOrigin, !dotSource, forCompletion);
|
||||
// Reset the command origin for script commands... // BUGBUG - dotting can get around command origin checks???
|
||||
if (commandProcessor != null && commandProcessor is ScriptCommandProcessorBase)
|
||||
{
|
||||
|
||||
@@ -1783,6 +1783,36 @@ class InheritedClassTest : System.Attribute
|
||||
}
|
||||
}
|
||||
|
||||
Context "Script parameter completion" {
|
||||
BeforeAll {
|
||||
Setup -File -Path 'ModuleReqTest.ps1' -Content @'
|
||||
#requires -Modules ThisModuleDoesNotExist
|
||||
param ($Param1)
|
||||
'@
|
||||
Setup -File -Path 'AdminReqTest.ps1' -Content @'
|
||||
#requires -RunAsAdministrator
|
||||
param ($Param1)
|
||||
'@
|
||||
Push-Location ${TestDrive}\
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
It "Input should successfully complete script parameter for script with failed script requirements" {
|
||||
$res = TabExpansion2 -inputScript '.\ModuleReqTest.ps1 -'
|
||||
$res.CompletionMatches.Count | Should -BeGreaterThan 0
|
||||
$res.CompletionMatches[0].CompletionText | Should -BeExactly '-Param1'
|
||||
}
|
||||
|
||||
It "Input should successfully complete script parameter for admin script while not elevated" {
|
||||
$res = TabExpansion2 -inputScript '.\AdminReqTest.ps1 -'
|
||||
$res.CompletionMatches.Count | Should -BeGreaterThan 0
|
||||
$res.CompletionMatches[0].CompletionText | Should -BeExactly '-Param1'
|
||||
}
|
||||
}
|
||||
|
||||
Context "File name completion" {
|
||||
BeforeAll {
|
||||
$tempDir = Join-Path -Path $TestDrive -ChildPath "baseDir"
|
||||
|
||||
Reference in New Issue
Block a user