private MergedCommandParameterMetadata GetMergedCommandParameterMetdata() { if (this._context == null) { return(null); } IScriptCommandInfo scriptCommandInfo = this as IScriptCommandInfo; CommandProcessor commandProcessor = (scriptCommandInfo != null) ? new CommandProcessor(scriptCommandInfo, this._context, true, false, scriptCommandInfo.ScriptBlock.SessionStateInternal ?? this.Context.EngineSessionState) : new CommandProcessor((CmdletInfo)this, this._context); ParameterBinderController.AddArgumentsToCommandProcessor(commandProcessor, this.Arguments); CommandProcessorBase currentCommandProcessor = this.Context.CurrentCommandProcessor; try { this.Context.CurrentCommandProcessor = commandProcessor; commandProcessor.SetCurrentScopeToExecutionScope(); commandProcessor.CmdletParameterBinderController.BindCommandLineParametersNoValidation(commandProcessor.arguments); } catch (ParameterBindingException) { if (commandProcessor.arguments.Count > 0) { throw; } } finally { this.Context.CurrentCommandProcessor = currentCommandProcessor; commandProcessor.RestorePreviousScope(); } return(commandProcessor.CmdletParameterBinderController.BindableParameters); }
private void GetMergedCommandParameterMetadata(out MergedCommandParameterMetadata result) { // MSFT:652277 - When invoking cmdlets or advanced functions, MyInvocation.MyCommand.Parameters do not contain the dynamic parameters // When trying to get parameter metadata for a CommandInfo that has dynamic parameters, a new CommandProcessor will be // created out of this CommandInfo and the parameter binding algorithm will be invoked. However, when this happens via // 'MyInvocation.MyCommand.Parameter', it's actually retrieving the parameter metadata of the same cmdlet that is currently // running. In this case, information about the specified parameters are not kept around in 'MyInvocation.MyCommand', so // going through the binding algorithm again won't give us the metadata about the dynamic parameters that should have been // discovered already. // The fix is to check if the CommandInfo is actually representing the currently running cmdlet. If so, the retrieval of parameter // metadata actually stems from the running of the same cmdlet. In this case, we can just use the current CommandProcessor to // retrieve all bindable parameters, which should include the dynamic parameters that have been discovered already. CommandProcessor processor; if (Context.CurrentCommandProcessor != null && Context.CurrentCommandProcessor.CommandInfo == this) { // Accessing the parameters within the invocation of the same cmdlet/advanced function. processor = (CommandProcessor)Context.CurrentCommandProcessor; } else { IScriptCommandInfo scriptCommand = this as IScriptCommandInfo; processor = scriptCommand != null ? new CommandProcessor(scriptCommand, _context, useLocalScope: true, fromScriptFile: false, sessionState: scriptCommand.ScriptBlock.SessionStateInternal ?? Context.EngineSessionState) : new CommandProcessor((CmdletInfo)this, _context) { UseLocalScope = true }; ParameterBinderController.AddArgumentsToCommandProcessor(processor, Arguments); CommandProcessorBase oldCurrentCommandProcessor = Context.CurrentCommandProcessor; try { Context.CurrentCommandProcessor = processor; processor.SetCurrentScopeToExecutionScope(); processor.CmdletParameterBinderController.BindCommandLineParametersNoValidation(processor.arguments); } catch (ParameterBindingException) { // Ignore the binding exception if no argument is specified if (processor.arguments.Count > 0) { throw; } } finally { Context.CurrentCommandProcessor = oldCurrentCommandProcessor; processor.RestorePreviousScope(); } } result = processor.CmdletParameterBinderController.BindableParameters; }