One of the most attractive features of Powershell is its ability to convert any object into text. We have used to convert object properties into text in different layouts and output it. What is even more surprising is that Powershell will output the most important information that best represents the essence of this object. An object has many properties, why does it output those properties alone?
If using:
Dir | Format-Table * -wrap
PSP PSP PSC PSD PSP PSI Bas Mod Nam Par Exi Roo Ful Ext Cre Cre Las La La La At
ath are hil riv rov sCo eNa e e ent sts t lNa ens ati ati tAc st st st tr
ntP dNa e ide nta me me ion onT onT ces Ac Wr Wr ib
ath me r ine ime ime sTi ce it it ut
r Utc me ss eT eT es
Ti im im
me e eU
Ut tc
c
--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- -- -- -- --
Mic Mic ABC C Mic Tru ABC d-- ABC Pow Tru C: C: 201 201 201 20 20 20 Di
ros ros ros e -- ers e Pow 1/1 1/1 1/1 11 11 11 re
oft oft oft hel ers 2/1 2/1 2/1 /1 /1 /1 ct
.Po .Po .Po l hel 9 1 9 9 9 1 2/ 2/ 2/ or
wer wer wer lA 7:0 :05 7:0 19 19 19 y
She She She BC 5:5 :55 5:5 9 1 9
ll. ll. ll. 5 5 :0 7: :0
Cor Cor Cor 5: 05 5:
eF eF eF 55 :5 55
ile ile ile 5
Sys Sys Sys
tem tem tem
::C ::C
owe owe
rsh rsh
ell ell
AB
C
Powershell will output each attribute to the maximum extent, but such output is basically meaningless and is not conducive to user reading. So what exactly makes Powershell only display this property but not that property by default? It is the "extended type system" Extended Type System (ETS), which will macro-control the mechanism for converting objects into text in the pipeline.
ETS consists of two parts, one controls the layout of the object and the other controls the properties of the object. Today, we mainly care about the first part.
Text conversion irreversible
After converting the object result into text in the pipeline, the text cannot be converted into objects anymore because ETS cannot process text.
If the directory list is converted into a String through ConvertTo-String, the commands such as Format-Table and Format-List will be invalid.
PS C:Powershell> $text= dir | Out-String
PS C:Powershell> $text
Table of Contents: C:Powershell
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/12/19 17:05 ABC
d---- 2011/12/19 17:06 ABD
d---- 2011/12/19 17:06 ABE
PS C:Powershell> $text | Format-Table
Table of Contents: C:Powershell
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/12/19 17:05 ABC
d---- 2011/12/19 17:06 ABD
d---- 2011/12/19 17:06 ABE
PS C:Powershell> $text | Format-List
Table of Contents: C:Powershell
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/12/19 17:05 ABC
d---- 2011/12/19 17:06 ABD
d---- 2011/12/19 17:06 ABE
Select properties
ETS also won't work if a command like Format-Table is used when displaying the object results, because Format-Table converts the value of each property into text. So sometimes, it is best to specify the properties you display clearly and do not hand over the power of life and death to ETS.
PS C:Powershell> dir | Format-Table Mode,FullName
Mode FullName
---- --------
d---- C:PowershellABC
d---- C:PowershellABD
d---- C:PowershellABE
d---- C:Powershellmyscript
-a--- C:
-a--- C:
-a--- C:
-a--- C:
-a--- C:Powershellalias
Known object formatting
If a formatted command is used, but no specific attribute is specified (such as: dir | Format-Table). ETS will make its first move, and it will determine which objects should be displayed and which attributes should be automatically selected. Before doing these tasks, ETS should first figure out that those objects can be converted into text.
PS C:Powershell> (dir)[0].GetType().FullName
Dir returns an object and contains the objects and child objects in this object. In this way, ETS can check its own internal records and convert the object into text through the internal records configuration. These internal records are XML files with the extension ".ps1xml"
PS C:Powershell> dir $PSHOME*format.ps1xml
Directory: C: WindowsSystem32WindowsPowerShellv1.0
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2009/6/11 5:24 27338 .ps1xml
-a--- 2009/6/11 5:24 27106 .ps1xml
-a--- 2009/6/11 5:24 72654 .ps1xml
-a--- 2009/6/11 5:24 24857 .ps1xml
-a--- 2009/6/11 5:24 257847 .ps1xml
-a--- 2009/6/11 5:24 89703 .ps1xml
-a--- 2009/6/11 5:24 18612 .ps1xml
-a--- 2009/6/11 5:24 20120 .ps1xml
-a--- 2009/6/11 5:24 24498 .ps1xml
Each object is defined in detail in these XML files, including those object properties that support conversion into text, and those objects should be displayed in a list or table by default.
One thing I said before is that ETS is not supported for the mixed command "Get-Process ; dir" above one line. The best way to avoid it is to specify the layout explicitly for each command.
PS C:Powershell> Get-Process | Format-Table ; dir | Format-Table
Unknown object formatting
Objects defined in ps1xml are known objects. How should those unknown objects ETS be handled? For unknown objects, ETS follows a rule:
If the object has less than 5 properties, the table will be displayed, otherwise the list will be displayed.
The following example creates an object and adds attributes to the object one by one.
PS C:Powershell> $obj=New-Object PSObject
PS C:Powershell> Add-Member -Name A -Value 1 -InputObject $obj
MemberType: PS C:Powershell>
PS C:Powershell> Add-Member -MemberType NoteProperty -Name "A" -Value "1" -InputObject $obj
PS C:Powershell> $obj
A
-
1
PS C:Powershell> Add-Member -MemberType NoteProperty -Name "B" -Value "2" -InputObject $obj
PS C:Powershell> Add-Member -MemberType NoteProperty -Name "C" -Value "3" -InputObject $obj
PS C:Powershell> Add-Member -MemberType NoteProperty -Name "D" -Value "4" -InputObject $obj
PS C:Powershell> $obj
A B C D
- - - -
1 2 3 4
PS C:Powershell> Add-Member -MemberType NoteProperty -Name "E" -Value "5" -InputObject $obj
PS C:Powershell> $obj
A : 1
B : 2
C : 3
D : 4
E : 5
Emergency mode
If ETS finds a critical state from the output, it will automatically switch to the list display. For example, "Get-Process; Dir", ETS is outputting Process objects in a table form, but suddenly encountering a FileInfo object, it will directly switch to list mode and output other types of objects.
Hide columns
If you encounter an unknown object, ETS will try to find clues from the first result output from the pipeline, which may lead to a strange phenomenon. ETS will judge attributes based on the first result of an unknown object, but the attributes of the first result will not always be output. When an object containing more attributes may be encountered, the currently selected attribute information may be suppressed.
The following example demonstrates that information will be suppressed. Get-Process returns all running processes, and then sorts them through StartTime, and outputs the name and opening time of each process:
PS C:Windowssystem32> Get-Process | Sort-Object StartTime | Select-Object Name
,StartTime
Sort-Object: An exception occurred while getting "StartTime": "Access denied."
Location Line: 1 Character: 26
+ Get-Process | Sort-Object <<<< StartTime | Select-Object Name,StartTime
+ CategoryInfo : InvalidResult: ( (audi
odg):PSObject) [Sort-Object], GetValueInvocationException
+ FullyQualifiedErrorId : ExpressionEvaluation,
When executing the above command line, you will receive many error messages. These error messages do not come from commands, but may be that some system processes deny access because the current console does not have administrator rights. Some of the output processes may have only process name (Name) and no start time (StartTime), and the start time is suppressed.
Using Select-Object will delete some properties of the object, but the properties of the object itself cannot be deleted, so ETS will regenerate an object in the pipeline with the type:.
PS C:Powershell> Get-Process | foreach {$_.gettype().fullname} | select -f 1
PS C:Powershell> (Get-Process | foreach {$_.gettype().fullname} | select -f 1 Name ).getType().fullname
Because PSCustomObject is not recorded in the ETS configuration, all properties will be output. The pipeline results were previously arranged according to StartTime ascending order, so the previous process did not have StartTime due to permission issues.
Expand ETS
Type objects included in the ETS configuration are converted into text in the best way. However, the performance of unknown objects is imperfect, and imperfect performance does not mean that there is no way to go. Fortunately, ETS can be expanded to allow ETS to handle new objects in the best way.
The first step in expanding ETS is to determine the type of object to be expanded. We may often obtain WMI services through Get-WmiObject. But if you don't like Powershell's default output, you can expand ETS.
PS C:Powershell> Get-WmiObject Win32_Processor
__GENUS : 2
__CLASS : Win32_Processor
__SUPERCLASS : CIM_Processor
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_Processor.DeviceID="CPU0"
__PROPERTY_COUNT : 48
__DERIVATION : {CIM_Processor, CIM_LogicalDevice, CIM_LogicalEle
First determine the type of object that the command returns the result
PS C:Powershell> $object = Get-WmiObject Win32_Processor | Select-Object -first 1
PS C:Powershell> $().FullName
The target type is found:
Next create a configuration file:
<configuration>
<viewdefinitions>
<view>
<name>CustomView</name>
<viewselectedby>
<typename></typename>
</viewselectedby>
<tablecontrol>
<tableheaders>
<tablecolumnheader>
<label>Name</label>
<width>12</width>
</tablecolumnheader>
<tablecolumnheader>
<label>Description</label>
<width>30</width>
</tablecolumnheader>
<tablecolumnheader>
<label>ID</label>
</tablecolumnheader>
</tableheaders>
<tablerowentries>
<tablerowentry>
<tablecolumnitems>
<tablecolumnitem>
<propertyname>DeviceID</propertyname>
</tablecolumnitem>
<tablecolumnitem>
<propertyname>Description</propertyname>
</tablecolumnitem>
<tablecolumnitem>
<propertyname>ProcessorID</propertyname>
</tablecolumnitem>
</tablecolumnitems>
</tablerowentry>
</tablerowentries>
</tablecontrol>
</view>
</viewdefinitions>
</configuration>
Save the file as Win32_Processor.format.ps1xml, then use the command Update-FormatData to load it into ETS, which will take effect immediately.
PS C:Powershell> Update-FormatData .Win32_Processor.format.ps1xml
PS C:Powershell> Get-WmiObject win32_processor
Name Description ID
---- ----------- --
CPU0 x64 Family 6 Model 15 Stepp... BFEBFBFF000006FD
However, such a definition may have a disadvantage. When we obtain other WMI objects, it will also be displayed according to the rules we define.
PS C:Powershell> Get-WmiObject Win32_Share
Name Description ID
---- ----------- --
Remote Admin
Default share
HP LaserJet P2050 Series PCL6
Remote IPC
Printer Drivers
The above situation occurs because all objects of WMI will be returned as type. Therefore, ETS did not make any mistakes, and the culprit was the special type of WMI. Therefore, when expanding ETS, you must refine a specific type. In fact, the WMI object has a PSTypeNames property, through which you can find more specific types.
PS C:Powershell> $object = Get-WmiObject Win32_Processor | Select-Object -first1
PS C:Powershell> $
#rootcimv2Win32_Processor
The inheritance hierarchy of WMI object types is shown above. Therefore, the object type we want to extend in our needs should be: #rootcimv2Win32_Processor
Therefore, the configuration file should be modified and the update should be reloaded. There will be an exception when updating
Update-FormatData: An error occurred while loading the format data file:
, C:PowershellWin32_Processor.format.ps1xml: The file was skipped,
Because the file has appeared in "".
The exception can be ignored and then retested.
PS C:Powershell> Get-WmiObject win32_Processor
Name Description ID
---- ----------- --
CPU0 x64 Family 6 Model 15 Stepp... BFEBFBFF000006FD
PS C:Powershell> Get-WmiObject win32_share
Name Path Description
---- ---- -----------
ADMIN$ C:Windows Remote Admin
C$ C: Default share
In this way, the ETS expansion is only valid for Win32_Processor. No other parent type objects are affected.