Lesson Learned Today about PowerShell’s .Net Type System

Today I was asked why this person saw more properties showing with a “format-table”, than with a “format-table *”.  I will admit, I wasn't sure.  I kicked myself later once I got the answer and I realized I should have known this.  There is a PFE colleague of mine that always seems to be AMAZING at answering our questions when we ask them.  He took maybe 30 minutes to school me on this.

Here is an example of what I am talking about:

PS C:\> (resolve-path HKLM:\SOFTWARE\Microsoft).provider | format-list *
ImplementingType : Microsoft.PowerShell.Commands.RegistryProvider
HelpFile : System.Management.Automation.dll-Help.xml
Name : Registry
PSSnapIn : Microsoft.PowerShell.Core
Description :
Capabilities : ShouldProcess
Home :
Drives : {HKLM, HKCU} PS C:\> (resolve-path HKLM:\SOFTWARE\Microsoft).provider | format-list
Name : Registry
Drives : {HKLM, HKCU}
Path :
Home :
Description :
Capabilities : ShouldProcess
ImplementingType : Microsoft.PowerShell.Commands.RegistryProvider
AssemblyInfo :

You’ll notice that in the second try, that there is a property showing that is called “assemblyinfo” that doesn't show in the first.  I always though that a format-list * should show everything.

 

Here is Rich Doyle’s response to me when I asked this (Rich is a PFE like me):

If you weren't aware, the default formatting for viewing of types are defined in the following files:

PS C:\> get-childitem $pshome\*.ps1xml

    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32\WindowsPowerShell\v1.0

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 11/21/2006 11:47 AM 22120 Certificate.format.ps1xml
-a--- 11/21/2006 11:47 AM 60703 DotNetTypes.format.ps1xml
-a--- 11/21/2006 11:47 AM 19730 FileSystem.format.ps1xml
-a--- 11/21/2006 11:47 AM 250197 Help.format.ps1xml
-a--- 11/21/2006 11:47 AM 65283 PowerShellCore.format.ps1xml
-a--- 11/21/2006 11:47 AM 13394 PowerShellTrace.format.ps1xml
-a--- 11/21/2006 11:47 AM 13540 Registry.format.ps1xml
-a--- 11/21/2006 11:47 AM 129836 types.ps1xml

If you look inside of PowerShellCore.format.ps1xml you will find the following view definition for System.Management.Automation.ProviderInfo:

        <View>
<Name>provider</Name>
<ViewSelectedBy>
<TypeName>System.Management.Automation.ProviderInfo</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Drives</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Path</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Home</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Description</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Capabilities</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ImplementingType</PropertyName>
</ListItem>
<ListItem>
<PropertyName>AssemblyInfo</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>

Now, looking at an object of type System.Management.Automation.ProviderInfo using Get-Member we can see all of the Properties that are available on the object:

PS C:\> (resolve-path HKLM:\SOFTWARE\Microsoft).provider | get-member

   TypeName: System.Management.Automation.ProviderInfo

Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
get_Capabilities Method System.Management.Automation.Provider.ProviderCapabilities get_Capabilities()
get_Description Method System.String get_Description()
get_Drives Method System.Collections.ObjectModel.Collection`1[[System.Management.Automation.PSDriveInf...
get_HelpFile Method System.String get_HelpFile()
get_Home Method System.String get_Home()
get_ImplementingType Method System.Type get_ImplementingType()
get_Name Method System.String get_Name()
get_PSSnapIn Method System.Management.Automation.PSSnapInInfo get_PSSnapIn()
set_Description Method System.Void set_Description(String value)
set_Home Method System.Void set_Home(String value)
ToString Method System.String ToString()
Capabilities Property System.Management.Automation.Provider.ProviderCapabilities Capabilities {get;}
Description Property System.String Description {get;set;}
Drives Property System.Collections.ObjectModel.Collection`1[[System.Management.Automation.PSDriveInf...
HelpFile Property System.String HelpFile {get;}
Home Property System.String Home {get;set;}
ImplementingType Property System.Type ImplementingType {get;}
Name Property System.String Name {get;}
PSSnapIn Property System.Management.Automation.PSSnapInInfo PSSnapIn {get;}

As we can see, AssemblyInfo is actually not a property of the object.

So, what is happening here is:

(resolve-path HKLM:\SOFTWARE\Microsoft).provider | format-list *

Piping the output to format-list * assumes inherent usage of the properties switch, and, just as with Get-Member enumerating properties, format-list is reading all of the properties from the object returning a nice list of their names and values - correct behavior.

(resolve-path HKLM:\SOFTWARE\Microsoft).provider | format-list

Piping the output to format-list (no properties or properties wildcard) invokes the default View definition in PowerShellCore.format.ps1xml, which enumerates what is defined and the values of those Properties, formatting them in a list.

This, again, is the correct behavior, it's just that the default View contains the property AssemblyInfo that is not present on this instance of this System.Management.Automation.ProviderInfo object. Therefore, we see the property showing in the result, of course with no value as the property is not really there. This is exactly how the .Net Type system is supposed to work, just the same as if you typed “format-list name,assemblyinfo”, which would show the empty looking property.

Thanks Rich for your response!

 

This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.