美文网首页PowerShell 教程
Windows PowerShell 学习笔记其二(变量与控制语

Windows PowerShell 学习笔记其二(变量与控制语

作者: rollingstarky | 来源:发表于2019-02-28 21:31 被阅读17次

    重定向与管道

    重定向

    可以借助管道符Out-File 命令将某个命令的输出内容重定向至文本文件中。

    如:Get-ChildItem | Out-File files.txt
    通过 Get-ChildItem(即 dir)获取当前目录下的文件列表,再借助管道和 Out-File 将列表保存在 files.txt 文件中。

    在使用 Out-File 命令时可以带上 -Encoding 等选项来指定输出文件的编码等属性:
    Get-Content filename.cs | Out-File -Encoding ASCII file.txt
    Get-ChildItem | Out-File -Width 120 files.cs

    或者也可以使用类似 bash 里的 > 符号:
    Get-ChildItem > files.txt
    Get-ChildItem 2> errors.txt
    Get-ChildItem n> otherStreams.txt

    在文件末尾添加内容

    在使用 Out-File 命令的同时,可以附加上 -Append 选项用来指明在文件末尾添加内容,如:
    Get-ChildItem | Out-File -Append files.txt

    同样也可以使用类似于 bash 中的 >> 符号:
    Get-ChildItem >> files.txt

    管道

    简单来说,管道可以用来连接多个命令,使得上一个命令的输出作为下一个命令的输入,从而将多个命令以“首尾相接”的方式执行。

    Get-Process | Where-Object WorkingSet -gt 100mb | Sort-Object -Descending WS
    获取系统当前的进程信息,并筛选出内存占用大于 100MB 的进程,再将筛选结果按照占用的内存由大到小排序后输出。

    PS C:\Users\starky> Get-Process | Where-Object WorkingSet -gt 100mb | Sort-Object -Descending WS
    
    Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
    -------  ------    -----      -----     ------     --  -- -----------
        997      75   342180     249576   1,265.59   8516   0 MsMpEng
       1598     103   147168     203348      40.02   5992   3 SearchUI
        806      29   167004     173960     186.02   5288   3 chrome
       1757     182    75120     153712     195.45  13116   3 chrome
       2816     134    89428     124596     126.25   1480   3 explorer
        367      38    83872     116840      74.64    416   3 chrome
    
    
    筛选(Where-Object)

    Where-Object 命令可以对某个列表内容或命令的输出应用各种类型的筛选条件。它的默认别名为 where?

    Get-Process | Where-Object { $_.Name -like "Baidu*" }
    获取当前系统中名字以“Baidu”开头的进程及其信息

    上面的命令同时也可以这样表述:
    Get-Process | Where-Object Name -like "Baidu*"

    即先通过 Get-Process 命令获取全部进程信息,再将它们传递给 Where-Object 命令。而 Where-Object 又指定每一个进程的 Name 属性(即进程名称)与模式 Baidu* 进行匹配,最后只输出匹配的结果。

    PS C:\Users\starky> gps | where { $_.Name -like "Baidu*" }
    
    Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
    -------  ------    -----      -----     ------     --  -- -----------
       1030     251    58288      98076     552.59    204   3 BaiduNetdisk
        187      14    11952       8628       0.06   4856   3 BaiduNetdiskHost
    

    其他示例如筛选未响应的进程:
    Get-Process | where { -not $_.Responding }

    筛选已经停止的服务:
    Get-Process | where { $_.Status -eq "Stopped" }

    遍历(Foreach-Object)

    Foreach-Object 命令(默认别名为 foreach%)用于对某个列表中的每一个对象指定特定的操作。如:

    PS C:\Users\starky> 1..5 | Foreach-Object { $_ * 2 }
    2
    4
    6
    8
    10
    

    又比如筛选当前目录下所有的文本文件,并去掉它们的只读属性:
    Get-ChildItem *.txt | Foreach-Object { attrib -r $_ }

    其中 $_ 表示传递给 Foreach-Object 的每一个对象。attrib -r $_ 即表示对 Get-ChildItem *.txt 获取到的所有文本文件去除只读属性。

    又如:

    PS C:\Users\starky> $myArray = 1,2,3,4,5
    PS C:\Users\starky> $sum = 0
    PS C:\Users\starky> $myArray | Foreach-Object { $sum += $_ }
    PS C:\Users\starky> $sum
    15
    

    上面的命令也可以使用如下形式:

    PS C:\Users\starky> $myArray = 1,2,3,4,5
    PS C:\Users\starky> $myArray | Foreach-Object { $sum = 0 } { $sum += $_ } { $sum }
    15
    
    格式化输出

    PowerShell 中的许多命令默认情况下是以“表格”的形式来格式化输出的,如:

    PS C:\Users\starky> Get-Process PowerShell
    
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
        410      41    60444      75004   550     3.21   4212 powershell
        428      43    60688      56684   561     4.04   5288 powershell
    

    实际上在多数情况下,命令的“真实”输出包含了更加丰富的信息,可以使用 Format-List 命令比较一下效果:

    PS C:\Users\starky> Get-Process PowerShell | Format-List *
    
    
    __NounName                 : Process
    Name                       : powershell
    Handles                    : 404
    VM                         : 575397888
    WS                         : 76754944
    PM                         : 61808640
    NPM                        : 41736
    Path                       : C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe
    Company                    : Microsoft Corporation
    CPU                        : 3.2136206
    FileVersion                : 6.3.9600.16406 (winblue_gdr_oob.130926-1103)
    ProductVersion             : 6.3.9600.16406
    Description                : Windows PowerShell
    Product                    : Microsoft® Windows® Operating System
    Id                         : 4212
    PriorityClass              : Normal
    HandleCount                : 404
    WorkingSet                 : 76754944
    PagedMemorySize            : 61808640
    PrivateMemorySize          : 61808640
    VirtualMemorySize          : 575397888
    TotalProcessorTime         : 00:00:03.2136206
    BasePriority               : 8
    ...
    

    Format-List 是 4 种格式化输出的命令之一,其他还有 Format-TableFormat-WideFormat-CustomFormat-List 用来接收输入内容并将其以列表的形式输出。

    默认情况下,不带任何参数的格式化命令只会输出对象的一小部分属性,如:

    PS C:\Users\starky> Get-Process PowerShell | Format-List
    
    Id      : 4212
    Handles : 428
    CPU     : 3.4632222
    Name    : powershell
    
    Id      : 5288
    Handles : 392
    CPU     : 4.1028263
    Name    : powershell
    

    Format-List * 则会显示输入对象的所有属性。

    同时,也可以在格式化命令后面手动指定需要显示的属性或参数,如:

    PS C:\Users\starky> Get-Process PowerShell | Format-Table Id,Name,CPU,WS -Auto
    
      Id Name             CPU       WS
      -- ----             ---       --
    4212 powershell 3.7128238 78704640
    5288 powershell 4.1028263 58068992
    

    变量与对象

    变量

    在 PowerShell 中,可以将命令的输出或其他内容先保存在某个变量(以 $ 符号为前缀)中,以供后续使用(甚至可以把变量直接传递给管道符)。

    PS C:\Users\starky> $result = 2 + 2
    PS C:\Users\starky> $result
    4
    PS C:\Users\starky> $processes = Get-Process
    PS C:\Users\starky> $processes.Count
    64
    PS C:\Users\starky> $processes | Where-Object { $_.ID -eq 0 }
    
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
          0       0        0         24     0               0 Idle
    
    访问环境变量

    PowerShell 可以很轻松地访问系统中定义的环境变量,如使用 Get-ChildItem env: 命令获取当前系统已定义的所有环境变量的列表:

    PS C:\Users\starky> Get-ChildItem env:
    
    Name                           Value
    ----                           -----
    ALLUSERSPROFILE                C:\ProgramData
    APPDATA                        C:\Users\starky\AppData\Roaming
    CommonProgramFiles             C:\Program Files\Common Files
    CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
    CommonProgramW6432             C:\Program Files\Common Files
    COMPUTERNAME                   Starky-Lenovo
    ComSpec                        C:\windows\system32\cmd.exe
    FP_NO_HOST_CHECK               NO
    HOMEDRIVE                      C:
    HOMEPATH                       \Users\starky
    LOCALAPPDATA                   C:\Users\starky\AppData\Local
    ...
    

    也可以使用 $env:variablename 形式的变量名直接表示系统环境变量。几种形式的示例如下:

    PS C:\Users\starky> Get-ChildItem env:username
    
    Name                           Value
    ----                           -----
    USERNAME                       starky
    
    
    PS C:\Users\starky> Get-ChildItem Environment::username
    
    Name                           Value
    ----                           -----
    USERNAME                       starky
    
    
    PS C:\Users\H19038> $env:username
    starky
    
    作用域

    创建一个只在特定范围内生效的变量,使用如下形式的语法:
    $SCOPE:variable = value

    获取特定的作用域里某个变量的值,使用如下形式的语法:
    $SCOPE:variable

    如创建一个在脚本执行完毕后仍旧有效的变量,使用 GLOBAL 作用域:
    $GLOBAL:variable = value

    在某个函数内部更改脚本范围内的变量,需要显式地指定 SCRIPT 作用域:
    $SCRIPT:variable = value

    PowerShell 中变量的作用域,就是控制各变量在不同范围内的可见性。比如当进入一个代码块、函数或别名时,当前的作用域成为新的“本地作用域”(子作用域),原来的作用域则成为“父作用域”。
    子作用域可以访问父作用域中定义的所有变量,但是没有权限直接修改这些变量的值。
    换句话说,子作用域可以修改在父作用域中定义的变量,但是这种修改不会将新值自动同步到父作用域。

    .NET 对象

    PowerShell 可以直接访问 .NET 对象的方法(包括静态方法和实例)和属性,比如访问某个静态方法:
    [ClassName]::MethodName(parameter list)

    访问某个对象实例绑定的方法:
    $objectReference.MethodName(parameter list)

    访问某个类的静态属性:
    [ClassName]::PropertyName

    访问某个对象实例的属性:
    $objectReference.PropertyName

    下面是一些具体的例子。

    静态方法

    PS C:\Users\starky> [System.Diagnostics.Process]::GetProcessById(0)
    
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
          0       0        0         24     0               0 Idle
    

    实例方法

    PS C:\Users\starky> $now = Get-Date
    PS C:\Users\starky> $now.ToString()
    2019/2/27 15:34:21
    

    静态属性

    PS C:\Users\starky> [System.DateTime]::Now
    
    2019年2月27日 15:36:09
    

    实例属性

    PS C:\Users\starky> $today = Get-Date
    PS C:\Users\starky> $today.DayOfWeek
    Wednesday
    
    创建对象的实例

    使用 New-Object 命令可以创建某个 .NET 对象的实例。如:

    PS C:\Users\starky> $generator = New-Object System.Random
    PS C:\Users\starky> $generator.NextDouble()
    0.697396862179691
    

    也可以在创建实例的同时直接使用它:

    PS C:\Users\starky> (New-Object Net.WebClient).DownloadString("http://www.baidu.com")
    <!DOCTYPE html><!--STATUS OK-->
    <html>
    <head>
    ...
    

    通常的做法是,创建对象实例的同时,还要为其指定某些属性。如:

    PS C:\Users\starky> $startInfo = New-Object Diagnostics.ProcessStartInfo -Property @{
    >> 'Filename' = "powershell.exe";
    >> 'WorkingDirectory' = $HOMEPATH;
    >> 'Verb' = "RunAs"
    >> }
    >>
    PS C:\Users\starky> [Diagnostics.Process]::Start($startInfo)
    
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
          4       2      260       1224     6     0.00   6248 powershell
    

    上述命令中创建 Diagnostics.ProcessStartInfo 对象的语句也可以简写为如下形式:

    $startInfo = [Diagnostics.ProcessStartInfo] @{
        'Filename' = "powershell.exe";
        'WorkingDirectory' = $HOMEPATH;
        'Verb' = "RunAs"
    }
    

    有时候为了简写 .NET 类的完整名称,可以借助变量赋值,如:

    PS C:\Users\starky> $math = [System.Math]
    PS C:\Users\starky> $math::Min(1,10)
    1
    PS C:\Users\starky> $math::Sin(3.14)
    0.00159265291648683
    

    循环与流程控制

    比较与逻辑运算

    PowerShell 支持的比较运算符
    -eq, -ne, -gt, -in, -notin, -lt, -le, -like, -notlike, -match, -notmatch, -contains, -notcontains, -is, -isnot

    逻辑运算符
    -and, -or, -xor, -not

    逻辑与比较运算符可以用来在数据间进行比较,同时也可以测试当前某些特定的条件是否成立。
    如判断当前目录下的文件个数是否大于等于 4:

    PS C:\Users\starky> (dir).Count -ge 4
    True
    

    某个字符串是否匹配特定的正则表达式:

    PS C:\Users\starky> "Hello World" -match "H.*World"
    True
    

    默认情况下,PowerShell 里的比较运算是区分大小写的,如果想不区分大小写,可以使用如下版本的比较运算符:
    -ceq, -cne, -cge, -cgt, -cin, -clt, -cle, -clike, -cnotlike, -cmatch, -cnotmatch, -ccontains, -cnotcontains

    逻辑运算符可以组合多个值为 truefalse 的语句,并根据运算符号的不同返回特定的逻辑运算结果。
    比如判断某个字符串是否匹配特定模式,且字符串长度大于 10:

    PS C:\Users\starky> $data = "Hello World"
    PS C:\Users\starky> ($data -like "*llo W*") -and ($data.Length -gt 10)
    True
    
    条件语句

    PowerShell 中的 if 语句基本用法如下:

    $temperature = 35
    
    if($temperature -le 0)
    {
        "Freezing"
    }
    elseif($temperature -le 10)
    {
        "Cold"
    }
    elseif($temperature -le 20)
    {
        "Warm"
    }
    else
    {
        "Hot"
    }
    

    除了流程控制,条件语句也经常用来对变量进行赋值,形式如下:

    PS C:\Users\starky> $result = if(Get-Process -n notepad) { "Running" } else { "Not running" }
    Get-Process : 找不到名为“notepad”的进程。请验证该进程名称,然后再次调用 cmdlet。
    ...
    
    PS C:\Users\starky> $result
    Not running
    

    通常情况下,使用 switch 语句可以替代包含大量 if ... elseif ... else 的语句。
    PowerShell 的 switch 在对用户输入进行条件判断时,支持多种选项的使用,如通配符正则表达式甚至简短的代码块,相比于 C 和 C++ 中的 switch 语句更显得强大。

    $temperature = 35
    
    switch($temperature)
    {
        { $_ -lt 0 }    { "Below Freezing"; break }
        32              { "Exactly Freezing"; break }
        { $_ -le 10 }   { "Cold"; break }
        { $_ -le 20 }   { "Warm"; break }
        default         { "Hot" }
    }
    
    循环

    for 循环

    for($counter = 1; $counter -le 10; $counter++)
    {
        "Loop number $counter"
    }
    

    foreach 循环

    foreach($file in dir)
    {
        "File name: " + $file.Name
    }
    

    或者:dir | foreach { "File name: " + $_.Name }

    while 循环

    $response = ""
    while($response -ne "QUIT")
    {
        $response = Read-Host "Type something"
    }
    

    do..while 循环

    $response = ""
    do
    {
        $response = Read-Host "Type something"
    } while($response -ne "QUIT")
    

    do..until 循环:

    $response = ""
    do
    {
        $response = Read-Host "Type something"
    } until($response -eq "QUIT")
    

    参考书籍

    Windows PowerShell Cookbook, 3rd Edition

    相关文章

      网友评论

        本文标题:Windows PowerShell 学习笔记其二(变量与控制语

        本文链接:https://www.haomeiwen.com/subject/fvfxyqtx.html