編碼 · 程式語言
PowerShell 入門教學
簡答
PowerShell 是 Microsoft 推出的跨平台 Shell 與自動化腳本語言。它的指令稱為 Cmdlet,會在管線中傳遞 .NET 物件而非純文字,因此不需要解析文字就能篩選、排序與匯出資料。本頁涵蓋安裝 PowerShell 7、執行腳本、Cmdlet、變數、運算子、流程控制、函式、集合與錯誤處理。
開啟正規測試PowerShell 是什麼、可以拿來做什麼
PowerShell 是 Microsoft 以 .NET 為基礎打造的跨平台 Shell 與腳本語言。傳統 Shell 在指令之間傳遞純文字,而 PowerShell 傳遞帶有屬性與方法的 .NET 物件,所以不需要解析文字就能篩選與排序資料。
系統管理員與 DevOps 工程師使用 PowerShell 來自動化 Windows、管理 Active Directory、Microsoft 365 與 Azure,以及撰寫建置與部署腳本。它有兩個版本:內建於 Windows 的 Windows PowerShell 5.1,以及開源、可在 Windows、Linux 與 macOS 上執行的 PowerShell 7 以上版本(指令名稱為 pwsh)。本教學以 PowerShell 7 為準。
安裝 PowerShell 並執行 Hello, world
在 Windows 上,可用 winget install --id Microsoft.PowerShell --source winget 安裝 PowerShell 7;在 macOS 與 Linux 上,請使用 Homebrew 或 Microsoft 安裝指南中說明的套件管理員。腳本是副檔名為 .ps1 的文字檔。
# hello.ps1
Write-Output "Hello, world!"pwsh ./hello.ps1
# Hello, world!在 Windows 上,執行原則可能會阻擋腳本。Set-ExecutionPolicy -Scope CurrentUser RemoteSigned 允許執行你自己的本機腳本,同時仍要求下載的腳本必須經過簽章。建議的編輯器是安裝了 PowerShell 擴充功能的 Visual Studio Code。
Cmdlet 與管線
指令稱為 Cmdlet,命名模式為 Verb-Noun,例如 Get-Process、Set-Location 或 New-Item。有三個 Cmdlet 能幫你探索其他所有指令:Get-Command、Get-Help 與 Get-Member。
Get-Command -Noun Process # list commands that work with processes
Get-Help Get-ChildItem -Examples # show usage examples
# five processes using the most memory
Get-Process |
Sort-Object -Property WorkingSet64 -Descending |
Select-Object -First 5 -Property Name, Id, WorkingSet64
# files larger than 1 MB in the current folder
Get-ChildItem -File | Where-Object { $_.Length -gt 1MB } |
ForEach-Object { "{0} {1:N0} KB" -f $_.Name, ($_.Length / 1KB) }
Get-Date | Get-Member -MemberType Property # inspect an object在指令碼區塊中,$_(或 $PSItem)是管線中的目前物件。由於物件保有其型別,Sort-Object 會自動依數值排序數字、依時間順序排序日期,不需要額外處理。
變數與型別
變數以 $ 開頭。它們可以存放任何 .NET 物件,也可以用方括號加上型別限制。雙引號字串會展開變數與 $( ) 運算式;單引號字串則是字面值。
$name = "Ada"
[int]$count = 3
$price = 19.99 # System.Double
$isAdmin = $false
$today = Get-Date
"Hello, $name" # Hello, Ada
"Next: $($count + 1)" # Next: 4
'No $expansion here' # No $expansion here
$price.GetType().Name # Double
$today.ToString("yyyy-MM-dd") # for example 2026-10-31
[int]"42" + 1 # 43 (explicit conversion)| 型別 | 範例 | 說明 |
|---|---|---|
[int] | 42 | 32 位元整數 |
[double] | 3.14 | 浮點數;金額請用 [decimal] |
[string] | "text" | 預設不區分大小寫的比較 |
[bool] | $true、$false | 自動變數,不是關鍵字 |
[datetime] | Get-Date | 完整的 .NET DateTime 物件 |
[array]、[hashtable] | @(1, 2), @{ a = 1 } | 集合,下方會說明 |
運算子與流程控制
比較運算子是單字而不是符號:-eq、-ne、-gt、-lt、-ge、-le、-like(萬用字元)、-match(規則運算式)與 -contains。字串比較預設不區分大小寫,除非使用 -ceq 這類 c 開頭的版本。
$temp = 22
if ($temp -gt 30) {
"hot"
} elseif ($temp -ge 15) {
"mild" # mild
} else {
"cold"
}
switch ("report.csv") {
{ $_ -like "*.csv" } { "CSV file" } # CSV file
{ $_ -like "*.txt" } { "text file" }
default { "other" }
}
foreach ($n in 1..3) { "n = $n" } # n = 1, n = 2, n = 3
for ($i = 0; $i -lt 2; $i++) { "i = $i" } # i = 0, i = 1
$k = 3
while ($k -gt 0) { $k-- }
"Hello" -eq "hello" # True函式與參數
函式使用 param() 區塊宣告有型別、具名稱的參數。加上 [CmdletBinding()] 後,函式便具有與內建 Cmdlet 相同的通用參數,例如 -Verbose。任何沒有被擷取的輸出都會成為函式的回傳值。
function Get-Greeting {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$Name,
[string]$Greeting = "Hello"
)
Write-Verbose "Building greeting for $Name"
"$Greeting, $Name!"
}
Get-Greeting -Name "Ann" # Hello, Ann!
Get-Greeting -Name "Bo" -Greeting "Hi" # Hi, Bo!
Get-Greeting "Cy" -Verbose # also prints the verbose message呼叫函式的方式與 Cmdlet 相同,引數之間用空格分隔:Get-Greeting -Name Ann。寫成 Get-Greeting("Ann", "Hi") 會傳入單一個陣列引數,這常讓從其他語言轉來的人感到意外。
陣列、雜湊表與自訂物件
陣列用 @( ) 或以逗號分隔的清單建立。雜湊表寫成 @{ },儲存鍵值對。[pscustomobject] 可把雜湊表轉成物件,能與 Sort-Object、Format-Table 和 Export-Csv 順利搭配。
$langs = @("PowerShell", "Python")
$langs += "Go" # creates a new, longer array
$langs.Count # 3
$langs[0] # PowerShell
$langs -contains "Go" # True
$ports = @{ http = 80; https = 443 }
$ports["ssh"] = 22
$ports.https # 443
$ports.Keys.Count # 3
$user = [pscustomobject]@{ Name = "Ann"; Age = 31 }
$user.Name # Ann
$people = @(
[pscustomobject]@{ Name = "Bo"; Age = 25 }
$user
)
$people | Sort-Object Age | Format-Table用 += 為陣列新增元素,每次都會複製整個陣列。處理大量迴圈時,請直接收集迴圈的輸出($result = foreach (...) { ... }),或使用 [System.Collections.Generic.List[object]]。
錯誤處理
PowerShell 有會中止執行的終止性錯誤,以及只印出訊息後繼續執行的非終止性錯誤。try/catch/finally 只會捕捉終止性錯誤,所以想捕捉某個 Cmdlet 的失敗時,請為它加上 -ErrorAction Stop。
try {
$content = Get-Content -Path "missing.txt" -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning "File not found: $($_.Exception.Message)"
}
catch {
Write-Error "Unexpected error: $_"
}
finally {
"cleanup done"
}
$ErrorActionPreference = "Stop" # make all errors terminating in this script
throw "Something went wrong" # raise your own terminating error在 catch 內,$_ 是錯誤記錄。在腳本開頭設定 $ErrorActionPreference = "Stop" 是常見的「快速失敗」做法。
完整的小腳本:磁碟用量報告
這個腳本列出資料夾下最大的檔案,依副檔名分組,並匯出 CSV 報告。它結合了參數、管線、計算屬性與錯誤處理。
# report.ps1
param(
[string]$Path = ".",
[int]$Top = 5
)
$ErrorActionPreference = "Stop"
$files = Get-ChildItem -Path $Path -File -Recurse
"Largest $Top files:"
$files | Sort-Object Length -Descending | Select-Object -First $Top |
Format-Table Name, @{ Name = "SizeKB"; Expression = { [math]::Round($_.Length / 1KB, 1) } }
$byExt = $files | Group-Object Extension | ForEach-Object {
[pscustomobject]@{
Extension = if ($_.Name) { $_.Name } else { "(none)" }
Files = $_.Count
TotalMB = [math]::Round(($_.Group | Measure-Object Length -Sum).Sum / 1MB, 2)
}
} | Sort-Object TotalMB -Descending
$byExt | Format-Table
$byExt | Export-Csv -Path "usage.csv" -NoTypeInformation
"Report saved to usage.csv"pwsh ./report.ps1 -Path ~/Documents -Top 3接下來可以學什麼
- Microsoft Learn 上的 PowerShell 101 與 PowerShell 文件。
- 在 Shell 中執行
Get-Help about_*,例如Get-Help about_Operators;請先執行Update-Help。 - PowerShell Gallery,官方的模組庫,搭配
Install-Module使用。 - PSScriptAnalyzer,依建議的最佳做法檢查腳本的 Linter。
常見問題
PowerShell 和 Windows PowerShell 有什麼差別?
Windows PowerShell 5.1 是內建於 Windows、以 .NET Framework 為基礎的舊版。PowerShell 7 以上是跨平台、開源、以現代 .NET 為基礎的版本,以 pwsh 指令啟動。
PowerShell 和命令提示字元一樣嗎?
不一樣。命令提示字元(cmd.exe)執行批次指令並傳遞文字。PowerShell 是完整的腳本語言,傳遞的是物件,但仍然可以執行大多數命令列程式。
PowerShell 可以在 Linux 和 macOS 上執行嗎?
可以。PowerShell 7 以上可在 Windows、Linux 與 macOS 上執行,不過部分 Windows 專用模組只在 Windows 上提供。
為什麼我的 .ps1 腳本無法執行?
可能是 Windows 的執行原則阻擋了它。請執行 Set-ExecutionPolicy -Scope CurrentUser RemoteSigned,並以路徑啟動腳本,例如 ./script.ps1。
PowerShell 中的 $_ 是什麼意思?
$_(也可寫成 $PSItem)是管線中的目前物件,用於 Where-Object 和 ForEach-Object 等 Cmdlet 的指令碼區塊內;在 catch 內則代表目前的錯誤。