來源:
https://blog.csdn.net/u011054333/article/details/72567590
https://blog.csdn.net/u011054333/article/details/72568190
https://blog.csdn.net/u011054333/article/details/72798046
一說起 Shell 編程,我們大家想到的應(yīng)該都是Linux 下的 Shell 編程。其實(shí) Windows 下也可以使用功能強(qiáng)大的 Shell 來編寫程序,這就是今天我要介紹的 Powershell。從名字就可以看出來,Powershell的功能很強(qiáng)大,所以才敢叫Powershell。
如果需要看官方文檔的話,點(diǎn)擊這里。雖然有一些機(jī)翻的意味,但是完全可以看。
需要說明一點(diǎn),Powershell是構(gòu)建在.NET平臺上的,所有命令傳遞的都是.NET對象。所以為了更好地使用Powershell,最好有一點(diǎn).NET編程基礎(chǔ),這樣學(xué)習(xí)Powershell就會感覺非常輕松和愉快。
這里我介紹的是 Powershell 5.0 ,它在 Windows Server 2016 和Windows 10 操作系統(tǒng)中是默認(rèn)安裝的。如果使用的是比較舊的操作系統(tǒng)例如 Windows 7 或者 Windows 8.1 ,就需要手動安裝 Powershell 5.0 。下載也很簡單,到這里下載 WMF 5.0,它包含了 Powershell 5.0 和一系列工具。
如果要查看當(dāng)前Powershell版本的話,也很簡單。在Powershell窗口中使用下面的命令即可查看相關(guān)信息。
C:\Users\asddf> $PSVersionTableName Value ---- ----- PSVersion 5.1.15063.296 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.15063.296 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
啟動 Powershell 很簡單,從運(yùn)行對話框或者開始菜單中搜索powershell
即可。這樣就可以打開 Powershell 命令行窗口了。默認(rèn)情況下這是一個藍(lán)色的窗口。
在64位操作系統(tǒng)下,有兩個版本的 Powershell 。默認(rèn)情況下,我們使用64位版本就可以了。如果有特殊需求的話,可以選擇啟動帶x86
字樣的32位版本的 Powershell 。
在終端中敲命令是一件很麻煩的事情,有沒有什么集成環(huán)境可以讓我們進(jìn)行交互式學(xué)習(xí)呢?當(dāng)然是有的,Windows 附帶了一個交互式環(huán)境,叫做Powershell ISE,可以幫助我們更方便的學(xué)習(xí)和使用 Powershell。
啟動 Powershell ISE也很簡單,在Windows 10下,直接在開始菜單中輸入 ISE
,就可以打開Powershell ISE了。
首先說明一下,和 Linux Shell 不同,Powershell 的命令基本上都是動詞-名詞
形式的。這樣做的好處是命令作用很容易就可以看出,缺點(diǎn)就是輸入稍微有些麻煩,習(xí)慣了Linux 的簡潔的同學(xué)可能會不太適應(yīng)。
Powershell 和Linux Shell 還有一個不同點(diǎn)在于Powershell 是基于 .NET平臺的,它的命令叫做cmdlet
。cmdlet
功能比普通的Linux 命令更強(qiáng),因為cmdlet
接受的參數(shù)不是字符串,而是 .NET 對象,這使得Powershell 的功能更加強(qiáng)大和靈活。
如果想要獲取當(dāng)前會話中所有可用的內(nèi)置命令,可以使用命令Get-Command
,它的別名是gcm
。
PS C:\Users\asddf> Get-Command CommandType Name Version Source----------- ---- ------- ------Cmdlet Get-Command 3.0.0.0 Microsoft.PowerShell.Core.....
如果希望列出指定名稱的命令,可以使用Name
參數(shù)。
PS C:\Users\asddf> Get-Command -Name Get-CommandCommandType Name Version Source----------- ---- ------- ------Cmdlet Get-Command 3.0.0.0 Microsoft.PowerShell.Core
有些命令比較常用,除了動詞-名詞
版本外,Powershell還提供了和Linux 一樣的別名來簡化輸入。我們可以使用-CommandType Alias
參數(shù)來顯示所有的命令別名。下面列舉了一部分輸出,可以看到,微軟為了照顧Linux用戶,很多命令都縮寫為Linux 命令的形式。
PS C:\Users\asddf> Get-Command -CommandType AliasCommandType Name Version Source----------- ---- ------- ------Alias % -> ForEach-ObjectAlias ? -> Where-ObjectAlias ac -> Add-ContentAlias blsmba -> 2.0.0.0 SmbShareAlias cat -> Get-ContentAlias cd -> Set-LocationAlias chdir -> Set-LocationAlias clc -> Clear-ContentAlias clear -> Clear-HostAlias clhy -> Clear-HistoryAlias cli -> Clear-ItemAlias clp -> Clear-ItemPropertyAlias cls -> Clear-Host
當(dāng)然,如果你觀察仔細(xì)的話,會發(fā)現(xiàn)命令類型這一欄有Alias
、cmdlet
以及function
三種類型。所以我在前面使用了“內(nèi)置命令”這個詞。函數(shù)基本上就是最簡單的命令,例如清屏(Clear-Host
),不能接受參數(shù),功能比較基本。cmdlet
則是功能強(qiáng)大的命令,可以接受各類參數(shù),還能復(fù)合使用。Alias
則是前兩者的別名,作用是簡化輸入。
當(dāng)然,如果想查找特定動詞/名詞的命令也是可以的。比方說,如果我想查找所有以Get
開頭的命令,可以使用下面的命令。
PS C:\Users\asddf> Get-Command -Verb Get
相應(yīng)的,如果我想獲取所有名詞是Help
的命令,可以使用下面的命令。
PS C:\Users\asddf> Get-Command -Noun HelpCommandType Name Version Source----------- ---- ------- ------Cmdlet Get-Help 3.0.0.0 Microsoft.PowerShell.CoreCmdlet Save-Help 3.0.0.0 Microsoft.PowerShell.CoreCmdlet Update-Help 3.0.0.0 Microsoft.PowerShell.Core
上面的命令都只列出了內(nèi)置命令。如果需要包含包括普通程序在內(nèi)的所有命令,可以使用通配符。
PS C:\Users\asddf> Get-Command *
如果要獲取一個命令的幫助,可以使用Get-Help
。如果使用上面介紹的列出別名的命令的話,會發(fā)現(xiàn)這個命令的別名是man
,恰好就是Linux 系統(tǒng)下的獲取幫助的命令。當(dāng)然它們的功能也很相似。
比方說,我們要查看一下清除屏幕這個命令的幫助,就可以簡單的輸入下面的命令。Powershell 會自動將別名解析為實(shí)際命令名稱。所以我們可以看到,cls
實(shí)際上是Clear-Host
命令的別名。
PS C:\Users\asddf> man cls名稱 Clear-Host摘要語法 Clear-Host [<CommonParameters>]說明相關(guān)鏈接 https://go.microsoft.com/fwlink/?LinkID=225747備注 若要查看示例,請鍵入: "get-help Clear-Host -examples". 有關(guān)詳細(xì)信息,請鍵入: "get-help Clear-Host -detailed". 若要獲取技術(shù)信息,請鍵入: "get-help Clear-Host -full". 有關(guān)在線幫助,請鍵入: "get-help Clear-Host -online"
其實(shí)從這個命令的幫助信息來看,我們就可以獲得大部分信息。比方說,如果我們要查看這個命令的在線幫助,就可以如同上面的備注所說,在命令上添加-online
參數(shù),這樣就會打開瀏覽器跳轉(zhuǎn)到這個命令的在線幫助頁上。
值得一提的還有幫助參數(shù)-?
、如果一個命令添加了幫助參數(shù),那么Powershell 不會實(shí)際執(zhí)行這個命令,而是顯示它的幫助信息。
原來,如果我們使用批處理來管理Windows服務(wù)的話,一般情況下用的是sc
這個命令。這個命令的作用有很多,其中一項就是啟動和停止Windows服務(wù)。不過在Powershell下有更好用的服務(wù)管理命令,功能也更加強(qiáng)大。
首先我們先查看一下有什么管理服務(wù)的命令,只需要查詢一下名詞是service
的命令即可??梢钥吹竭@些命令涵蓋了從創(chuàng)建服務(wù)到管理服務(wù)的各個方面,功能很豐富。
PS C:\Users\asddf> Get-Command -Noun serviceCommandType Name Version Source----------- ---- ------- ------Cmdlet Get-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet New-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Restart-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Resume-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Set-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Start-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Stop-Service 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Suspend-Service 3.1.0.0 Microsoft.PowerShell.Management
比方說,我們要查詢一下當(dāng)前計算機(jī)安裝了哪些和MySQL相關(guān)的服務(wù),就可以用下面的命令。
PS C:\Users\asddf> Get-Service mysql*Status Name DisplayName------ ---- -----------Running MySQL57 MySQL57
然后如果需要停止服務(wù)也很簡單,需要注意停止服務(wù)的話需要管理員權(quán)限,因此Powershell需要在管理員模式下運(yùn)行。
PS C:\WINDOWS\system32> Stop-Service MySQL57警告: 正在等待服務(wù)“MySQL57 (MySQL57)”停止...
其他命令就不介紹了,配合幫助命令可以很快學(xué)習(xí)如何使用。
最后直接從網(wǎng)上找了個例子來看看Powershell的實(shí)際作用。我們可以從中了解到Powershell的強(qiáng)大特性,用它幫助我們方便地管理Windows操作系統(tǒng)。
這里貼一個網(wǎng)絡(luò)上的例子,我是從知乎上看到的。運(yùn)行一下會直接打開Excel并填充數(shù)據(jù),然后畫出占用內(nèi)存前十的程序的餅狀圖,一氣呵成。我第一次運(yùn)行的時候簡直驚呆了。
# create new excel instance $objExcel = New-Object -comobject Excel.Application $objExcel.Visible = $True $objWorkbook = $objExcel.Workbooks.Add() $objWorksheet = $objWorkbook.Worksheets.Item(1) # write information to the excel file$i = 0$first10 = (ps | sort ws -Descending | select -first 10)$first10 | foreach -Process {$i++; $objWorksheet.Cells.Item($i,1) = $_.name; $objWorksheet.Cells.Item($i,2) = $_.ws}$otherMem = (ps | measure ws -s).Sum - ($first10 | measure ws -s).Sum$objWorksheet.Cells.Item(11,1) = "Others"; $objWorksheet.Cells.Item(11,2) = $otherMem# draw the pie chart$objCharts = $objWorksheet.ChartObjects()$objChart = $objCharts.Add(0, 0, 500, 300)$objChart.Chart.SetSourceData($objWorksheet.range("A1:B11"), 2)$objChart.Chart.ChartType = 70$objChart.Chart.ApplyDataLabels(5)
當(dāng)然其實(shí)Powershell能做的事情非常多。微軟自從Powershell出現(xiàn)之后就一直推動Windows和Powershell的互操作。到現(xiàn)在為止大概大部分Windows管理和配置功能都可以使用Powershell來進(jìn)行。
一開始我也對Powershell不太了解。不過了解了一點(diǎn)之后,我感覺Powershell的功能確實(shí)對得起它的名字。我已經(jīng)決定學(xué)習(xí)完P(guān)owershell之后,將來在所有可以使用Powershell的地方全部使用它,享受命令行管理系統(tǒng)的快感。
這一部分著重于介紹Powershell的程序知識,讓我們能夠編寫功能強(qiáng)大的Powershell腳本,執(zhí)行比較復(fù)雜的任務(wù)。
變量使用$變量名
創(chuàng)建和引用。舉個例子,Get-Location
命令用于獲取當(dāng)前工作目錄位置,它的別名是pwd
。那么我們可以使用下面的命令來創(chuàng)建一個變量,存儲當(dāng)前目錄位置。
C:\Users\asddf> $current=pwd
然后我們訪問$current
,就可以獲取實(shí)際值了。
C:\Users\asddf> $currentPath ---- C:\Users\asddf
如果知道這個命令返回的實(shí)際是.NET對象的話,我們還可以更進(jìn)一步,比方說直接訪問這個對象的Path
屬性,獲取值。
C:\Users\asddf> $current.PathC:\Users\asddf
還有一個命令Get-Member
,別名是gm
,用于獲取對象的屬性。比方說,我們將Get-Location
命令的結(jié)果通過管道傳遞給Get-Member
命令,就會顯示下面的輸出。如果不了解.NET的話,可能感覺比較陌生。但是如果你懂得.NET和C#的話,就會像我一樣大喊一聲:“臥槽,還能這樣玩?!”
C:\Users\asddf> Get-Location|Get-Member TypeName:System.Management.Automation.PathInfoName MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Drive Property System.Management.Automation.PSDriveInfo Drive {get;} Path Property string Path {get;} Provider Property System.Management.Automation.ProviderInfo Provider {get;}ProviderPath Property string ProviderPath {get;}
如果我們要獲取對象的所有屬性,使用MemberType
參數(shù)。
C:\Users\asddf> pwd|gm -MemberType Property
我們還可以在變量上調(diào)用方法, 比如說將路徑轉(zhuǎn)換為全小寫。
C:\Users\asddf> $current.Path.ToLower()c:\users\asddf
最后,如果不再需要一個變量,可以使用Remove-Variable
刪除變量,它的別名是rv
。
C:\Users\asddf> Remove-Variable current
來看看Powershell中支持的操作符。
首先,基本的數(shù)學(xué)運(yùn)算符都是支持的。
PS D:\Desktop> $i=5PS D:\Desktop> $sum=3+4*($i-3)/2PS D:\Desktop> $sum7
前置后置自增自減運(yùn)算符也是支持的。
PS D:\Desktop> $i=0PS D:\Desktop> $i--PS D:\Desktop> $i++PS D:\Desktop> ++$iPS D:\Desktop> --$i
然后是比較運(yùn)算符,這些和Linux Shell中很相似,有大于(-gt
),大于等于(-ge
),小于(-lt
),小于等于(-le
),等于(-eq
),不等于(-ne
)幾個。
-like
和-notlike
用于?*
這樣的通配符。
PS D:\Desktop> 'hello' -like '?ello'TruePS D:\Desktop> 'hello' -notlike '?ello'FalsePS D:\Desktop> 'hello' -like '*o'True
-match
和-notmatch
用于正則表達(dá)式。
PS D:\Desktop> 'aabcc' -match 'a*b?c+'TruePS D:\Desktop> 'aab' -match 'a*b?c+'False
-contains
查找序列中是否包含某個元素。
PS D:\Desktop> 'hello','zhang3' -contains 'zhang3'True
-replace
用于替換字符串中某個部分,當(dāng)然正則表達(dá)式也是支持的。
PS D:\Desktop> 'hello zhang3' -replace 'zhang3','yitian'hello yitian
-split
和-join
用于將一個字符串分為幾個子部分,或者將幾個子部分組合為一個字符串。
PS D:\Desktop> 'A B C DE' -split ' 'ABCDEPS D:\Desktop> 'A','B','C' -join ','A,B,C
上面這些運(yùn)算符都是大小寫不敏感的,如果需要大小寫敏感的功能,可以在運(yùn)算符前面添加c
前綴。
PS D:\Desktop> 'yitian' -match 'Yitian'TruePS D:\Desktop> 'yitian' -cmatch 'Yitian'False
邏輯運(yùn)算符有與(-and
)、或(-or
)、非(-not
或!
)以及異或(xor
)幾個,并且支持短路計算。
如果需要使用真值和假值字面量,可以使用$true
和$false
。
Powershell 和.NET平臺綁定,所以它是一門強(qiáng)類型的腳本。因此我們可以在腳本中判斷數(shù)據(jù)的類型,只要使用-is
或-isnot
運(yùn)算符即可,類型需要寫到方括號中。這里的類型可以是所有合適的.NET類型。
PS D:\Desktop> 3.14 -is [Double]TruePS D:\Desktop> 3.14 -isnot [Float]True
這個稍微比較麻煩一點(diǎn)。
首先是>
和>>
運(yùn)算符,用于將標(biāo)準(zhǔn)輸出流重定向到文件,前者會覆蓋已有文件,后者則是追加到已有文件末尾。
然后我們來說說日志級別,如果有使用過某些語言的日志框架的話,就很好理解了。在這里,2代表錯誤、3代表警告、4代表信息、5代表調(diào)試信息。n>
和n>>
運(yùn)算符就是用于將對應(yīng)級別的輸出重定向到文件的,這兩者的區(qū)別和前面相同。n>&1
將對應(yīng)級別的輸出和標(biāo)準(zhǔn)輸出一起重定向到文件。
最后就是*>
和*>>
了,這兩者將所有輸出信息重定向到文件。
需要注意,Powershell使用Unicode編碼來輸出信息。如果你需要使用其他類型的編碼,就不能使用重定向運(yùn)算符了,而應(yīng)該使用Out-File
命令。
&
運(yùn)算符將它后面的命令設(shè)置為后臺運(yùn)行,當(dāng)運(yùn)行的命令需要阻塞當(dāng)前終端的時候很有用。
.\\
運(yùn)算符用于執(zhí)行一個腳本或命令。如果執(zhí)行的是Powershell腳本,那么腳本會在自己的作用域中執(zhí)行,也就是說在當(dāng)前環(huán)境下無法訪問被執(zhí)行的腳本中的變量。
[]
運(yùn)算符用于轉(zhuǎn)換變量的類型,比如說下面的代碼,就將pi
變量轉(zhuǎn)換為了Float
類型。
[Float]$pi = 3.14$pi -is [Float]
.
運(yùn)算符用于調(diào)用.NET對象的成員,它也可以用于執(zhí)行腳本。當(dāng)它用于執(zhí)行腳本的時候,腳本會在當(dāng)前作用域中執(zhí)行。所以腳本結(jié)束之后,我們可以訪問腳本中的元素。
::
運(yùn)算符用于調(diào)用類中的靜態(tài)成員,例如下面就會調(diào)用.NET平臺中DateTime
類的Now
屬性。
PS D:\Desktop> [DateTime]::Now2017年5月18日 22:45:42
..
運(yùn)算符用于創(chuàng)建一個范圍閉區(qū)間,例如下面這樣。
PS D:\Desktop> 1..3123PS D:\Desktop> 3..1321
-f
運(yùn)算符用于格式化數(shù)據(jù),例如下面這樣。格式化方法和C#中的完全相同,所以如果不熟悉的話直接看在C#中如何格式化數(shù)據(jù)就行了。
PS D:\Desktop> 'My name is {0}, I am {1} years old' -f 'yitian',24My name is yitian, I am 24 years old
$
運(yùn)算符可以將字符串內(nèi)部的變量轉(zhuǎn)換為實(shí)際的值,例如下面這樣。需要注意使用內(nèi)插操作符的時候,外部字符串需要使用雙引號,否則Powershell會直接輸出字符串內(nèi)容。
PS D:\Desktop> $name='yitian'PS D:\Desktop> $age=24PS D:\Desktop> "My name is $name, I am $age years old."My name is yitian, I am 24 years old.
@()
運(yùn)算符用于將一系列值轉(zhuǎn)換為一個數(shù)組。假如在腳本中有一個函數(shù)可能返回0、1或多個值,就可以使用這個操作符,將一系列值合并為一個數(shù)組,方便后續(xù)處理。
,
逗號運(yùn)算符如果放置在單個值前面,就會創(chuàng)建一個包含這個值的單元素數(shù)組。
Powershell中的條件判斷和一般的編程語言以及Shell編程都很類似,直接看代碼就能理解。
$condition = $trueif ($condition -eq $true) { Write-Output "condition is $true"}elseif ($condition -ne $true ) { Write-Output "condition is $false"}else { Write-Output "other ocndition"}
如果需要多重判斷,可以考慮使用switch語句。一個典型的switch如下所示。
$n = 4switch ($n) { 1 {"n is 1"} 2 {"n is 2"} 3 {"n is 3"} default {"n is others"}}
其實(shí)細(xì)說起來,這個switch的坑還是不少的。例如,switch語句可以接受多個值來測試,在switch語句中還可以編寫多個case相同的語句。這里我就不細(xì)說了,想具體了解的話直接看官方文檔 about_Switch吧。
提醒一下,不管是哪種循環(huán)語句,在循環(huán)體內(nèi)都可以使用break
或continue
中斷/繼續(xù)循環(huán)。
首先來看看do-while循環(huán),先執(zhí)行循環(huán)體,然后判斷是否滿足條件,如果滿足條件則繼續(xù)執(zhí)行。
$i = 0do { $i++ Write-Output $i}while ($i -ne 3)
然后是do-until循環(huán),和do-while類似,不過當(dāng)條件不滿足的時候才會繼續(xù)循環(huán),如果滿足條件則退出循環(huán)。
$i = 0do { $i++ Write-Output $i}until ($i -eq 3)
while循環(huán)是先判斷循環(huán)條件,滿足條件時執(zhí)行循環(huán)。
$i = 0while ($i -lt 3) { Write-Output $i $i++}
for循環(huán)可以看做是while循環(huán)的另一種形式,常用于固定次數(shù)的循環(huán)。
for ($i = 0; $i -ne 3; $i++) { Write-Output $i}
for-each循環(huán)用于遍歷一個集合中的所有元素。
$array = @(1, 2, 3, 4)foreach ($i in $array) { Write-Output $i}
值得一提的是,for-each語句用在管道上時,還有以下一種用法。
<command> | foreach {<beginning command_block>}{<middle command_block>}{<ending command_block>}
使用這種方法時,for-each后面可以跟三個語句塊,第一個語句塊是開始語句塊,在循環(huán)前執(zhí)行一次,常用來初始化一些數(shù)據(jù);第三個是結(jié)束語句塊,在循環(huán)結(jié)束之后執(zhí)行一次,常用于統(tǒng)計一些循環(huán)數(shù)據(jù);第二個就是正常的循環(huán)語句塊,會循環(huán)多次。
定義函數(shù)使用function
關(guān)鍵字。
function hello { Write-Output 'Hello Powershell'}
定義好函數(shù)之后,就可以使用函數(shù)名來調(diào)用函數(shù)了。
hello
函數(shù)當(dāng)然也可以帶參數(shù)了,參數(shù)列表有兩種寫法:第一種是C風(fēng)格的,參數(shù)列表寫在函數(shù)名后面,使用小括號分隔開;第二種方式是在方法體中,使用param
關(guān)鍵字聲明參數(shù)。這兩種方法是完全等價的,當(dāng)然我習(xí)慣上還是喜歡使用第一種方式。
Powershell是一種強(qiáng)類型的腳本語言,所以可以在參數(shù)列表上添加參數(shù)類型,參數(shù)類型是可選的,不過我還是推薦寫的時候帶上類型,方便閱讀和類型檢查。
function Say-Hello ([string] $name) { Write-Output "Hello, $name"}function Say-Hello2 { param([string] $name) Write-Output "Hello, $name"}
調(diào)用帶參數(shù)的函數(shù)時,需要向調(diào)用命令那樣,使用-參數(shù)名
來傳遞參數(shù),例如下面這樣。
Say-Hello -name 'yitian'
Powershell支持默認(rèn)參數(shù),直接用賦值號=
在參數(shù)列表上指定參數(shù)默認(rèn)值即可。
function Say-Hello3 { param([string] $name = 'zhang3') Write-Output "Hello, $name"}
Powershell也支持位置參數(shù),它會把所有參數(shù)包裝到$args
數(shù)組中,所以我們可以通過這個變量訪問所有位置的參數(shù)。例如下面,將所有參數(shù)合并一個字符串,然后打印出來。
function Say-Hellos { $names = $args -join ',' Write-Output "Hello, $names"}
這個函數(shù)調(diào)用時候需要指定多個參數(shù),注意不要在多個參數(shù)之間添加括號,否則會變成一個數(shù)組參數(shù),而不是多個參數(shù)。
Say-Hellos 'yitian' 'zhang3' 'li4'
開關(guān)參數(shù)沒有類型,作用僅僅是標(biāo)志是或者否。如果在使用函數(shù)的時候帶上開關(guān)參數(shù),那么它就是開的狀態(tài),否則就是關(guān)的狀態(tài)。開關(guān)參數(shù)需要指定參數(shù)類型為switch
。
function Answer-Hello ([switch] $yes) { if ($yes) { Write-Output "Hi" }}
然后在調(diào)用時就可以看出區(qū)別了。
Answer-Hello -yesAnswer-Hello
最后來說說函數(shù)返回值。這個其實(shí)也很簡單,只要使用return
語句就可以了。
function Add ([double]$a, [double]$b) { $c = $a + $b return $c}
然后我們調(diào)用函數(shù),就可以看到結(jié)果了。
Add -a 3 -b 5
關(guān)于Powershell編程的知識就介紹到這里,其實(shí)如果看看官方文檔的話,就知道這里介紹的也僅僅是一部分而已。不過這一部分對于我們?nèi)粘J褂煤蛯W(xué)習(xí)基本上也夠用了。
如果要查看詳細(xì)幫助的話,可以運(yùn)行一下下面的命令,這樣會顯示所有和Powershell相關(guān)的幫助文檔。
Get-Help about*
然后,就可以閱讀自己感興趣的部分了。比方說,如果我們想了解用Powershell編寫類,就可以使用下面的命令。如果想在瀏覽器中瀏覽器在線版本,加上-online
參數(shù)即可。
Get-Help about_Classes
http://windowsitpro.com/powershell/windows-powershell-operators
好像關(guān)于Powershell說的已經(jīng)差不多了,所以最后一篇文章就來使用Powershell寫一些腳本,幫助我們完成一些日常工作。
先來看看常用的文件管理命令。
Set-Location
命令用于切換工作目錄,它的別名是cd
。
Get-Location
命令用于獲取當(dāng)前工作目錄,它的別名是pwd
。
Get-ChildItem
命令用于獲取當(dāng)前目錄下的所有文件。
Get-Item
命令用于獲取給定文件的信息。
還有文件移動、刪除、復(fù)制、粘貼、重命名等命令,輸入Get-Command -Noun item
就可以看到這些命令,這里就不做介紹了。
獲取文件信息可以利用命令Get-Item
。下面獲取了我電腦上的cmder.exe
可執(zhí)行文件的信息。
λ Get-Item .\Cmder.exe 目錄: D:\devtools\cmder_miniMode LastWriteTime Length Name---- ------------- ------ -----a---- 2016/12/2 7:15 130560 Cmder.exe
默認(rèn)只列出這么三個屬性,當(dāng)然其實(shí)文件屬性遠(yuǎn)不止這些。我們可以通過管道,將文件信息對象傳遞給命令Select-Object
,讓它幫我們顯示所有屬性。這里只粘貼了一點(diǎn)點(diǎn)內(nèi)容,其實(shí)文件信息很長,大家可以自行嘗試。
λ Get-Item .\Cmder.exe|Select-Object *PSPath : Microsoft.PowerShell.Core\FileSystem::D:\devtools\cmder_mini\Cmder.exePSParentPath : Microsoft.PowerShell.Core\FileSystem::D:\devtools\cmder_mini
用Get-ChildItem
顯示當(dāng)前當(dāng)前文件的時候,會顯示所有文件。有時候我們可能僅僅需要搜索或者過濾部分文件。
首先,如果是比較簡單的需求,可以使用?*
通配符來搞定,問號用于匹配任意單個字符,星號用于匹配任意多個字符。比方說,我想要列出所有.md
格式的文件,就可以使用下面的命令。
PS D:\devtools\cmder_mini> Get-ChildItem *.md 目錄: D:\devtools\cmder_miniMode LastWriteTime Length Name---- ------------- ------ -----a---- 2016/12/2 7:14 73491 CHANGELOG.md-a---- 2016/12/2 7:14 1784 CONTRIBUTING.md-a---- 2016/12/2 7:14 10039 README.md
有時候可能需要使用正則表達(dá)式來查找文件,不過好像Get-ChildItem
沒有正則表達(dá)式查詢的命令行,不過我們可以使用Where-Object
命令來自定義查詢。如果了解C#語言的LINQ的話,應(yīng)該可以猜到,這個命令對應(yīng)于LINQ的where
語句。
下面同樣是查找所有.md
格式的文件,不過這次使用了Where-Object
和正則表達(dá)式,其中Where-Object
里面的$_
是形式變量,代表每次迭代的文件。如果了解過C#的LINQ,或者Java 8的流類庫,應(yīng)該對這種形式會比較熟悉。
Get-ChildItem|Where-Object {$_ -match '\w*.md$'}
如果僅僅為了搜索文件名的話,這種方式好像一點(diǎn)優(yōu)勢都沒有。實(shí)際上Where-Object
的功能非常強(qiáng)大。比方說,我現(xiàn)在想查找大于5kb
的所有.md
格式文件,那么就可以這么寫。這里又用到了Powershell的一個方便的特性,文件大小單位,KB GB MB TB
等單位都支持。當(dāng)然其實(shí)并不僅僅可以查詢文件大小屬性,基本上所有文件信息都可以用來查詢。
Get-ChildItem|Where-Object {$_ -match '\w*.md$' -and $_.Length/1kb -gt 5}
最后,Get-ChildItem
不僅可以列出當(dāng)前文件夾下的所有內(nèi)容,還可以遞歸查詢所有子文件夾。比方說,我要查找一下迅雷文件夾下所有可執(zhí)行文件,就可以使用下面的命令。如果添加-Depth
參數(shù)的話,還可以指定遞歸深度。
Get-ChildItem -Recurse *.exe
訪問谷歌的一種方式就是更改hosts文件。這里就用Powershell做一個修改hosts的功能。
首先先來介紹一個命令Invoke-WebRequest
,利用它我們可以獲取網(wǎng)頁內(nèi)容、下載文件甚至是填寫表單。這個命令的別名是iwr
、curl
和wget
。我們就使用它來下載網(wǎng)上的hosts文件。
剩余就沒有什么難度了,無非就是讀寫文件、追加文件、復(fù)制和粘貼這種基本操作。最后寫完這個功能發(fā)現(xiàn)有一百多行,就不往這里復(fù)制粘貼了。如果有興趣的話,可以直接看我的Github上面的腳本。
首先我們看看有多少和進(jìn)程相關(guān)的命令,這個很簡單,只要查看一下名詞是Process
的命令即可。
PS C:\WINDOWS\system32> Get-Command -Noun processCommandType Name Version Source----------- ---- ------- ------Cmdlet Debug-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Get-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Start-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Stop-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Wait-Process 3.1.0.0 Microsoft.PowerShell.Management
使用這些命令,我們就可以非常方便的管理進(jìn)程了。比方說,我想查詢現(xiàn)在運(yùn)行的所有進(jìn)程,就可以使用下面的命令,這樣就會列出所有運(yùn)行的進(jìn)程,就像任務(wù)管理器里顯示的那樣。
PS C:\WINDOWS\system32> Get-ProcessGet-Process
上面這個命令會顯示所有進(jìn)程。如果需要,我們可以按照某個屬性對進(jìn)程進(jìn)行排序顯示,這需要使用另外一個命令Sort-Object
。另外,如果只需要顯示前幾個進(jìn)程,可以使用命令Select-Object
來選擇顯示多少數(shù)據(jù)。比方說,如果我們要查看當(dāng)前占用CPU前5的chrome進(jìn)程,就可以使用下面的命令。
Get-Process chrome|Sort-Object cpu -Descending|Select-Object -First 5
利用這幾個命令,我們可以按照任何想要的方式來查詢進(jìn)程。
先來看看MSDN上的一個官方例子。首先先打開三個記事本進(jìn)程,然后使用名稱獲取這些進(jìn)程,然后調(diào)用進(jìn)程的Kill()
函數(shù)即可把這些進(jìn)程全殺掉。中間調(diào)用了Count
屬性測試了一下總共獲取到了幾個進(jìn)程。
PS C:\WINDOWS\system32> notepad;notepad;notepad;PS C:\WINDOWS\system32> $notepads=Get-Process -Name notepadPS C:\WINDOWS\system32> $notepads.Count3PS C:\WINDOWS\system32> $notepads.Kill()
再學(xué)習(xí)Powershell編程的時候,我們常常會同時開幾個Powershell窗口。不再使用的時候一個一個關(guān)閉它們也是一件麻煩事情,所以官方文檔還為我們介紹了如何關(guān)閉除當(dāng)前窗口外的所有Powershell進(jìn)程。
每個Powershell進(jìn)程都有一個變量$PID
,用于標(biāo)志當(dāng)前進(jìn)程的進(jìn)程號,利用這一點(diǎn)我們就可以實(shí)現(xiàn)這個功能。這里的-WhatIf
參數(shù)表示不真正關(guān)閉進(jìn)程,僅列出將要關(guān)閉的進(jìn)程。
PS C:\WINDOWS\system32> Get-Process powershell |Where-Object {$_.Id -ne $PID}|Stop-Process -WhatIfWhatIf: 正在目標(biāo)“powershell (2676)”上執(zhí)行操作“Stop-Process”。
如果既想要關(guān)閉進(jìn)程,還想知道關(guān)閉了哪些進(jìn)程,可以使用-PassThru
參數(shù)。
PS C:\WINDOWS\system32> Get-Process powershell |Where-Object {$_.Id -ne $PID}|Stop-Process -PassThruHandles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName------- ------ ----- ----- ------ -- -- ----------- 573 30 56884 68992 0.92 2676 1 powershell
如果在死循環(huán)中不斷查找任務(wù)管理器進(jìn)程,發(fā)現(xiàn)它在運(yùn)行就把它關(guān)閉,就可以做一個小小的“病毒”。代碼很簡單,基本上一下子就能看懂。一開始我沒有加Sleep,然后CPU使用率飚的非常高,加了之后基本上對電腦性能沒有影響了。
$process_name = "taskmgr"while ($true) { $processes = Get-Process if ($processes.Name -contains $process_name) { Get-Process $process_name|Stop-Process } else { Start-Sleep -Milliseconds 500 }}
如果把上面代碼中的taskmgr
換成英雄聯(lián)盟的進(jìn)程名字,我們就可以做一個簡單的“熊孩子防火墻”,防止熊孩子用電腦來玩游戲了。
首先來介紹一下注冊表根的簡寫,例如HKEY_CURRENT_USER
的簡寫就是HKCU
,HKEY_LOCAL_MACHINE
的簡寫就是HKLM
。知道了簡寫,我們就可以將Powershell的工作目錄切換到注冊表內(nèi)。例如,如果我們想查看HKEY_CURRENT_USER\Control Panel\Desktop\MuiCached
下的值,就可以先把工作目錄切換到這個位置內(nèi)部。這里需要將對應(yīng)的注冊表根修改為對應(yīng)的簡寫加冒號的形式。
PS C:\WINDOWS\system32> Set-Location 'HKCU:\Control Panel\Desktop\MuiCached'PS HKCU:\Control Panel\Desktop\MuiCached>
切換到了注冊表內(nèi)部,我們就可以利用Get-Item
命令獲取注冊表的值了。比如說,要獲取這個注冊表鍵的值,就可以直接輸入Get-Item .
了。注意這個點(diǎn)不能省去,它代表當(dāng)前工作目錄。
PS HKCU:\Control Panel\Desktop\MuiCached> Get-Item . Hive: HKEY_CURRENT_USER\Control Panel\DesktopName Property---- --------MuiCached MachinePreferredUILanguages : {zh-CN}
如果要獲取當(dāng)前注冊表項的屬性值,可以利用Get-ItemProperty
命令。
PS HKCU:\Control Panel\Desktop\MuiCached> Get-ItemProperty . MachinePreferredUILanguagesMachinePreferredUILanguages : {zh-CN}PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Control Panel\Desktop\MuiCachedPSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Control Panel\DesktopPSChildName : MuiCachedPSDrive : HKCUPSProvider : Microsoft.PowerShell.Core\Registry
當(dāng)然,切換工作目錄這件事情也可以不做。直接利用Get-ItemProperty
命令通過路徑參數(shù)來獲取屬性。
Get-ItemProperty -Path 'HKCU:\Control Panel\Desktop\MuiCached' -Name MachinePreferredUILanguages
下面這個路徑是一個安全的注冊表路徑,在這里修改注冊表不會造成嚴(yán)重的系統(tǒng)問題。所以我們把它保存為一個變量。
$path = "HKCU:\Control Panel\Desktop"
如果要新建注冊表項,可以使用New-Item
命令。我們可以使用注冊表編輯器regedit
來驗證項是否創(chuàng)建成功。
New-Item –Path $path –Name HelloKey
如果要修改項的屬性,使用Set-ItemProperty
命令。
Set-ItemProperty -path $path\hellokey -name Fake -Value fuck
最后,如果要刪除項的屬性,使用Remove-ItemProperty
命令。
Remove-ItemProperty -path $path\hellokey -name Fake
如果要刪除整個注冊表項,使用Remove-Item
命令。
Remove-Item -path $path\hellokey -Recurse
下面的參考資料中列出了一個MSDN上的文檔,告訴我們?nèi)绾巫x取注冊表的值來判斷當(dāng)前安裝了.NET Framework的版本,并給出了相應(yīng)的C#代碼。下面的代碼做的就是將C#代碼改寫成Powershell腳本。
# 判斷系統(tǒng)當(dāng)前安裝.NET框架版本的腳本$path = 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full'$not_found_msg = ".net framework 4.5 or later not installed on your system"function CheckFor45PlusVersion([int] $releaseKey) { if ($releaseKey -ge 460798) { return "4.7 or later"; } if ($releaseKey -ge 394802) { return "4.6.2"; } if ($releaseKey -ge 394254) { return "4.6.1"; } if ($releaseKey -ge 393295) { return "4.6"; } if (($releaseKey -ge 379893)) { return "4.5.2"; } if (($releaseKey -ge 378675)) { return "4.5.1"; } if (($releaseKey -ge 378389)) { return "4.5"; } return $not_found_msg;}try { $key = get-item $path $releaseKey = Get-ItemPropertyValue $path 'release' if ($releaseKey -is [int]) { $releaseKey = [int]$releaseKey $version = CheckFor45PlusVersion($releaseKey) Write-Host ".NET framework ${version}" } else { Write-Host $not_found_msg }}catch { Write-Host $not_found_msg}
雖然Powershell可以通過COM接口和Office程序交互,不過最常用的還是操作Excel,所以我這里只介紹如何控制Excel表。下面最后一個參考資料就是我參考的操作Excel的文章,可能需要梯子才能訪問。需要注意一點(diǎn),既然是操作Excel,當(dāng)然首先電腦上需要先安裝Excel才能正常使用。
首先,我們來創(chuàng)建一個Excel對象,這樣實(shí)際上會創(chuàng)建一個Excel應(yīng)用程序。
$excel = New-Object -ComObject Excel.Application
執(zhí)行了上面的命令,什么事情都沒有發(fā)生。這是因為默認(rèn)啟動的實(shí)例是隱藏的,要顯示Excel的窗口的話,將它設(shè)置為可見即可。
$excel.Visible=$true
如果要打開一個現(xiàn)成的工作簿,使用Open
函數(shù)。
$workbook = $excel.Workbooks.Open("XXX.xlsx")
如果要創(chuàng)建一個新的工作簿,使用Add
函數(shù)。
$workbook = $excel.Workbooks.Add()
一個工作簿可以有多個工作表,要選擇某一個工作表,使用Worksheets.Item
屬性,需要注意這里的下標(biāo)從一開始。
$worksheet = $workbook.Worksheets.Item(1)
對數(shù)據(jù)完成操作之后,需要保存的話,使用SaveAs
函數(shù)。
$workbook.SaveAs("D:\Desktop\hello.xlsx")
前面只說了打開和關(guān)閉操作,下面來看看如何具體讀取和寫入數(shù)據(jù)。首先回到上面那步工作表,因為如果要操作數(shù)據(jù),需要在工作表對象上進(jìn)行操作。
$worksheet = $workbook.Worksheets.Item(1)
要操作數(shù)據(jù),調(diào)用工作表對象的Cells
屬性即可。比方說我要打印九九乘法表,那么就可以用類似下面的代碼來迭代寫入數(shù)據(jù)。
for ($i = 1; $i -le 9; ++$i) { # 第一行 $worksheet.Cells(1, $i + 1) = $i # 第一列 $worksheet.Cells($i + 1, 1) = $i # 它們的乘積 for ($j = 1; $j -le 9; ++$j) { $worksheet.Cells($i + 1, $j + 1) = $i * $j }}
操作之后,Excel表中應(yīng)該存在如圖所示的數(shù)據(jù)。
類似的,讀取數(shù)據(jù)也很簡單,只要讀取Cells
屬性即可。
for ($i = 1; $i -le 10; ++$i) { for ($j = 1; $j -le 10; ++$j) { Write-Host -NoNewline $worksheet.Cells($i, $j).Text "`t" } Write-Host}
上面的代碼獲取了我們剛才寫入Excel的數(shù)據(jù),然后將其轉(zhuǎn)換為文本并輸出,每個數(shù)據(jù)之間使用制表符\t
分隔,注意Powershell中的轉(zhuǎn)義字符使用的這個特殊字符。結(jié)果應(yīng)該類似如圖所示。
Excel很常用的一種操作就是繪制圖表,這里也簡單說說。不過由于這種資料在網(wǎng)上面實(shí)在太少,我就算用谷歌搜索英文網(wǎng)頁也搜不出來多少資料,大部分都屬于一點(diǎn)小腳本。所以這里只能隨便說說了。
首先準(zhǔn)備一下數(shù)據(jù),我準(zhǔn)備了如圖所示的數(shù)據(jù)。
然后來創(chuàng)建一個圖表對象。如果使用交互式環(huán)境Powershell ISE的話,智能提示會顯示這里有AddChart
和AddChart2
兩個方法,不過我看了下文檔,前面那個過時了,所以這里使用帶2的那個版本。
$chart=$worksheet.Shapes.AddChart2().Chart
創(chuàng)建了圖表對象之后,我們?yōu)樗付〝?shù)據(jù)源。
$chart.SetSourceData($worksheet.Range('a1', 'd5'))
這時候如果觀察Excel的話,會發(fā)現(xiàn)已經(jīng)出現(xiàn)了一個初步的圖形。如果希望改變圖形樣式的話,設(shè)置圖標(biāo)的類型即可。這里將圖表類型保存為一個變量,之后就可以省略長長的類名了。這里推薦使用Powershell ISE,因為自動補(bǔ)全可以顯示所有類型的圖標(biāo),只需要修改一下圖表類型并觀察Excel中圖標(biāo)類型的變化就可以明白類型和圖標(biāo)的對應(yīng)關(guān)系了。
$chartTypes = [Microsoft.Office.Interop.Excel.XLChartType]$chart.ChartType = $chartTypes::xlColumnClustered
最后效果如圖所示,我看到人家可以使用方法顯示圖例。但是我使用這個方法卻不知道為什么顯示不了。所以這里只能將就一下了。
最后再來畫個餅狀圖,數(shù)據(jù)還是上面的數(shù)據(jù),不過這次只使用語文那一列的數(shù)據(jù)?;旧虾蜕厦娴囊粯?,只有類型那里改成xlPie
。
$chartTypes = [Microsoft.Office.Interop.Excel.XLChartType]$chart = $worksheet.Shapes.AddChart2().Chart$chart.SetSourceData($worksheet.Range('a1', 'b5'))$chart.ChartType = $chartTypes::xlPie$chart.ApplyDataLabels(5)
最終效果圖如下。
上面的方法好像只能在安裝Excel的環(huán)境下運(yùn)行,如果沒有安裝Office,但是也想使用編程功能,可以使用第三方的模塊。這就是這里要介紹的ImportExcel。使用它,我們可以在沒有安裝Excel的情況下編輯Excel文件。
首先需要安裝它,可以利用Powershell的包管理器方便的安裝。
Install-Module ImportExcel -scope CurrentUser
如果想讓所有用戶都可以使用這個模塊,需要安裝到全局位置,不過這需要管理員權(quán)限,所以需要在管理員模式的Powershell窗口中運(yùn)行。
Install-Module ImportExcel
這個模塊如何使用我就不作介紹了,這個項目的README文件上基本列出了所有功能和對應(yīng)的GIF圖,需要什么功能只要看一看應(yīng)該就可以使用了。
https://4sysops.com/archives/interacting-with-the-registry-in-powershell/
https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.aspx
http://www.lazywinadmin.com/2014/03/powershell-read-excel-file-using-com.html