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
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,7 @@ internal void BindCommandLineParametersNoValidation(Collection<CommandParameterI
var psCompiledScriptCmdlet = this.Command as PSScriptCmdlet;
if (psCompiledScriptCmdlet != null)
{
psCompiledScriptCmdlet.PrepareForBinding(
((ScriptParameterBinder)this.DefaultParameterBinder).LocalScope,
this.CommandLineParameters);
psCompiledScriptCmdlet.PrepareForBinding(this.CommandLineParameters);
}

// Add the passed in arguments to the unboundArguments collection
Expand Down Expand Up @@ -1759,14 +1757,6 @@ private void HandleCommandLineDynamicParameters(out ParameterBindingException ou
{
s_tracer.WriteLine("Getting the bindable object from the Cmdlet");

var psCompiledScriptCmdlet = this.Command as PSScriptCmdlet;
if (psCompiledScriptCmdlet != null)
{
psCompiledScriptCmdlet.PrepareForBinding(
((ScriptParameterBinder)this.DefaultParameterBinder).LocalScope,
this.CommandLineParameters);
}

// Now get the dynamic parameter bindable object.
object dynamicParamBindableObject;

Expand Down
34 changes: 30 additions & 4 deletions src/System.Management.Automation/engine/CommandProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,28 @@ internal override void Prepare(IDictionary psDefaultParameterValues)
BindCommandLineParameters();
}

protected override void OnSetCurrentScope()
{
// When dotting a script cmdlet, push the locals of automatic variables to
// the 'DottedScopes' of the current scope.
PSScriptCmdlet scriptCmdlet = this.Command as PSScriptCmdlet;
if (scriptCmdlet != null && !UseLocalScope)
{
scriptCmdlet.PushDottedScope(CommandSessionState.CurrentScope);
}
}

protected override void OnRestorePreviousScope()
{
// When dotting a script cmdlet, pop the locals of automatic variables from
// the 'DottedScopes' of the current scope.
PSScriptCmdlet scriptCmdlet = this.Command as PSScriptCmdlet;
if (scriptCmdlet != null && !UseLocalScope)
{
scriptCmdlet.PopDottedScope(CommandSessionState.CurrentScope);
}
}

/// <summary>
/// Execute BeginProcessing part of command
/// </summary>
Expand Down Expand Up @@ -731,14 +753,18 @@ private void Init(CmdletInfo cmdletInformation)

private void Init(IScriptCommandInfo scriptCommandInfo)
{
InternalCommand scriptCmdlet =
new PSScriptCmdlet(scriptCommandInfo.ScriptBlock, _useLocalScope, FromScriptFile, _context);

var scriptCmdlet = new PSScriptCmdlet(scriptCommandInfo.ScriptBlock, UseLocalScope, FromScriptFile, _context);
this.Command = scriptCmdlet;
this.CommandScope = _useLocalScope
this.CommandScope = UseLocalScope
? this.CommandSessionState.NewScope(_fromScriptFile)
: this.CommandSessionState.CurrentScope;

if (UseLocalScope)
{
// Set the 'LocalsTuple' of the new scope to that of the scriptCmdlet
scriptCmdlet.SetLocalsTupleForNewScope(CommandScope);
}

InitCommon();

// If the script has been dotted, throw an error if it's from a different language mode.
Expand Down
16 changes: 10 additions & 6 deletions src/System.Management.Automation/engine/ScriptCommandProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ private void Init()
_obsoleteAttribute = _scriptBlock.ObsoleteAttribute;
_runOptimizedCode = _scriptBlock.Compile(optimized: _context._debuggingMode > 0 ? false : UseLocalScope);
_localsTuple = _scriptBlock.MakeLocalsTuple(_runOptimizedCode);

if (UseLocalScope)
{
Diagnostics.Assert(CommandScope.LocalsTuple == null, "a newly created scope shouldn't have it's tuple set.");
CommandScope.LocalsTuple = _localsTuple;
}
}

/// <summary>
Expand All @@ -282,12 +288,6 @@ internal override ObsoleteAttribute ObsoleteAttribute

internal override void Prepare(IDictionary psDefaultParameterValues)
{
if (UseLocalScope)
{
Diagnostics.Assert(CommandScope.LocalsTuple == null, "a newly created scope shouldn't have it's tuple set.");
CommandScope.LocalsTuple = _localsTuple;
}

_localsTuple.SetAutomaticVariable(AutomaticVariable.MyInvocation, this.Command.MyInvocation, _context);
_scriptBlock.SetPSScriptRootAndPSCommandPath(_localsTuple, _context);
_functionContext = new FunctionContext
Expand Down Expand Up @@ -585,6 +585,8 @@ private void EnterScope()

protected override void OnSetCurrentScope()
{
// When dotting a script, push the locals of automatic variables to
// the 'DottedScopes' of the current scope.
if (!UseLocalScope)
{
CommandSessionState.CurrentScope.DottedScopes.Push(_localsTuple);
Expand All @@ -593,6 +595,8 @@ protected override void OnSetCurrentScope()

protected override void OnRestorePreviousScope()
{
// When dotting a script, pop the locals of automatic variables from
// the 'DottedScopes' of the current scope.
if (!UseLocalScope)
{
CommandSessionState.CurrentScope.DottedScopes.Pop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1864,21 +1864,11 @@ internal override void DoEndProcessing()
private void EnterScope()
{
_commandRuntime.SetVariableListsInPipe();

if (!_useLocalScope)
{
this.Context.SessionState.Internal.CurrentScope.DottedScopes.Push(_localsTuple);
}
}

private void ExitScope()
{
_commandRuntime.RemoveVariableListsInPipe();

if (!_useLocalScope)
{
this.Context.SessionState.Internal.CurrentScope.DottedScopes.Pop();
}
}

private void RunClause(Action<FunctionContext> clause, object dollarUnderbar, object inputToProcess)
Expand Down Expand Up @@ -1986,12 +1976,33 @@ public object GetDynamicParameters()
return null;
}

public void PrepareForBinding(SessionStateScope scope, CommandLineParameters commandLineParameters)
/// <summary>
/// If the script cmdlet will run in a new local scope, this method is used to set the locals to the newly created scope.
/// </summary>
internal void SetLocalsTupleForNewScope(SessionStateScope scope)
{
Diagnostics.Assert(scope.LocalsTuple == null, "a newly created scope shouldn't have it's tuple set.");
scope.LocalsTuple = _localsTuple;
}

/// <summary>
/// If the script cmdlet is dotted, this method is used to push the locals to the 'DottedScopes' of the current scope.
/// </summary>
internal void PushDottedScope(SessionStateScope scope)
{
scope.DottedScopes.Push(_localsTuple);
}

/// <summary>
/// If the script cmdlet is dotted, this method is used to pop the locals from the 'DottedScopes' of the current scope.
/// </summary>
internal void PopDottedScope(SessionStateScope scope)
{
scope.DottedScopes.Pop();
}

internal void PrepareForBinding(CommandLineParameters commandLineParameters)
{
if (_useLocalScope && scope.LocalsTuple == null)
{
scope.LocalsTuple = _localsTuple;
}
_localsTuple.SetAutomaticVariable(AutomaticVariable.PSBoundParameters,
commandLineParameters.GetValueToBindToPSBoundParameters(), this.Context);
_localsTuple.SetAutomaticVariable(AutomaticVariable.MyInvocation, MyInvocation, this.Context);
Expand Down
49 changes: 49 additions & 0 deletions test/powershell/engine/ParameterBinding/ParameterBinding.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,53 @@
$_.Exception.Message | should match "Parameter2"
}
}

Context "Use automatic variables as default value for parameters" {
BeforeAll {
## Explicit use of 'CmdletBinding' make it a script cmdlet
$test1 = @'
[CmdletBinding()]
param ($Root = $PSScriptRoot)
"[$Root]"
'@
## Use of 'Parameter' implicitly make it a script cmdlet
$test2 = @'
param (
[Parameter()]
$Root = $PSScriptRoot
)
"[$Root]"
'@
$tempDir = Join-Path -Path $TestDrive -ChildPath "DefaultValueTest"
$test1File = Join-Path -Path $tempDir -ChildPath "test1.ps1"
$test2File = Join-Path -Path $tempDir -ChildPath "test2.ps1"

$expected = "[$tempDir]"
$psPath = "$PSHOME\powershell"

$null = New-Item -Path $tempDir -ItemType Directory -Force
Set-Content -Path $test1File -Value $test1 -Force
Set-Content -Path $test2File -Value $test2 -Force
}

AfterAll {
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
}

It "Test dot-source should evaluate '`$PSScriptRoot' for parameter default value" {
$result = . $test1File
$result | Should Be $expected

$result = . $test2File
$result | Should Be $expected
}

It "Test 'powershell -File' should evaluate '`$PSScriptRoot' for parameter default value" {
$result = & $psPath -NoProfile -File $test1File
$result | Should Be $expected

$result = & $psPath -NoProfile -File $test2File
$result | Should Be $expected
}
}
}