vexx32 / PSKoans

A simple, fun, and interactive way to learn the PowerShell language through Pester unit testing.
GNU General Public License v3.0
1.72k stars 176 forks source link

Seemingly correct answers in AboutGetMember don't work. #429

Closed rogerramtech closed 3 years ago

rogerramtech commented 3 years ago

Describe "Koan Bug, Issue, or Help Request"

I have my team using PSKoans as some additional training. A few have struck the following problem in the AboutGetMember topic in the foundation module.

$BecauseString = "property '{0}' should be present in output from {1}"

$Cmdlet1 = 'Get-Blank'
$PropertyName = 'Name'

$Reason = $BecauseString -f $PropertyName, $cmdlet1
    & (Get-Command -Name $Cmdlet1) |
        Get-Member -MemberType Property -Name $PropertyName |
        Should -Not -BeNullOrEmpty -Because $Reason

Returns

Expected a value, because property 'Name' should be present in output from Get-Blank, but got $null or empty.

    Please meditate on the following code:

× It "allows us to explore properties on an object"
at <ScriptBlock>, C:\Users\RossMarston\PSKoans\Introduction\AboutGetMember.Koans.ps1: line 69
69:             Should -Not -BeNullOrEmpty -Because $Reason

Context "The Problematic Assertions"

  It 'allows us to explore properties on an object' {

Context "Your Attempts"

I have attempted this on various device and in various environments. It doesn't seem to happen in pwsh Version 7.1.2 but this is not conclusive, as the devices and OS are also different. the environment that this does occur in are as follows.

$PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.1.3
PSEdition                      Core
GitCommitId                    7.1.3
OS                             Microsoft Windows 10.0.19042
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

I have attempted the following in the same environment and get these successful results. I have also tried with many other cmdlets, with the same outcome. The only way to get past it seems to be to comment out the entire assertion and Topic.

Get-Command 'Get-Blank' | Get-Member -MemberType Property -Name 'Name'

   TypeName: System.Management.Automation.FunctionInfo

Name MemberType Definition
---- ---------- ----------
Name Property   string Name {get;}

Clearly not empty or $null. So why is the It assertion say it is? This issue does not happen in the MacOS version using 7.1.2 core. I have not tested in 5.1 or lower.

Context "Additional Information"

Any assistance appreciated.

vexx32 commented 3 years ago

Yeah, I can see how that would prove pretty confusing.

When you call Get-Command 'Get-Blank' and pipe that to Get-Member, you're passing the meta-object that represents the function itself. What the koan is doing is actually invoking that meta-object to run the function, using &.

So what you would need to be looking at is instead:

& (Get-Command 'Get-Blank') | Get-Member -MemberType Property

This might just error though, I think? Either that or probably not return anything.

I'd expect Get-Blank to be a difficult one to use here; by design it emits an object that tries its utmost to behave as close to $null as possible while also doing a bit of subterfuge to make certain patterns easier for the module to present to users without also triggering a large amount of very confusing errors.

rogerramtech commented 3 years ago

Ah! I see the issue now. They had tried a bunch of commands filtered by

Get-Command -CommandType Cmdlet

and happened to get a whole bunch (~15) all with Null returns. I can see that it does work, but you have to be very judicious about the Cmdlets you pick. To use your example...

& (Get-Command -Name 'Get-Process') | Get-Member -MemberType Property -Name 'Threads'

   TypeName: System.Diagnostics.Process

Name    MemberType Definition
----    ---------- ----------
Threads Property   System.Diagnostics.ProcessThreadCollection Threads {get;}

Just a matter of picking the right Cmdlet Property combo to return a result. Surprising how many don't. Particularly if you stray away from -Verb Get Thanks.

vexx32 commented 3 years ago

Yeah, for the most part you won't get a lot of data / properties from non-Get cmdlets. There are exceptions, as with anything, but the majority of things that emit output are Get-*.

Glad you got it sorted out! 💖 🌸