重定向與管道
重定向
可以借助管道符和 Out-File 命令將某個(gè)命令的輸出內(nèi)容重定向至文本文件中。
如:Get-ChildItem | Out-File files.txt
通過(guò) Get-ChildItem(即 dir)獲取當(dāng)前目錄下的文件列表,再借助管道和 Out-File 將列表保存在 files.txt 文件中。
在使用 Out-File 命令時(shí)可以帶上 -Encoding 等選項(xiàng)來(lái)指定輸出文件的編碼等屬性:
Get-Content filename.cs | Out-File -Encoding ASCII file.txt
Get-ChildItem | Out-File -Width 120 files.cs
或者也可以使用類似 bash 里的 > 符號(hào):
Get-ChildItem > files.txt
Get-ChildItem 2> errors.txt
Get-ChildItem n> otherStreams.txt
在文件末尾添加內(nèi)容
在使用 Out-File 命令的同時(shí),可以附加上 -Append 選項(xiàng)用來(lái)指明在文件末尾添加內(nèi)容,如:
Get-ChildItem | Out-File -Append files.txt
同樣也可以使用類似于 bash 中的 >> 符號(hào):
Get-ChildItem >> files.txt
管道
簡(jiǎn)單來(lái)說(shuō),管道可以用來(lái)連接多個(gè)命令,使得上一個(gè)命令的輸出作為下一個(gè)命令的輸入,從而將多個(gè)命令以“首尾相接”的方式執(zhí)行。
Get-Process | Where-Object WorkingSet -gt 100mb | Sort-Object -Descending WS
獲取系統(tǒng)當(dāng)前的進(jìn)程信息,并篩選出內(nèi)存占用大于 100MB 的進(jìn)程,再將篩選結(jié)果按照占用的內(nèi)存由大到小排序后輸出。
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 命令可以對(duì)某個(gè)列表內(nèi)容或命令的輸出應(yīng)用各種類型的篩選條件。它的默認(rèn)別名為 where 和 ?。
Get-Process | Where-Object { $_.Name -like "Baidu*" }
獲取當(dāng)前系統(tǒng)中名字以“Baidu”開(kāi)頭的進(jìn)程及其信息
上面的命令同時(shí)也可以這樣表述:
Get-Process | Where-Object Name -like "Baidu*"
即先通過(guò) Get-Process 命令獲取全部進(jìn)程信息,再將它們傳遞給 Where-Object 命令。而 Where-Object 又指定每一個(gè)進(jìn)程的 Name 屬性(即進(jìn)程名稱)與模式 Baidu* 進(jìn)行匹配,最后只輸出匹配的結(jié)果。
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
其他示例如篩選未響應(yīng)的進(jìn)程:
Get-Process | where { -not $_.Responding }
篩選已經(jīng)停止的服務(wù):
Get-Process | where { $_.Status -eq "Stopped" }
遍歷(Foreach-Object)
Foreach-Object 命令(默認(rèn)別名為 foreach 和 %)用于對(duì)某個(gè)列表中的每一個(gè)對(duì)象指定特定的操作。如:
PS C:\Users\starky> 1..5 | Foreach-Object { $_ * 2 }
2
4
6
8
10
又比如篩選當(dāng)前目錄下所有的文本文件,并去掉它們的只讀屬性:
Get-ChildItem *.txt | Foreach-Object { attrib -r $_ }
其中 $_ 表示傳遞給 Foreach-Object 的每一個(gè)對(duì)象。attrib -r $_ 即表示對(duì) 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 中的許多命令默認(rèn)情況下是以“表格”的形式來(lái)格式化輸出的,如:
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
實(shí)際上在多數(shù)情況下,命令的“真實(shí)”輸出包含了更加豐富的信息,可以使用 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-Table、Format-Wide、Format-Custom。Format-List 用來(lái)接收輸入內(nèi)容并將其以列表的形式輸出。
默認(rèn)情況下,不帶任何參數(shù)的格式化命令只會(huì)輸出對(duì)象的一小部分屬性,如:
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 * 則會(huì)顯示輸入對(duì)象的所有屬性。
同時(shí),也可以在格式化命令后面手動(dòng)指定需要顯示的屬性或參數(shù),如:
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
變量與對(duì)象
變量
在 PowerShell 中,可以將命令的輸出或其他內(nèi)容先保存在某個(gè)變量(以 $ 符號(hào)為前綴)中,以供后續(xù)使用(甚至可以把變量直接傳遞給管道符)。
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
訪問(wèn)環(huán)境變量
PowerShell 可以很輕松地訪問(wèn)系統(tǒng)中定義的環(huán)境變量,如使用 Get-ChildItem env: 命令獲取當(dāng)前系統(tǒng)已定義的所有環(huán)境變量的列表:
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 形式的變量名直接表示系統(tǒng)環(huán)境變量。幾種形式的示例如下:
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
作用域
創(chuàng)建一個(gè)只在特定范圍內(nèi)生效的變量,使用如下形式的語(yǔ)法:
$SCOPE:variable = value
獲取特定的作用域里某個(gè)變量的值,使用如下形式的語(yǔ)法:
$SCOPE:variable
如創(chuàng)建一個(gè)在腳本執(zhí)行完畢后仍舊有效的變量,使用 GLOBAL 作用域:
$GLOBAL:variable = value
在某個(gè)函數(shù)內(nèi)部更改腳本范圍內(nèi)的變量,需要顯式地指定 SCRIPT 作用域:
$SCRIPT:variable = value
PowerShell 中變量的作用域,就是控制各變量在不同范圍內(nèi)的可見(jiàn)性。比如當(dāng)進(jìn)入一個(gè)代碼塊、函數(shù)或別名時(shí),當(dāng)前的作用域成為新的“本地作用域”(子作用域),原來(lái)的作用域則成為“父作用域”。
子作用域可以訪問(wèn)父作用域中定義的所有變量,但是沒(méi)有權(quán)限直接修改這些變量的值。
換句話說(shuō),子作用域可以修改在父作用域中定義的變量,但是這種修改不會(huì)將新值自動(dòng)同步到父作用域。
.NET 對(duì)象
PowerShell 可以直接訪問(wèn) .NET 對(duì)象的方法(包括靜態(tài)方法和實(shí)例)和屬性,比如訪問(wèn)某個(gè)靜態(tài)方法:
[ClassName]::MethodName(parameter list)
訪問(wèn)某個(gè)對(duì)象實(shí)例綁定的方法:
$objectReference.MethodName(parameter list)
訪問(wèn)某個(gè)類的靜態(tài)屬性:
[ClassName]::PropertyName
訪問(wèn)某個(gè)對(duì)象實(shí)例的屬性:
$objectReference.PropertyName
下面是一些具體的例子。
靜態(tài)方法:
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
實(shí)例方法:
PS C:\Users\starky> $now = Get-Date
PS C:\Users\starky> $now.ToString()
2019/2/27 15:34:21
靜態(tài)屬性:
PS C:\Users\starky> [System.DateTime]::Now
2019年2月27日 15:36:09
實(shí)例屬性:
PS C:\Users\starky> $today = Get-Date
PS C:\Users\starky> $today.DayOfWeek
Wednesday
創(chuàng)建對(duì)象的實(shí)例
使用 New-Object 命令可以創(chuàng)建某個(gè) .NET 對(duì)象的實(shí)例。如:
PS C:\Users\starky> $generator = New-Object System.Random
PS C:\Users\starky> $generator.NextDouble()
0.697396862179691
也可以在創(chuàng)建實(shí)例的同時(shí)直接使用它:
PS C:\Users\starky> (New-Object Net.WebClient).DownloadString("http://www.baidu.com")
<!DOCTYPE html><!--STATUS OK-->
<html>
<head>
...
通常的做法是,創(chuàng)建對(duì)象實(shí)例的同時(shí),還要為其指定某些屬性。如:
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
上述命令中創(chuàng)建 Diagnostics.ProcessStartInfo 對(duì)象的語(yǔ)句也可以簡(jiǎn)寫為如下形式:
$startInfo = [Diagnostics.ProcessStartInfo] @{
'Filename' = "powershell.exe";
'WorkingDirectory' = $HOMEPATH;
'Verb' = "RunAs"
}
有時(shí)候?yàn)榱撕?jiǎn)寫 .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
循環(huán)與流程控制
比較與邏輯運(yùn)算
PowerShell 支持的比較運(yùn)算符:
-eq, -ne, -gt, -in, -notin, -lt, -le, -like, -notlike, -match, -notmatch, -contains, -notcontains, -is, -isnot
邏輯運(yùn)算符:
-and, -or, -xor, -not
邏輯與比較運(yùn)算符可以用來(lái)在數(shù)據(jù)間進(jìn)行比較,同時(shí)也可以測(cè)試當(dāng)前某些特定的條件是否成立。
如判斷當(dāng)前目錄下的文件個(gè)數(shù)是否大于等于 4:
PS C:\Users\starky> (dir).Count -ge 4
True
某個(gè)字符串是否匹配特定的正則表達(dá)式:
PS C:\Users\starky> "Hello World" -match "H.*World"
True
默認(rèn)情況下,PowerShell 里的比較運(yùn)算是區(qū)分大小寫的,如果想不區(qū)分大小寫,可以使用如下版本的比較運(yùn)算符:
-ceq, -cne, -cge, -cgt, -cin, -clt, -cle, -clike, -cnotlike, -cmatch, -cnotmatch, -ccontains, -cnotcontains
邏輯運(yùn)算符可以組合多個(gè)值為 true 或 false 的語(yǔ)句,并根據(jù)運(yùn)算符號(hào)的不同返回特定的邏輯運(yùn)算結(jié)果。
比如判斷某個(gè)字符串是否匹配特定模式,且字符串長(zhǎng)度大于 10:
PS C:\Users\starky> $data = "Hello World"
PS C:\Users\starky> ($data -like "*llo W*") -and ($data.Length -gt 10)
True
條件語(yǔ)句
PowerShell 中的 if 語(yǔ)句基本用法如下:
$temperature = 35
if($temperature -le 0)
{
"Freezing"
}
elseif($temperature -le 10)
{
"Cold"
}
elseif($temperature -le 20)
{
"Warm"
}
else
{
"Hot"
}
除了流程控制,條件語(yǔ)句也經(jīng)常用來(lái)對(duì)變量進(jìn)行賦值,形式如下:
PS C:\Users\starky> $result = if(Get-Process -n notepad) { "Running" } else { "Not running" }
Get-Process : 找不到名為“notepad”的進(jìn)程。請(qǐng)驗(yàn)證該進(jìn)程名稱,然后再次調(diào)用 cmdlet。
...
PS C:\Users\starky> $result
Not running
通常情況下,使用 switch 語(yǔ)句可以替代包含大量 if ... elseif ... else 的語(yǔ)句。
PowerShell 的 switch 在對(duì)用戶輸入進(jìn)行條件判斷時(shí),支持多種選項(xiàng)的使用,如通配符、正則表達(dá)式甚至簡(jiǎn)短的代碼塊,相比于 C 和 C++ 中的 switch 語(yǔ)句更顯得強(qiáng)大。
$temperature = 35
switch($temperature)
{
{ $_ -lt 0 } { "Below Freezing"; break }
32 { "Exactly Freezing"; break }
{ $_ -le 10 } { "Cold"; break }
{ $_ -le 20 } { "Warm"; break }
default { "Hot" }
}
循環(huán)
for 循環(huán):
for($counter = 1; $counter -le 10; $counter++)
{
"Loop number $counter"
}
foreach 循環(huán):
foreach($file in dir)
{
"File name: " + $file.Name
}
或者:dir | foreach { "File name: " + $_.Name }
while 循環(huán):
$response = ""
while($response -ne "QUIT")
{
$response = Read-Host "Type something"
}
do..while 循環(huán):
$response = ""
do
{
$response = Read-Host "Type something"
} while($response -ne "QUIT")
do..until 循環(huán):
$response = ""
do
{
$response = Read-Host "Type something"
} until($response -eq "QUIT")