Powershell: Should Get-Member behave differently in Strict Mode?

Created on 21 Mar 2019  ·  9Comments  ·  Source: PowerShell/PowerShell

In normal mode, accessing a property that does not exist returns $null. StrictMode disables this and makes it an exception. That is consistent over several commands - except Get-Member which returns $null. This is surprising, and I expected it should also raise an exception. Should it?

Test cases:

PS C:\> Set-StrictMode -Version 2
PS C:\> $x = Get-Item 'C:\windows'
PS C:\> $x.pretend
The property 'pretend' cannot be found on this object. # PropertyNotFoundStrict

PS C:\> $x | Select-Object -ExpandProperty pretend
Select-Object : Property "pretend" cannot be found # ExpandPropertyNotFound

PS C:\> $x | ForEach-Object -MemberName pretend
ForEach-Object : The input name "pretend" cannot be resolved to a member. # PropertyOrMethodNotFound

PS C:\> $x | Where-Object -Property pretend -eq $null
Where-Object : The input name "pretend" cannot be resolved to a property. # PropertyNotFound

PS C:\> $x.foreach('pretend')
The property 'pretend' cannot be found on this object. # PropertyNotFoundStrict

PS C:\> $x | Get-Member -Name pretend    # outputs $null
Issue-Question

All 9 comments

I'm half-thinking it's best to leave it so that we have _some_ way of figuring out whether a property exists or not without throwing an exception.
🤷‍♂️

I see your point, @vexx32. Using an expression you could do [bool] $x.psobject.properties['pretend'] or [bool] $x.psobject.methods['pretendMethod'], however.

@HumanEquivalentUnit, note that Select-Object -ExpandProperty pretend _always_ reports a _non-terminating_ error (per input object that lacks the property), irrespective of the strict-mode setting (strict-mode violations are _statement-terminating_ errors).

I doubt it would be possible to change now without breaking existing code; perhaps only document it. But my question is, was that deliberate or accidental?

@mklement0 you might have seen the related discussion #9086 including testing whether properties exist before using them, in strictmode. I didn't note that Select-Object -ExpandProperty always reports errors for absent properties, that is interesting. I did note that Select-Object -Property Nme with a typo, works perfectly fine in strictmode, no errors about absent properties, and does make an object with a property Nme = $null, just as it would in normal mode.

As per the null-soaking issue, if the intent of StrictMode PropertyNotFound exceptions is to guard against typos, avoid propagating $null, or assert the object is the type you expected it to be, this behaviour of Get-Member and normal behaviour of Select-Object -Property, don't seem consistent with it.

I see your point re Select-Object -Property, @HumanEquivalentUnit.

The tension is between:

  • wanting to ensure in strict mode that you've only specified a _preexisting_ property

  • the convenience of intentionally _creating_ a property / ensuring its existence across heterogenous input.

Both use cases are valid.

Similarly, with Get-Member, you could argue that Getting something with an (umambiguous, non-wildcard) name that doesn't refer to something existing should fail in strict mode.
It relates to the discussion about having separate Test-* cmdlets if the intent is merely to _test_ existence - see https://github.com/PowerShell/PowerShell/issues/7498#issuecomment-414350751

I'm not sure what the right answer is, but I agree that at least updating the docs is called for.

I stumbled upon this with regard to select-object.

Set-StrictMode -Version latest
$PSVersionTable | select-object `
@{ Name = "Dummy"; Expression = { $_.DoesNotExist } }

I would expect this to fail, or at least have a possibility to make it fail.

@leonardder

Problem with that is that

$PSVersionTable | Select-Object @{ n='Dummy'; e={ throw }}

also fails silently

You're correct. Slightly worrying.

Yeah slightly, but that's also how properties tend to work in PS (and you could consider that expression to be somewhat of a property get accessor). e.g.

public class MyObject
{
    public string MyProperty => throw new System.InvalidOperationException();
}

Accessing MyProperty on that object will work mostly the same.

That's good to know, @SeeminglyScience, but perhaps even more worrying (I know that this ship sailed a long time ago), given that _setting_ properties and _method calls_ do surface exceptions.

As it stands, it is impossible to surface errors from the script blocks of calculated properties.

Was this page helpful?
0 / 5 - 0 ratings