前言
傳統上,Windows 的腳本語言分為批次檔 (batch script) 和 Windows Script Host (註) 兩種。前者是命令提示字元 (Command Prompt) 內建的語法,但功能有限。後者則可利用 COM (Component Object Model) 取得較多的功能,但不是終端機環境所用的語法。
(註) Windows Script Host 的內建語言有 VBScript 和 JScript 兩種,可再安裝其他腳本語言。
PowerShell 則結合兩者的特性,既是命令列環境,又是命令列腳本語言。此外,可以用 PowerShell 或 .NET 平台語言來擴充其功能。雖然不一定要直接用 PowerShell 取代命令提示字元,可以把 PowerShell 當成新工具來學。
PowerShell 的版本
PowerShell 在這幾年中隨著 .NET 技術持續演進,出現兩種版本。我們在本節介紹不同的 PowerShell。
基於 .NET Core 的 PowerShell Core
微軟近幾年把 .NET 平台的重心移到 .NET Core 上,也在 .NET Core 上實作新的 PowerShell Core。這個版本的 PowerShell 隨著 .NET Core 跨越多個平台,在 Windows、macOS、GNU/Linux 都可使用。
由於 Unix 原本的 shell 環境和命令列工具已經相當成熟,PowerShell 不太會取代掉這些工具,純 Unix 使用者也不會轉用這個新環境。 PowerShell 是給同時有在用 Windows 和 Unix 的程式設計者一個 (相對) 一致的系統管理工具。
這個版本的 PowerShell 不是 Windows 系統預設軟體,需另行安裝。
基於 .NET Framework 的 PowerShell
原本的 PowerShell 基於 .NET Framework。這個版本的 PowerShell 則是 Windows 限定的工具。為了相容於現有的命令列腳本,Windows 上仍會保留此命令列環境,但不太會新增功能了。除了要相容舊系統外,不用刻意守在這個版本的 PowerShell。
啟動 PowerShell 終端機
按下 Win鍵 + r 啟動「執行」對話框。輸入 powershell
後按 Enter 鍵即可啟動 .NET Framework 版本的 PowerShell。而輸入 pwsh
即可啟動 .NET Core 版本的 PowerShell。
第一次使用 PowerShell
剛進入 PowerShell 的命令列環境,會出現以下的提示 (prompt),等待使用者輸入:
PS C:\Users\user>
命令列環境和 GUI 環境不同,沒有視覺提示,要由使用者自行輸入指令來操作該環境。
每台 Windows 主機的工作目錄是相異的,為了簡化,我們省去工作目錄的部分:
PS >
我們實際輸入 Get-ChildItem
指令來檢視工作目錄下的檔案和子目錄:
PS > Get-ChildItem
輸入的方式是用鍵盤逐一輸入 G
、e
、t
、-
、C
、h
、i
、l
、d
、I
、t
、e
、m
後按下 ENTER 鍵。
其實 PowerShell 的指令是不分大小寫的 (case-insensitive),在這裡刻意區分大小寫僅是易於閱讀,也符合 PowerShell 社群的慣例。讀者習慣 PowerShell 的使用方式後可自行轉為全小寫輸入指令,可以少按幾個鍵。
有用過其他命令列環境的讀者可能會覺得 PowerShell 的指令很怪。因為 PowerShell 的指令是用 Verb-Noun
的概念來組合,而不像傳統的命令列環境,每個命令列工具各自命名。
輸入指令後,系統會顯示出該工作目錄的檔案和子目錄,然後將命令列環境的使用權返還給使用者:
PS > Get-ChildItem
目錄: C:\Users\user
Mode LastWriteTime Length Name
---- ------------- ------ ----
d-r-- 2014/12/24 下午 12:33 Contacts
d-r-- 2020/4/29 上午 11:24 Desktop
d-r-- 2020/4/20 下午 08:46 Documents
d-r-- 2020/5/6 下午 07:19 Downloads
d-r-- 2014/12/24 下午 12:33 Favorites
d---- 2014/12/24 下午 01:00 Intel
d-r-- 2019/11/2 上午 08:48 Links
d-r-- 2014/12/24 下午 12:33 Music
d-r-- 2019/11/2 上午 08:48 OneDrive
d-r-- 2014/12/24 下午 12:33 Pictures
d-r-- 2014/12/24 下午 12:33 Saved Games
d-r-- 2020/4/20 下午 08:47 Searches
d-r-- 2014/12/24 下午 12:33 Videos
PS >
當命令列環境的使用者返還給使用者後,使用者可繼續輸入下一個指令。
互動性使用 (interactive mode) 是命令列環境基本的使用方式。而非互動模式 (non-interactive mode) 或批次模式 (batch mode) 則是較進階的使用方式。在批次模式中,使用者要預先寫好命令列腳本 (command-line script),執行該腳本時逐一執行腳本內預寫好的指令。
原本的 Get-ChildItem
指令較長。PowerShell 允許使用別名 (alias) 來輸入指令:
PS > dir
這時候指令就短多了。但還是要熟記指令的全名,對查閱 API 文件比較方便。
取得 PowerShell 的版本
由於 PowerShell 是持續演進的系統,了解自己目前使用的 PowerShell 版本對撰寫 PowerShell 腳本有所幫助。輸入以下指令來檢視 PowerShell 的版本:
PS > Get-Host | Select-Object Version
Version
-------
2.0
PS >
讀者可能會懷疑這個指令怎麼這麼長?實際上,這是兩個指令 Get-Host
和 Select-Object
,兩者間用 |
(pipe) 串連起來。
PowerShell 的管線 (pipe) 和 Unix 的管線略有不同,前者所傳遞的是 PowerShell 物件 (object) 而非字串 (string)。PowerShell 用物件來傳遞的理由是不需要重新解析字串,當物件傳到下一個指令時可直接使用。
關閉 PowerShell
輸入 exit
指令即可離開 PowerShell 終端機。
PowerShell 指令的組成
命令列環境的指令其實也是電腦程式。這些程式本身沒有 GUI,需搭配命令列環境來使用。PowerShell 的指令的主要來源如下:
- cmdlet
- cmdlet 的別名 (alias)
- 命令提示字元指令
- 批次檔
- 外部程式
前兩種是 PowerShell 內建的功能。PowerShell 內建的指令稱為 cmdlet (command-let)。而別名並不是真正的 cmdlet,只是給 cmdlet 起個短名。
在 PowerShell 環境中使用命令提示字元指令和批次檔僅是為了相容舊程式。如果要把 PowerShell 當成主力環境的話,就不需要再刻意寫批次檔。
外部程式則是第三方命令列工具。因命令列工具已經發展多年,不可能全部用 PowerShell 改寫。做為一種命令列環境,PowerShell 仍需相容於現有的命令列工具。
取得特定指令的來源
使用 Get-Command
指令可顯示指令的來源。例如,用 Get-Command
來檢視 dir
指令的來源:
PS > Get-Command dir
CommandType Name Definition
----------- ---- ----------
Alias dir Get-ChildItem
由此可知,dir
不是 cmdlet,而是 cmdlet 的別名。
除了用來檢視指令的來源外,Get-Command
可以模擬 Unix 的 which(1)
指令。例如,檢查系統上是否能用 GCC:
PS > Get-Command gcc 2>$null
這時候,我們不需要 Get-Command
的錯誤訊息,只要知道該指令是否有成功。所以把標準錯誤重導到 $null
(空物件)。
當輸出為空時,代表該指令不存在。我們可以進一步檢查自動變數 $?
:
PS > $?
False
這時候確認系統上沒有 GCC 可用。
獲得 cmdlet 的說明文件
由於命令列環境沒有視覺提示,得熟悉指令才能順利使用。本節介紹如何使用 PowerShell 終端機內建的工具來學習 PowerShell 指令。
剛安裝好 PowerShell 時,PowerShell 的本地端文件不是很完善。如果想要在本地端觀看 PowerShell 的幫助文件,可以使用 Update-Help
指令:
PS > Update-Help
這個指令可以下載或更新本地端的幫助文件。
取得說明文件的 cmdlet 是 Get-Help
。假定要用 Get-Help
查詢 Get-ChildItem
的用法,輸入以下指令:
PS > Get-Help Get-ChildItem
以下指令和前一個指令等效:
PS > Get-ChildItem -?
-?
是 cmdlet 的共通參數,用來查詢該 cmdlet 的說明文件。
如果想要取得詳細一點的說明,在 Get-Help
指令中加上 -Detailed
參數:
PS > Get-Help Get-ChildItem -Detailed | more
由於說明文字較長,用 |
(pipe) 重導給 more
指令,就可以逐頁捲動。
more
並不是 cmdlet,而是命令提示字元的指令。由此可知,PowerShell 在必要時仍可呼叫命令提示字元的指令。
如果想取得完整的說明,在 Get-Help
指令中加上 -Full
參數:
PS > Get-Help Get-ChildItem -Full | more
也可以使用命令提示字元的 help
指令:
PS > help Get-ChildItem
如果想看線上版說明,可在 Get-Help
指令中加上 -Online
參數:
PS > Get-Help Get-ChildItem -Online
這時候會連到官方的 API 文件,這應該算是最完整且最具權威性的文件了。但要注意說明文件的版本和自己系統的版本是否相符。
取得別名 (Alias) 的原始 cmdlet
雖然用別名打指令很方便,最好還是學一下每個 cmdlet 的實際名際,查相關文件會比較方便。用 Get-Alias
指令可取得特定別名的原 cmdlet。以下指令用來取得 dir
的原 cmdlet:
PS > Get-Alias dir
取得 cmdlet 的屬性
由於 cmdlet 回傳的值是物件,用 Get-Member
指令可以觀看物件的屬性:
PS > Get-Location | Get-Member
TypeName: System.Management.Automation.PathInfo
Name 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;}
在 PowerShell 中撰寫多行程式
以下範例展示如何在 PowerShell 中撰寫多行程式:
PS > if ($true) {
>> Write-Host "Hello World"
>> }
>>
Hello World
PS >
實際輸入的方式是每撰寫一行就按一次 Enter 鍵。PowerShell 環境會自動換行。尾端輸入空行後會結束該程式碼片段並執行。
如果碰到較長或需重覆使用的 PowerShell 程式,還是會寫在命令稿後再執行。
使用 PowerShell 的議題
PowerShell 是持續發展的命令列環境,但系統上的 PowerShell 版本不一定是最新版。使用 PowerShell 時應儘量避免過新或實驗性質的特性,以免寫出不相容的 PowerShell 命令稿。
雖然 PowerShell 在非 Windows 系統也可以使用,但在非 Windows 系統上 PowerShell 不是主流的系統管理工具,大部分的系統不會預裝 PowerShell。如果需要使用 GNU/Linux 或 Unix 主機,最好還是花點時間學習正統的 Unix 命令列環境和命令列工具。