• PowerShell笔记


    本系列是一个重新学习PowerShell的笔记,内容引用自PowerShell中文博客

    使用管道

    排序导并导出JSON格式文件

    PS C:Code> ls | Sort-Object -Descending Name | Select-Object -First 1 Name,Length,LastWriteTime | ConvertTo-Json | Out-File ls.txt                                                                                                             PS C:Code> Get-Content .ls.txt
    {
        "Name":  "Redis",
        "Length":  null,
        "LastWriteTime":  "/Date(1623377222092)/"
    }
    
    首先列出当前目录下的目录和文件,然后根据文件名降序排列,再投影文件名,文件大小,文件的修改时间,转换成Html格式,输出到当前目录的ls.txt
    

    面向对象的管道

    上面的例子属于面向对象的管道,每个命令的末尾可以使用新的命令对上个命令的结果做进一步处理,除非管道是以输出命令结束的。就像Sort-Object一样,对文件的列表进行排序,需要告诉它排序的关键字,按照升序还是降序。ls的返回值为一个数组,数组中的每一个元素都是一个对象,对象的每一个属性都可以作为Sort-Object的排序关键字。但是排序时必须指定一个具体的关键字,因为Powershell所传递的对象可能有很多属性。不像普通的文本,对象的信息都是结构化的,因此也使得Powershell的管道变得更加强大和方便。

    转换命令执行的结果为文本

    在执行Powershell命令时,解释器会默认在命令的结尾追加一个管道命令,Out-Default,这样可以将原来的对象结果以文本的形式显示在控制台上,但是并没有将结果进行转换,所以可以继续使用其它管道对对象的结果进行操作,但是一旦使用了诸如ConvertTo-JSON这样的命令后,就会将结果转换成固定格式的纯文本。

    常用管道命令

        #常用的对管道结果进一步处理的命令有:
        Compare-Object: 比较两组对象。
        ConvertTo-Html: 将 Microsoft .NET Framework 对象转换为可在 Web 浏览器中显示的 HTML。
        Export-Clixml: 创建对象的基于 XML 的表示形式并将其存储在文件中。
        Export-Csv: 将 Microsoft .NET Framework 对象转换为一系列以逗号分隔的、长度可变的 (CSV) 字符串,并将这些字符串保存到一个 CSV 文件中。
        ForEach-Object: 针对每一组输入对象执行操作。
        Format-List: 将输出的格式设置为属性列表,其中每个属性均各占一行显示。
        Format-Table: 将输出的格式设置为表。
        Format-Wide: 将对象的格式设置为只能显示每个对象的一个属性的宽表。
        Get-Unique: 从排序列表返回唯一项目。
        Group-Object: 指定的属性包含相同值的组对象。
        Import-Clixml: 导入 CLIXML 文件,并在 Windows PowerShell 中创建相应的对象。
        Measure-Object: 计算对象的数字属性以及字符串对象(如文本文件)中的字符数、单词数和行数。
        more: 对结果分屏显示。
        Out-File: 将输出发送到文件。
        Out-Null: 删除输出,不将其发送到控制台。
        Out-Printer: 将输出发送到打印机。
        Out-String: 将对象作为一列字符串发送到主机。
        Select-Object: 选择一个对象或一组对象的指定属性。它还可以从对象的数组中选择唯一对象,也可以从对象数组的开头或末尾选择指定个数的对象。
        Sort-Object: 按属性值对象进行排序。
        Tee-Object: 将命令输出保存在文件或变量中,并将其显示在控制台中。
        Where-Object: 创建控制哪些对象沿着命令管道传递的筛选器。
    

    管道的处理模式

    当我们把许多命名组合成一个管道时,可能会感兴趣每一个命令的执行时是顺序执行还是同时执行?通过管道处理结果实际上是实时的。这就是为什么存在两个管道模式:

    顺序模式(较慢)
    在顺序模式中管道中同一时间只执行一条命令,只有当前一条命令的所有执行完毕,才会把所有结果交付给下一条 命令。这种模式速度慢并且耗内存,因为必须需要很多次分配空间存储中间结果。
    
    流模式(较快)
    流模式会立即执行所有命令,同一时间可能在执行多条命令。前一条命令可能会产生多个结果,但是一旦产生其中一个结果,就会立即交付给下一条命令处理。这样的流模式节省比较节省内存,可能管道的某个任务还在执行,但是已经有部分结果输出了。减少了中间结果的保存。
    

    管道命令的阻塞

    可以使用Sort-Object对管道的结果进行排序,但是有时候排序可能导致整个操作系统阻塞,因为排序命令的的执行属于顺序模式,必须得上一条命令的结果全部完成,才能排序。
    因此在使用这类命令时,要注意操作对象的大小,和它们需要的内存。例如这条命令:
    Dir C: -recurse | Sort-Object -recurse 选项是递归查询子目录,可想而知系统盘的文件和目录有多大。
    这条命令一旦运行起来,需要等很长很长的时间,甚至可能导致系统崩溃,得重启电脑。
    你可以在执行这条命令时,打开任务管理器查看Powershell进程的内存占用在以每秒种几十兆的速率增加。
    到底哪些命令可能系统阻塞,要视命令的实现方式以及处理的对象大小决定,例如Sort-object导致阻塞的原因肯定是由于技术实现上采用的是内排序,没有使用外排序。
    但是象Out-Host -paging 这样的命令属于流出来模式,就一般不会导致系统阻塞。

    将对象转换为文本

    怎样将Powershell的对象结果转换成文本并显示在控制台上。Powershell已经内置Out-Default命令追加在管道的命令串的末尾。因此你使用dir 和dir | out-default的结果是相同的。
    Out-Default可以将对象转换成可视的文本。事实上Out-Default会首先调用Format-Table,将更多的属性默认隐藏。再调用Out-Host将结果输出在控制台上。因此下面的四组命令执行结果是相同的。
    
    PS C:Code> ls                                                                                                  PS C:Code> ls | Format-Table                                                                                   PS C:Code> ls | Format-Table | Out-Default                                                                     PS C:Code> ls | Format-Table | Out-Default |Out-Host  
    
    #显示隐藏的对象属性
    PS C:Code	estdir> ls | Format-Table *
    
    #使用通配符显示进程的名字和其它以”pe”打头,以”64″结尾的进程。
    PS C:Code> Get-Process i* | Format-Table Name,pe*64                                                                                                                                         
    Name                                PeakPagedMemorySize64 PeakWorkingSet64 PeakVirtualMemorySize64
    ----                                --------------------- ---------------- -----------------------
    ibmpmsvc                                          2994176          9728000              4404154368
    Idle                                                61440            12288                    8192
    igfxCUIService                                    3088384         12537856           2203426746368
    
    #添加定义列
    PS C:Code> ls | Format-Table Name,{ [int]($_.Length/1kb) }                                                                                                                                  
    Name                   [int]($_.Length/1kb)
    ----                  ----------------------
    0605                                       0
    0707                                       0
    0811                                       0
    0917                                       0
    1020                                       0
    1201                                       0
    
    #定义列头
    PS C:Code> $column = @{Expression={ [int]($_.Length/1KB) }; Label="KB" }                                                                                                                    PS C:Code> ls | Format-Table Name,$column                                                                                                                                                   
    Name                  KB
    ----                  --
    0605                   0
    0707                   0
    0811                   0
    0917                   0
    

    排序及分组

    #分组
    PS C:Code> ls | Group-Object Extension |Format-Table Name,Count                                                                                                                             
    Name  Count
    ----  -----
             18
    .xlsx     1
    .txt      1
    
    #排序
    PS C:Code> ls | Group-Object Extension |Sort-Object @{expression="Count";Descending=$true},@{expression="Name";Ascending=$true} |Format-Table Name,Count                                    
    Name  Count
    ----  -----
             18
    .txt      1
    .xlsx     1
    
    

    分析和对比

    使用Measure-Object和Compare-Object可以统计和对比管道结果。
    Measure-Object允许指定待统计对象的属性。Compare-Object可以对比对象前后的快照。
    

    统计和计算

    #统计
    PS C:Code> ls | Measure-Object Length                                                                                  
    
    Count    : 2 #文件数量
    Average  :
    Sum      :
    Maximum  :
    Minimum  :
    Property : Length
    
    #指定统计最大最小等
    PS C:Code> ls | Measure-Object Length -Average -Sum -Maximum -Minimum
    
    Count    : 2
    Average  : 6566
    Sum      : 13132
    Maximum  : 12930
    Minimum  : 202
    Property : Length
    
    #统计文本文件内的行、字、词等
    PS C:Code> Get-Content .ls.txt | Measure-Object -Line -Word -Character
    
    Lines Words Characters Property
    ----- ----- ---------- --------
        5     8         90
    

    对比

    PS C:Code> $d1 = Get-Date
    PS C:Code> $d2 = Get-Date
    PS C:Code> Compare-Object $d1 $d2
    
    InputObject        SideIndicator
    -----------        -------------
    2021/9/10 17:45:50 => #新增项
    2021/9/10 17:45:36 <= #删除项
    
    #指定属性对比
    PS C:Code> $h1 = @{N=1}
    PS C:Code> $h2 = @{N=2}
    PS C:Code> Compare-Object $h1 $h2 -Property Values
    
    Values SideIndicator
    ------ -------------
    {2}    =>
    {1}    <=
    
    PS C:Code> Compare-Object $h1 $h2 -Property Keys
    

    扩展类型系统

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

    PS C:> dir | Select-Object -First 1 | Format-Table *  -Wrap
    PSPath  PSParentPath    PSChildName     PSDrive
    ------
    

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

    文本转换不可逆

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

    PS C:> $test = Dir |Out-String                                                                                                                                                    PS C:> $test                                                                                                                                                                      
    
        Directory: C:
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----        2021/6/10     14:40                8001
    d-----        2021/6/11     10:12                8002
    d-----        2021/6/11     10:12                8003
    
    PS C:> $test | Format-List
    
    
        Directory: C:
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----        2021/6/10     14:40                8001
    d-----        2021/6/11     10:12                8002
    d-----        2021/6/11     10:12                8003
    
    
    PS C:> dir | Format-List                                                                                                                                                          
    
        Directory: C:
    
    Name           : 8001
    CreationTime   : 2021/6/10 13:43:27
    LastWriteTime  : 2021/6/10 14:40:50
    LastAccessTime : 2021/6/10 14:40:50
    Mode           : d-----
    LinkType       :
    Target         : {}
    
    

    已知对象格式化

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

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

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

    PS C:> dir $PSHOME *format.ps1*                                                                                                                                                   
    
        Directory: C:WindowsSystem32WindowsPowerShellv1.0
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        2019/3/19     12:46          12825 Certificate.format.ps1xml
    -a----        2019/3/19     12:46           5074 Diagnostics.Format.ps1xml
    -a----        2019/3/19     12:46         138223 DotNetTypes.format.ps1xml
    -a----        2019/3/19     12:46          10144 Event.Format.ps1xml
    -a----        2019/3/19     12:46          25526 FileSystem.format.ps1xml
    -a----        2019/3/19     12:46          91655 Help.format.ps1xml
    -a----        2019/3/19     12:46         138625 HelpV3.format.ps1xml
    -a----        2019/3/19     12:46         206468 PowerShellCore.format.ps1xml
    -a----        2019/3/19     12:46           4097 PowerShellTrace.format.ps1xml
    -a----        2019/3/19     12:46           8458 Registry.format.ps1xml
    -a----        2019/3/19     12:46          16598 WSMan.Format.ps1xml
    

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

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

    未知对象格式化

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

    PS C:> $obj = New-Object psobject                                                                            PS C:> Add-Member -MemberType NoteProperty -Name "A" -Value "1" -InputObject $obj                            PS C:> $obj                                                                                                  
    A
    -
    1
    
    
    PS C:> Add-Member -MemberType NoteProperty -Name "B" -Value "2" -InputObject $obj                            PS C:> Add-Member -MemberType NoteProperty -Name "C" -Value "3" -InputObject $obj                            PS C:> $obj                                                                                                  
    A B C
    - - -
    1 2 3
    
    
    PS C:> Add-Member -MemberType NoteProperty -Name "D" -Value "4" -InputObject $obj                            PS C:> Add-Member -MemberType NoteProperty -Name "E" -Value "5" -InputObject $obj                            PS C:> $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:> Get-Process | Sort-Object StartTime | Select-Object Name                                              Sort-Object : Exception getting "StartTime": "Access is denied"
    At line:1 char:15
    + Get-Process | Sort-Object StartTime | Select-Object Name
    +               ~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidResult: (System.Diagnostics.Process (1E.Client):PSObject) [Sort-Object], GetValue
       InvocationException
        + FullyQualifiedErrorId : ExpressionEvaluation,Microsoft.PowerShell.Commands.SortObjectCommand
    
    

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

    PS C:> Get-Process | foreach{$_.GetType().FullName} | Select-Object -First 1                                 System.Diagnostics.Process
    PS C:> (Get-Process | foreach{$_.GetType().FullName} | Select-Object -First 1 Name).GetType().FullName       System.Management.Automation.PSCustomObject
    

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

  • 相关阅读:
    2019左其盛好书榜,没见过更好的榜单(截至4月30日)
    3星|菲利普·科特勒《我的营销人生》:大师一生经历、成就、著作回顾
    3星|樊登《低风险创业》:创业相关的书+樊登个人创业经验
    OKR能解决996吗?德鲁克怎么看?
    《中国合伙人》背后的故事:4星|俞敏洪《我曾走在崩溃的边缘》
    3星|路江涌《共演战略画布》:PPT技巧级别的创新,缺实际分析案例
    C# 通用数据库配置界面,微软原生DLL重整合
    SoapUI、Jmeter、Postman三种接口测试工具的比较分析
    用VS制作的windows服务安装包 安装完后如何让服务自动启动
    POI使用详解
  • 原文地址:https://www.cnblogs.com/MerLin-LiuNian/p/15261930.html
Copyright © 2020-2023  润新知