• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Windows Powershell扩展类型系统

    Powershell一个最吸引人的功能是它能够将任何对象转换成文本,我们已经使用过将对象属性以不同的版式转换成文本,并且输出。更令人惊奇的是Powershell会把最重要最能代表这个对象本质的信息输出。一个对象有很多属性,为什么它单单就输出那几个属性呢?
    如果使用:

    复制代码 代码如下:

    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会最大限度的输出每个属性,但是这样的输出基本上没有意义,不利于用户阅读。那到底是什么让Powershell默认只显示此属性不显示彼属性呢?是“扩展类型系统”Extended Type System (ETS),ETS会对管道中对象转换成文本的机制进行宏观调控。
    ETS由两部分组成,一部分控制对象的版式,一部分控制对象的属性,今天主要关心第一部分。

    文本转换不可逆

    在管道中将对象结果转换成文本后,不能再将文本转换成对象,因为ETS不能处理文本。
    如果通过ConvertTo-String将目录列表的转换成String后,使用Format-Table和Format-List这些命令就会无效。

    复制代码 代码如下:

    PS C:Powershell> $text= dir | Out-String
    PS C:Powershell> $text

        目录: 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

        目录: 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

        目录: 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

    选择属性

    在显示对象结果时如果使用了像Format-Table这样的命令,ETS也不会起作用,因为Format-Table将每个属性的值转换成了文本。所以有的时候,显示那些属性最好自己指定清楚,不要把生杀大权交给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:Powershella.ccs
    -a--- C:Powershella.csv
    -a--- C:Powershella.html
    -a--- C:Powershella.txt
    -a--- C:Powershellalias

    已知对象格式化

    如果使用了格式化的命令,但是没有指定具体的属性(如: dir | Format-Table)。ETS将会首次大展拳脚,它会决定那些对象应当显示,那些属性应当被自动选择。ETS在做这些工作之前,首先应当弄清楚,那些对象能够被转换成文本。

    复制代码 代码如下:

    PS C:Powershell> (dir)[0].GetType().FullName
    System.IO.DirectoryInfo

    Dir 返回一个System.IO.DirectoryInfo对象,并且包含了这个对象里面的System.IO.FileInfo对象和System.IO.DirectoryInfo子对象。这样ETS就可以去检查自己的内部记录,通过内部记录的配置,将对象转换成文本。这些内部记录为XML文件,扩展名为“.ps1xml”

    复制代码 代码如下:

    PS C:Powershell> dir $PSHOME*format.ps1xml

        目录: C:WindowsSystem32WindowsPowerShellv1.0

    Mode         LastWriteTime Length Name
    ----         ------------- ------ ----
    -a---  2009/6/11      5:24  27338 Certificate.format.ps1xml
    -a---  2009/6/11      5:24  27106 Diagnostics.Format.ps1xml
    -a---  2009/6/11      5:24  72654 DotNetTypes.format.ps1xml
    -a---  2009/6/11      5:24  24857 FileSystem.format.ps1xml
    -a---  2009/6/11      5:24 257847 Help.format.ps1xml
    -a---  2009/6/11      5:24  89703 PowerShellCore.format.ps1xml
    -a---  2009/6/11      5:24  18612 PowerShellTrace.format.ps1xml
    -a---  2009/6/11      5:24  20120 Registry.format.ps1xml
    -a---  2009/6/11      5:24  24498 WSMan.Format.ps1xml

    每一个对象详细地被定义在这些XML文件中,定义包括那些对象属性支持转换成文本,那些对象应当默认显示在列表或者表格中。
    有一点之前说过,对于一行上面的混合命令“ Get-Process ; dir”ETS不支持,要想避免最好的方式是每个命令明确地指定版式。

    PS C:Powershell> Get-Process | Format-Table ; dir | Format-Table

    未知对象格式化

    在ps1xml中定义过的对象属于已知对象,那些未知对象ETS应当怎样处理呢?对于未知对象,ETS遵循一个规律:
    如果对象的属性少于5个则表格显示,否则列表显示。
    下面的例子创建一个对象,并向对象中逐个增加属性。

    复制代码 代码如下:

    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

    应急模式

    如果ETS从输出中发现临界状态,会自动切换到列表显示。例如“Get-Process; Dir”,ETS正在以表格形式输出Process对象,但是突然碰到一个FileInfo对象,就会直接切换到列表模式,输出其它类型的对象。

    隐藏列

    如果碰到未知的对象,ETS会试着从管道输出的第一个结果寻找线索,这样可能导致一个奇怪的现象。ETS会根据未知对象的第一个结果,来判断属性,但第一条结果的属性并不总会输出。可能再碰到包含更多属性的对象时,当前选择的属性信息就可能会被抑制。
    接下来的例子演示那些信息会被抑制,Get-Process 返回正在运行的所有进程,然后通过StartTime进行排序,最输出每个进程的名称和开启时间:

    复制代码 代码如下:

    PS C:Windowssystem32> Get-Process | Sort-Object StartTime | Select-Object Name
    ,StartTime
    Sort-Object : 获取“StartTime”时发生异常:“拒绝访问。”
    所在位置 行:1 字符: 26
    + Get-Process | Sort-Object StartTime | Select-Object Name,StartTime
    + CategoryInfo : InvalidResult: (System.Diagnostics.Process (audi
    odg):PSObject) [Sort-Object], GetValueInvocationException
    + FullyQualifiedErrorId : ExpressionEvaluation,Microsoft.PowerShell.Comman
    ds.SortObjectCommand

    当执行上面的命令行时,会收到许多错误信息。这些错误信息并不是来源于命令,而是可能因为当前控制台没有管理员权限,某些系统进程拒绝访问。输出的进程中可能有一部分进程只有进程名(Name),没有开启时间(StartTime),开启时间被抑制了。
    使用Select-Object,会删除对象的某些属性,但是对象本身的属性是不能删除的,所以ETS会在管道中重新生成一个对象,类型为:System.Management.Automation.PSCustomObject。

    复制代码 代码如下:

    PS C:Powershell> Get-Process | foreach {$_.gettype().fullname} | select -f 1
    System.Diagnostics.Process
    PS C:Powershell> (Get-Process | foreach {$_.gettype().fullname} | select -f 1 Name ).getType().fullname
    System.Management.Automation.PSCustomObject

    因为PSCustomObject在ETS配置中没有记录,就会输出全部属性。管道结果之前根据StartTime升序排列过,所以前面的进程由于权限问题没有StartTime。

    扩充ETS

    ETS配置中包含的类型对象会以最佳的方式转换成文本。但是对于未知对象就表现不完美了,表现不完美并不代表束手无策。幸运的是可以通过扩充ETS让ETS以最佳的方式处理新对象。
    扩充ETS的第一步是确定待扩充对象类型。我们可能经常通过Get-WmiObject 来获取WMI服务。但是不太喜欢Powershell对于它的默认输出,就可以扩充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

    首先确定命令返回结果的对象类型

    复制代码 代码如下:

    PS C:Powershell> $object = Get-WmiObject Win32_Processor | Select-Object -first 1
    PS C:Powershell> $object.GetType().FullName
    System.Management.ManagementObject

    发现目标类型为:System.Management.ManagementObject
    接下来创建一个配置文件:

    复制代码 代码如下:

    configuration>
    viewdefinitions>
    view>
    name>CustomView/name>
    viewselectedby>
    typename>System.Management.ManagementObject/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>

    将文件保存为Win32_Processor.format.ps1xml,然后使用命令Update-FormatData把它加载进ETS,会立即生效

    复制代码 代码如下:

    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

    但是这样的定义可能有个缺点,当我们获取其它WMI对象时,也会根据我们定义的规则显示。

    复制代码 代码如下:

    PS C:Powershell> Get-WmiObject Win32_Share

    Name         Description                    ID
    ----         -----------                    --
                 Remote Admin
                 Default share
                 HP LaserJet P2050 Series PCL6
                 Remote IPC
                 Printer Drivers

    出现上面的情况,是因为WMI的所有对象都会以System.Management.ManagementObject类型返回。因此ETS没有出错,罪魁祸首是WMI这个特殊的类型。所以扩充ETS时一定要细化一个具体的类型。事实上WMI对象有一个PSTypeNames属性,通过它就可以找到更具体的类型。

    复制代码 代码如下:

    PS C:Powershell> $object = Get-WmiObject Win32_Processor | Select-Object -first1
    PS C:Powershell> $object.PSTypeNames
    System.Management.ManagementObject#rootcimv2Win32_Processor
    System.Management.ManagementObject
    System.Management.ManagementBaseObject
    System.ComponentModel.Component
    System.MarshalByRefObject
    System.Object

    上面显示了WMI对象类型的继承层次。所以我们需求中要扩展的对象类型应该为:System.Management.ManagementObject#rootcimv2Win32_Processor

    所以应当修改配置文件,重新加载更新。更新时会有一条异常
    Update-FormatData : 加载格式数据文件时出错:
    Microsoft.PowerShell,C:PowershellWin32_Processor.format.ps1xml: 文件被跳过,
    因为该文件已在“Microsoft.PowerShell”中出现过。

    异常可以忽略,然后重新测试。

    复制代码 代码如下:

    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

    这样ETS的扩充只对Win32_Processor有效了。不会影响到其他父类型对象。

    您可能感兴趣的文章:
    • Windows Powershell分析和比较管道结果
    • Windows Powershell导出管道结果
    • Windows Powershell对象=属性+方法
    • Windows Powershell属性:描述对象是什么
    • Windows Powershell方法(对象能做什么)
    • Windows Powershell调用静态方法
    上一篇:Windows Powershell导出管道结果
    下一篇:Windows Powershell对象=属性+方法
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Windows Powershell扩展类型系统 Windows,Powershell,扩展,类型,