The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,157 other followers

powershell – Format-Table forgets some properties, but Format-List shows them all. Why? – Stack Overflow

Posted by jpluimers on 2020/11/12

Reminder to self: finish the script that initiated this 2013 question (yes ages ago!) [WayBack] powershell – Format-Table forgets some properties, but Format-List shows them all. Why? – Stack Overflow.

The question was based on code I was really happy I saved in the WayBack machine: WayBack: how-to: Print/List installed programs/applications sorted by date | Tech Off | Forums | Channel 9

So here the question and the answer.

Question

Given the below PowerShell 3 script, Format-Table does not list all properties as columns (it skips NoRemove), but Format-List does, and you can force the properties to be there using Select-Object.

Out-GridView behaves the same as Format-Table and also skips NoRemove

Why is that?

Note: this is from a much less restricted Where-Object clause, where it looks like Format-Tabledoes inspect more than just the first object in the array to guess the columns.

The example comes from Channel 9 how-to: Print/List installed ​programs/ap​plications sorted by date which forgot to initialize the first Get-ItemProperty (gp) as an array so you got an error like this:

Method invocation failed because [Microsoft.Win32.RegistryKey] doesn't
contain a method named 'op_Addition'.

Example code:

$nonUninstallableSoftwareRegistryKeys = (@(Get-Item HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*)) + 
(Get-Item HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*) + 
(Get-Item HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*) | 
  Where-Object { $_.ValueCount -eq 1 }

$nonUninstallableSoftwareRegistryKeys.GetType().FullName
$nonUninstallableSoftwareRegistryKeys | Get-Member

$nonUninstallableSoftwareRegistryNameValues = $nonUninstallableSoftwareRegistryKeys | 
  Get-ItemProperty

$nonUninstallableSoftwareRegistryNameValues.GetType().FullName
$nonUninstallableSoftwareRegistryNameValues | Get-Member

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table

$nonUninstallableSoftwareRegistryNameValues |
  Format-List

$nonUninstallableSoftwareRegistryNameValues |
  Select-Object SystemComponent, NoRemove, PSPath, PSParentPath, PSChildName, PSProvider |
  Format-Table

I used GetType().FullName and Get-Member to inspect the underlying types.

$nonUninstallableSoftwareRegistryKeys starts with all installed software (user, system x64 and system x86) filtered by registry keys having only 1 value (empirically those are the ones you cannot uninstall).

The first part of the output shows that $nonUninstallableSoftwareRegistryKeys is a System.Object[] of type Microsoft.Win32.RegistryKey with all the right members. Hence the ability to perform a Where-Object filter on the ValueCount property even though the code-completion does not show that.

$nonUninstallableSoftwareRegistryKeys exposes also a few PowerShell “Extended Type System” NoteProperty properties including Property that contain the registry Name/Value pairs under the key and a bunch of PS* coming from the registry provider.

$nonUninstallableSoftwareRegistryNameValues is also a System.Object[] but now of typeSystem.Management.Automation.PSCustomObject because of the Get-ItemProperty which expands the Name/Value pairs in the Property of each $nonUninstallableSoftwareRegistryKeysitem into properties. For the first item in my output, it adds the SystemComponent property. For the second item it adds NoRemove. And it adds a bunch of PS* coming from the registry provider.

Format-Table output:

SystemComponent PSPath                                                                                                                                    PSParentPath                        
--------------- ------                                                                                                                                    ------------                        
              1 Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager             Microsoft.PowerShell.Core\Registr...
                Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC                            Microsoft.PowerShell.Core\Registr...
              1 Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager Microsoft.PowerShell.Core\Registr...
                Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC                Microsoft.PowerShell.Core\Registr...

Format-List output:

SystemComponent : 1
PSPath          : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager
PSParentPath    : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName     : Connection Manager
PSProvider      : Microsoft.PowerShell.Core\Registry

NoRemove     : 1
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName  : WIC
PSProvider   : Microsoft.PowerShell.Core\Registry

SystemComponent : 1
PSPath          : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager
PSParentPath    : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName     : Connection Manager
PSProvider      : Microsoft.PowerShell.Core\Registry

NoRemove     : 1
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName  : WIC
PSProvider   : Microsoft.PowerShell.Core\Registry

Select-Object output:

SystemComponent NoRemove PSPath                                                                                                                                    PSParentPath               
--------------- -------- ------                                                                                                                                    ------------               
              1          Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager             Microsoft.PowerShell.Cor...
                1        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC                            Microsoft.PowerShell.Cor...
              1          Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager Microsoft.PowerShell.Cor...
                1        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC                Microsoft.PowerShell.Cor...

Edit: my environment

PS C:\Users\Developer> Get-CimInstance Win32_OperatingSystem | Select-Object Version, Caption | Format-List
$PSVersionTable

Version : 6.2.9200
Caption : Microsoft Windows 8 Pro

Name                           Value                                                                                                                                                          
----                           -----                                                                                                                                                          
PSVersion                      3.0                                                                                                                                                            
WSManStackVersion              3.0                                                                                                                                                            
SerializationVersion           1.1.0.1                                                                                                                                                        
CLRVersion                     4.0.30319.18051                                                                                                                                                
BuildVersion                   6.2.9200.16628                                                                                                                                                 
PSCompatibleVersions           {1.0, 2.0, 3.0}                                                                                                                                                
PSRemotingProtocolVersion      2.2   

These 2 return the same table:

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table *                                                                                                                                                         

Answer 1

If you don’t specify the property names or ‘*’ for all of them, Format-Table will print by default just the first 4 (the default value of $FormatEnumerationLimit), not ure why you get only three in the ft output. Format-List will show all only when the type of objects doesn’t have a format view for Format-List.

Comment

I did a $nonUninstallableSoftwareRegistryNameValues | Format-Table * which also skips NoRemove. Something fishy is going on here.

And if you add -Force?

This also fails: $nonUninstallableSoftwareRegistryNameValues | Format-Table * -Force

I can see all properties when piping to fl (without -force) and with ft *.

What OS and PS version do you run? I’ve added mine to my question.

Answer 2

Did you try the following?

$nonUninstallableSoftwareRegistryNameValues |
  Select-Object SystemComponent, NoRemove, PSPath, PSParentPath, PSChildName, PSProvider |
  Format-Table -Wrap

Comment

That works (it is almost the same as the last entry in my example), but why can’t Format-Table figure this out by itself? Or maybe phrased differently: what criteria does Format-Table to determine which columns to pick?

–jeroen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 
%d bloggers like this: