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有效了。不会影响到其他父类型对象。

(0)

相关推荐

  • Windows Powershell对象=属性+方法

    在现实世界中,你可能已经了解对象就是那些能够摸到的东西.Powershell中的对象和现实生活很相似.例如要在现实生活中描述一把小刀.我们可能会分两方面描述它 属性:一把小刀拥有一些特殊的属性,比如它的颜色.制造商.大小.刀片数.这个对象是红色的,重55克,有3个刀片,ABC公司生产的.因此属性描述了一个对象是什么. 方法:可以使用这个对象做什么,比如切东西.当螺丝钉用.开啤酒盖.一个对象能干什么就属于这个对象的方法. 创建对象 通过New-Object可以创建一个对象,甚至可以创建一个虚拟的小

  • Windows Powershell导出管道结果

    可以将管道的结果转换成文本输出,默认是Out-Default.可以通过Get-Command -verb out查看Powershell都有哪些输出的命令. 复制代码 代码如下: PS C:PowerShell> get-command -Verb out CommandType Name         Definition ----------- ----         ---------- Cmdlet      Out-Default  Out-Default [-InputObjec

  • Windows Powershell属性:描述对象是什么

    属性可以描述一个对象,对象的属性可以被Powershell自动转换成文本,并且输出到控制台.因此可以通过这种方法查看任何对象,例如$host: 复制代码 代码如下: PS C:Powershell> $host Name              : ConsoleHost Version           : 2.0 InstanceId            : 7fefa1fa-fb2e-47c7-a867-c13b123da5c2 UI                : System.

  • Windows Powershell方法(对象能做什么)

    方法定义了一个对象可以做什么事情.当你把一个对象输出在控制台时,它的属性可能会被转换成可视的文本.但是它的方法却不可见.列出一个对象的所有方法可是使用Get-Member命令,给"MemeberType"参数 传入"Method": 复制代码 代码如下: PS C:Powershell> $Host | Get-Member -MemberType Method TypeName: System.Management.Automation.Internal.H

  • Windows Powershell分析和比较管道结果

    使用Measure-Object和Compare-Object可以统计和对比管道结果.Measure-Object允许指定待统计对象的属性.Compare-Object可以对比对象前后的快照. 统计和计算 使用Measure-Object可以对对象的属性求最小值.最大值.平均值.和.例如要查看当前目录文件占用空间的情况. PS C:Powershell> ls | measure length Count : 19 Average : Sum : Maximum : Minimum : Prop

  • Windows Powershell调用静态方法

    Powershell将信息存储在对象中,每个对象都会有一个具体的类型,简单的文本会以System.String类型存储,日期会以System.DateTime类型存储.任何.NET对象都可以通过GetType()方法返回它的类型,该类型中有一个FullName属性,可以查看类型的完整名称. 复制代码 代码如下: PS C:Powershell> $date=get-date PS C:Powershell> $date 2012年1月11日 15:19:49 PS C:Powershell&g

  • 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 A

  • Windows Powershell 自动化变量

    Powershell 自动化变量 是那些一旦打开Powershell就会自动加载的变量. 这些变量一般存放的内容包括 用户信息:例如用户的根目录$home 配置信息:例如powershell控制台的大小,颜色,背景等. 运行时信息:例如一个函数由谁调用,一个脚本运行的目录等. PS> $HOME C:\Users\test PS> $currentProcessID=$pid PS> $currentProcessID 5356 PS> Get-Process -Id $pid H

  • Windows Powershell 别名

    简短描述 在Windows PowerShell中, 别名就是cmdlets或其他命令的替代名称. 详细描述 别名就是cmdlet或者命令(例如: 函数, 脚本, 文件, 可执行文件. )的替代名称或者说是个昵称. 在使用命令的地方, 你都可以使用别名. cmdlet 的名称由一个动词和一个名词组成,其功能对用户来讲一目了然.但是对于一个经常使用powershell命令的人每天敲那么多命令也很麻烦啊.能不能把命令缩短一点呢?于是"别名"就应运而生了.Powershell内部也实现了很多

  • Windows PowerShell是啥?看完本文你就懂它了

    引子 一直很羡慕Linux的命令提示符(当然他们叫Shell).正则表达式,管道,各种神奇的命令,组合起来就能高效完成很多复杂的任务.效率实在是高.流了n年的哈喇子以后,终于有幸用上了Win7,邂逅了cmd的升级版:Windows PowerShell.从此暗爽无比,原来Windows下也有这样的利器呀~ 看看下面的Windows脚本,不到15行有效代码.在Win7下只要右击脚本文件,选择Run with PowerShell,就会自动找到最占内存的10个进程,然后将它们占用的内存画成一个三维饼

  • Windows Powershell 介绍和安装

    Powershell 是运行在windows机器上实现系统和应用程序管理自动化的命令行脚本环境.你可以把它看成是命令行提示符cmd.exe的扩充,不对,应当是颠覆. powershell需要.NET环境的支持,同时支持.NET对象.微软之所以将Powershell 定位为Power,并不是夸大其词,因为它完全支持对象.其可读性,易用性,可以位居当前所有shell之首. 当前powershell有四版本,分别为1.0,2.0,3.0 ,4.0 如果您的系统是window7或者Windows Ser

  • Windows Powershell Where-Object 条件过滤

    过滤管道结果 使用Get-Process返回所有的当前进程 ,但是你可能并不对所有的进程感兴趣,然后通过每个Process对象的属性进行过滤.首先得知道每个对象支持那些属性. 复制代码 代码如下: PS C:Powershell> Get-Process | select -First 1 | fl * __NounName                 : Process Name                       : AcroRd32 Handles               

  • Windows Powershell使用管道

    管道并不是什么新事物,以前的Cmd控制台也有重定向的命令,例如Dir | More可以将结果分屏显示. 传统的Cmd管道是基于文本的,但是Powershell是基于对象. PS> ls | Sort-Object -Descending Name | Select-Object Name,Length,LastWriteTime | ConvertTo-Html | Out-File ls.html PS> Get-Content .ls.html Name Length LastWriteT

  • Windows PowerShell 微软官方解释

    通过提供一百多种系统管理实用工具.一致的语法.及对普通管理数据更好地导航(如登记或 Windows Management Instrumentation (WMI)),Windows PowerShell 使 Windows 管理员提高了生产力.Windows PowerShell 还包括全面启动 Windows 系统自动化管理任务的脚本编写语言.Windows PowerShell 语言是直观的,并支持贵企业现有的脚本和命令行工具投入.Exchange Server 2007 和 System

  • Windows Powershell 通过函数扩展别名

    在Powershell中设置别名的确方便快捷,但是在设置别名的过程中并设置参数的相关信息.尽管别名会自动识别参数,但是如何把经常使用的参数默认设定在别名里面呢?例如Test-Connection -Count 2 -ComputerName,让-"-Count 2″ 固化在别名中. 这时简单的别名无法完成上述需求,可以通过函数来完成它,并且一旦把函数拉过来,定义别名会变得更加灵活. PS C:\PS> function test-conn { Test-Connection -Count

随机推荐