跳到主要内容

控制流

控制流语句决定了脚本的执行路径。PowerShell 提供了完整的条件判断和循环结构,包括 if-else、switch、for、foreach、while、do-while 等。

条件判断

if 语句

if 语句根据条件决定是否执行代码块:

$temperature = 25

if ($temperature -gt 30) {
Write-Host "天气炎热"
}

if-else 语句

$score = 75

if ($score -ge 60) {
Write-Host "及格"
} else {
Write-Host "不及格"
}

if-elseif-else 语句

多个条件判断:

$score = 85

if ($score -ge 90) {
Write-Host "优秀"
} elseif ($score -ge 80) {
Write-Host "良好"
} elseif ($score -ge 60) {
Write-Host "及格"
} else {
Write-Host "不及格"
}

条件表达式

if 的条件可以是任何表达式,PowerShell 会自动转换为布尔值:

$name = "PowerShell"

if ($name) {
Write-Host "变量有值"
}

$processes = Get-Process chrome -ErrorAction SilentlyContinue
if ($processes) {
Write-Host "Chrome 正在运行"
}

switch 语句

switch 语句用于多值匹配,比多个 if-elseif 更清晰:

基本用法

$day = 3

switch ($day) {
1 { "星期一" }
2 { "星期二" }
3 { "星期三" }
4 { "星期四" }
5 { "星期五" }
6 { "星期六" }
7 { "星期日" }
default { "无效的日期" }
}

使用 break

默认情况下,switch 会继续检查后续条件。使用 break 停止匹配:

$value = 1

switch ($value) {
1 { "一"; break }
2 { "二"; break }
default { "其他" }
}

字符串匹配

$fruit = "apple"

switch ($fruit) {
"apple" { "苹果" }
"banana" { "香蕉" }
"orange" { "橙子" }
default { "未知水果" }
}

通配符匹配

使用 -wildcard 参数:

$filename = "document.txt"

switch -wildcard ($filename) {
"*.txt" { "文本文件" }
"*.jpg" { "图片文件" }
"*.mp3" { "音频文件" }
default { "未知类型" }
}

正则表达式匹配

使用 -regex 参数:

$email = "[email protected]"

switch -regex ($email) {
"^\w+@\w+\.\w+$" { "有效的邮箱格式" }
default { "无效的邮箱格式" }
}

匹配多个值

$value = 3

switch ($value) {
{ $_ -in 1, 3, 5, 7, 9 } { "奇数" }
{ $_ -in 2, 4, 6, 8, 10 } { "偶数" }
}

处理数组

switch 可以遍历数组中的每个元素:

$numbers = 1, 2, 3, 4, 5

switch ($numbers) {
{ $_ % 2 -eq 0 } { "$_ 是偶数" }
{ $_ % 2 -ne 0 } { "$_ 是奇数" }
}

循环结构

for 循环

for 循环适合已知迭代次数的情况:

for ($i = 1; $i -le 5; $i++) {
Write-Host "第 $i 次循环"
}

遍历数组:

$fruits = "apple", "banana", "cherry"

for ($i = 0; $i -lt $fruits.Length; $i++) {
Write-Host "水果 $i : $($fruits[$i])"
}

foreach 循环

foreach 循环遍历集合中的每个元素:

$fruits = "apple", "banana", "cherry"

foreach ($fruit in $fruits) {
Write-Host "水果: $fruit"
}

遍历哈希表:

$person = @{
Name = "张三"
Age = 30
City = "北京"
}

foreach ($key in $person.Keys) {
Write-Host "$key : $($person[$key])"
}

while 循环

while 循环在条件为真时持续执行:

$count = 0

while ($count -lt 5) {
Write-Host "计数: $count"
$count++
}

读取用户输入直到满足条件:

$input = ""

while ($input -ne "quit") {
$input = Read-Host "请输入命令(输入 quit 退出)"
Write-Host "你输入了: $input"
}

do-while 循环

do-while 循环先执行一次,然后检查条件:

$count = 0

do {
Write-Host "计数: $count"
$count++
} while ($count -lt 5)

while 的区别是,即使条件一开始就为假,do-while 也会执行一次:

$count = 10

do {
Write-Host "这会执行一次"
$count++
} while ($count -lt 5)

do-until 循环

do-until 循环执行直到条件为真:

$count = 0

do {
Write-Host "计数: $count"
$count++
} until ($count -ge 5)

do-untildo-while 的逻辑相反:do-while 在条件为真时继续,do-until 在条件为真时停止。

循环控制

break 语句

break 立即终止整个循环:

for ($i = 1; $i -le 10; $i++) {
if ($i -eq 5) {
break
}
Write-Host "i = $i"
}

输出:

i = 1
i = 2
i = 3
i = 4

continue 语句

continue 跳过当前迭代,继续下一次循环:

for ($i = 1; $i -le 5; $i++) {
if ($i -eq 3) {
continue
}
Write-Host "i = $i"
}

输出:

i = 1
i = 2
i = 4
i = 5

嵌套循环中的 break

在嵌套循环中,break 只终止最内层循环。使用标签可以终止外层循环:

:outer for ($i = 1; $i -le 3; $i++) {
for ($j = 1; $j -le 3; $j++) {
if ($i -eq 2 -and $j -eq 2) {
break outer
}
Write-Host "i=$i, j=$j"
}
}

ForEach-Object cmdlet

除了 foreach 语句,还有 ForEach-Object cmdlet,常用于管道:

1..5 | ForEach-Object {
Write-Host "数字: $_"
}

ForEach-Object 支持 beginprocessend 块:

1..5 | ForEach-Object -Begin {
Write-Host "开始处理"
} -Process {
Write-Host "处理: $_"
} -End {
Write-Host "处理完成"
}

别名 %ForEach-Object 的简写:

1..5 | % { $_ * 2 }

Where-Object cmdlet

Where-Object 用于过滤集合,类似 SQL 的 WHERE 子句:

1..10 | Where-Object { $_ -gt 5 }

过滤进程:

Get-Process | Where-Object { $_.CPU -gt 100 }

使用脚本块语法简化:

Get-Process | Where-Object CPU -gt 100

别名 ?Where-Object 的简写:

1..10 | ? { $_ % 2 -eq 0 }

实用示例

批量处理文件

$files = Get-ChildItem -Path "C:\Logs" -Filter "*.log"

foreach ($file in $files) {
$content = Get-Content $file.FullName
$lineCount = $content.Count
Write-Host "$($file.Name): $lineCount 行"
}

查找大文件

$largeFiles = Get-ChildItem -Path "C:\" -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.Length -gt 100MB } |
Select-Object Name, @{Name="Size(MB)";Expression={[math]::Round($_.Length/1MB, 2)}}

foreach ($file in $largeFiles) {
Write-Host "$($file.Name) - $($file.'Size(MB)') MB"
}

监控服务状态

$services = "Spooler", "wuauserv", "WinRM"

foreach ($serviceName in $services) {
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue

if ($service) {
switch ($service.Status) {
"Running" {
Write-Host "$serviceName 正在运行" -ForegroundColor Green
}
"Stopped" {
Write-Host "$serviceName 已停止" -ForegroundColor Red
}
default {
Write-Host "$serviceName 状态: $($service.Status)" -ForegroundColor Yellow
}
}
} else {
Write-Host "$serviceName 不存在" -ForegroundColor Gray
}
}

下一步

掌握了控制流后,接下来学习 函数,了解如何定义可重用的代码块。