PowerShell 教程

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

2019-02-28  本文已影响17人  rollingstarky

重定向与管道

重定向

可以借助管道符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

上一篇下一篇

猜你喜欢

热点阅读