Make Select-Object/ForEach-Object/Where-Object see dynamic properties (#6898)

Dynamic (DLR) objects work in some places today, but not others.  This change expands that support to ForEach-Object, Where-Object and the family of cmdlets that use 'MshExpression' (Select-Object, etc.).

This change addresses both wildcard and non-wildcard cases. In wildcard cases, it uses the existing support of generating PSDynamicMember objects for names returned by GetDynamicMemberNames.

In non-wildcard cases, a dynamic property access is attempted whether or not the name shows up in GetDynamicMemberNames, but a truly "blind" access is only attempted if we see that the base object is an IDMOP. If the dynamic access fails, you'll get the same or a similar error experience as before ("The property 'Blarg' cannot be found", or no error at all, depending on the cmdlet and the strict mode setting).

The included test coverage includes a stub for the.ForEach operator--once people are happy with this change, I can continue by adding support there.

This change should allegedly also have positive perf impact, though in actual perf testing, although it does seem ever-so-slightly faster, I found it difficult to measure much difference at all.
This commit is contained in:
Dan Thompson authored and Dongbo Wang committed 2018-06-12 23:48:34 -07:00
1 parent 3a5a3e4c6e
commit ce3cb68551
7 files changed
+415 -89

No files matched your search

@@ -1,6 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
. (Join-Path -Path $PSScriptRoot -ChildPath Test-Mocks.ps1)
Add-TestDynamicType
Describe "Select-Object" -Tags "CI" {
BeforeEach {
@@ -242,6 +243,47 @@ Describe "Select-Object DRT basic functionality" -Tags "CI" {
$results.Count | Should -Be 1
$results[0] | Should -BeExactly "3"
}
It "Select-Object should handle dynamic (DLR) properties"{
$dynObj = [TestDynamic]::new()
$results = $dynObj, $dynObj | Select-Object -ExpandProperty FooProp
$results.Count | Should -Be 2
$results[0] | Should -Be 123
$results[1] | Should -Be 123
}
It "Select-Object should handle dynamic (DLR) properties without GetDynamicMemberNames hint"{
$dynObj = [TestDynamic]::new()
$results = $dynObj, $dynObj | Select-Object -ExpandProperty HiddenProp
$results.Count | Should -Be 2
$results[0] | Should -Be 789
$results[1] | Should -Be 789
}
It "Select-Object should handle wildcarded dynamic (DLR) properties when hinted by GetDynamicMemberNames"{
$dynObj = [TestDynamic]::new()
$results = $dynObj, $dynObj | Select-Object -ExpandProperty FooP*
$results.Count | Should -Be 2
$results[0] | Should -Be 123
$results[1] | Should -Be 123
}
It "Select-Object should work when multiple dynamic (DLR) properties match"{
$dynObj = [TestDynamic]::new()
$results = $dynObj, $dynObj | Select-Object *Prop
$results.Count | Should -Be 2
$results[0].FooProp | Should -Be 123
$results[0].BarProp | Should -Be 456
$results[1].FooProp | Should -Be 123
$results[1].BarProp | Should -Be 456
}
It "Select-Object -ExpandProperty should yield errors if multiple dynamic (DLR) properties match"{
$dynObj = [TestDynamic]::new()
$e = { $results = $dynObj, $dynObj | Select-Object -ExpandProperty *Prop -ErrorAction Stop} |
Should -Throw -PassThru -ErrorId "MutlipleExpandProperties,Microsoft.PowerShell.Commands.SelectObjectCommand"
$e.CategoryInfo | Should -Match "PSArgumentException"
}
}
Describe "Select-Object with Property = '*'" -Tags "CI" {