Push locals of automatic variables to 'DottedScopes' when dotting script cmdlets (#4709)

When dotting a script cmdlet, the locals of automatic variables from the `PSScriptCmdlet` is not set up in the current scope before parameter binding. The fix is to push the locals in `CommandProcessor.OnSetCurrentScope` and pop them in `CommandProcessor.OnRestorePreviousScope`, which will be called from `SetCurrentScopeToExecutionScope` and `RestorePreviousScope` respectively.

Summary of changes:
1. When a new local scope is used, currently we set the locals for `CommandProcessor` right before parameter binding (in `BindCommandLineParametersNoValidation`); we set the locals for `ScriptCommandProcessor` in `Prepare`. I moved both to the constructor, right after the new scope is created so that the code is more consistent.

2. In `CmdletParameterBinderController.cs`, we set up the `PSBoundParameters` and `MyInvocation` variables in `HandleCommandLineDynamicParameters` again, which I think is unnecessary because this method is only called from `BindCommandLineParametersNoValidation`, where the setup is done for the first time.

3. Currently, the locals will be set for dotted script cmdlet in `EnterScope()` and `ExitScope()`. Now, that logic is moved to `OnSetCurrentScope` and `OnRestorePreviousScope` of `CommandProcessor`. This not only makes sure that locals are set before parameter binding, but also is consistent with the `ScriptCommandProcessor`.
This commit is contained in:
Dongbo Wang
2017-09-06 10:25:33 -07:00
committed by GitHub
parent 955e01dc65
commit 41f12b1d2c
5 changed files with 116 additions and 36 deletions
@@ -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
}
}
}