Type Accelerator?

I’ve asked this question to colleagues and of course google. I’m assuming it has something to do with it being a type accelerator, but from what I’ve read my understanding is that type accelerators help you to not have to type the full .Net type. So why can’t I do it the long way? I’m looking for actual technical reasons, not “because Bruce Payette said so” or the like. :slight_smile:

This

$var = [System.Management.Automation.PSCustomObject]@{
    Name = 'test'
    Admin = $true
}

results in error

Cannot convert the "System.Collections.Hashtable" value of type "System.Collections.Hashtable" to type "System.Management.Automation.PSCustomObject".

But this

$var = [PSCustomObject]@{
    Name = 'test'
    Admin = $true
}
$var | gm

works just fine, get-member shows

$var | gm

TypeName: System.Management.Automation.PSCustomObject

And then lastly

$var = @{
    Name = 'test'
    Admin = $true
}

Is just a hash table

$var | gm

TypeName: System.Collections.Hashtable

I know it’s probably something dumb and I’m an idiot for asking. But it’s always bugged me.

Interesting topic !

I’ve tried your cast inside a Trace-Command block… and getting no more useful info.

I’ve assumed also it might be a parser thing (maybe Bruce :slight_smile: checked for this specific cast only for the type accelerator name, and not for the full base type, or the System namespace but not System.Management.Automation, or whatever …)

But it is not the parser. It seems something inside .NET, as doing it in two steps also fails the same way :

$var1 = @{
Name = ‘test’
Admin = $true
} # OK
$Var2 = [System.Management.Automation.PSCustomObject]$Var1 # Same error

BTW,

$var -IS [System.management.automation.pscustomobject] # returns $true

Next step would be checking the PowerShell source code…

Great question. I think somehow it’s the equivalent of:

new-object -typename psobject -property @{name='test'}

But even this still results in a hashtable:

[psobject]::new(@{name='test'})

Name                           Value
----                           -----
name                           test

Get type accelerator: https://powershellexplained.com/2016-10-28-powershell-everything-you-wanted-to-know-about-pscustomobject/

[psobject].Assembly.GetType(“System.Management.Automation.TypeAccelerators”)::get | 
  % { $_.['pscustomobject'] } 

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     PSObject                                 System.Object

Dang it, Bruce! Thanks for chiming in guys, I’ve already learned a couple of things from you both.

I’ve been digging around. It might just be a bug or non-optimal behavior that would require a breaking change? For example: https://github.com/PowerShell/PowerShell/issues/2295

That is exactly the issue, it tabbed completed and didn’t work. I am curious (and annoyed) with my favorite search engine that I wasn’t able to locate this. Thank you so much for spending the time to find this.

Looks like the magic is in the source code: https://stackoverflow.com/a/61141536/6654942

Absolutely. I love the comments.

// We can't use the normal PSConvertBinder because it is strongly typed, and we // play some funny games with the PSCustomObject type (externally, it's just an // alias for PSObject, internally we do other stuff with it.)