cv.cm

編碼 · 程式語言

PowerShell 入門教學

閱讀約 10 分鐘

簡答

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]4232 位元整數
[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 內則代表目前的錯誤。

全部編碼教學