[TOC]
0x05 流(Flow)控制
描述: 当你从编写 PowerShell 单行命令转为编写脚本时,实际复杂程度没有想象的那么高。脚本只是在 PowerShell 控制台中以交互方式运行的相同或类似命令,只不过它们保存为 .PS1 文件;
0.条件判断
Where-Object 语句
描述: Where-Object会对集合逐个过滤,将符合条件的结果保留, 别名是 ? 与 Where。
基础示例:
# 1.根据Notepad++进程名过滤所有记事本进程。
Get-Process | Where-Object {$_.Name -eq "notepad"}
# Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
# ------- ------ ----- ----- ----- ------ -- -----------
# 158 7 8800 37264 114 18.41 6204 notepad
# 2.根据company过滤所有产品发布者以”Microsoft”打头的进程:
Get-Process | Where-Object {$_.company -like '*Microsoft*' } | select Name,Description,Company
# 3.因为Where-Object的使用概率比较高,所以有一个很形象的别名 ? 可以使用:
Get-Service | ? {$_.Name -like "B*"}
Get-Service | where {$_.Name -like "B*"}
# 4.输出可以被2整除的值(满足则输出), 或者两者同时满足
1..10 | ? { $_ % 2 -eq 0 }
# 2
# 4
# 6
# 8
# 10
1..10 | where { $_ % 2 -eq 0 -and $_ % 4 -eq 0 }
# 4
# 8
Tips : 通过Get-Alias -Definition Where-Object利用cmdlet查看其别名
IF 语句
if…else 与 if…elseif…else 语句
基础示例:
# 1.单条件判断
$week=(Get-Date).DayOfWeek
if ( $week -eq 'Thursday' ) {
Write-Output "今天是星期四(Thur),当前时间:"
Get-Date
} else {
Write-Output "今天不是星期四"
}
# 2.多条件判断
if ( $week -eq 'Monday' ) {
Write-Output "unhappy,今天是星期1"
} elseif ( $week -eq 'Thesday') {
Write-Output "unhappy,今天是星期2"
} elseif ( $week -eq 'Wednesday') {
Write-Output "unhappy,今天是星期3"
} elseif ( $week -eq 'Thursday') {
Write-Output "unhappy,今天是星期4"
} elseif ( $week -eq 'Friday') {
Write-Output "unhappy,今天是星期5"
} elseif ( $week -eq 'Saturday') {
Write-Output "Happy,今天是星期6"
} else {
Write-Output "Happy,今天是星期天"
}
Switch 判断语句
基础示例:
# 方式1.满足条件输出
$value=6
switch($value)
{
1 {"I come from Beijing"}
2 {"I come from Shanghai"}
3 {"I come from Tianjin"}
6 {"I come from Chongqing"}
}
# I come from Chongqing
# 方式2.测试取值范围
# 自定义将条件放在花括号中,必须保证条件表达式的返回值为布尔类型”$True”或”$False”
$value=18
switch($value)
{
{$_ -lt 10} {"小于10"}
10 {"等于10"}
{$_ -gt 10} {"大于10"}
}
#输出
#大于10
# 方式3.没有匹配条件时,我们需要使用Default关键字
$value=-7
# 使用 Switch 测试取值范围
switch($value)
{
{($_ -lt 10) -and ( $_ -gt 0) } {"小于10"}
10 {"等于10"}
{$_ -gt 10} {"大于10"}
Default {"没有匹配条件"}
}
# 没有匹配条件
# 如果case中有多个条件匹配,那么每个匹配的条件都会进行处理,所以我们需要使用Break关键字
$value=99
switch($value)
{
{$_ -lt 5 } { "小于5"; break}
{$_ -gt 0 } { "大于0"; break}
{$_ -lt 100} { "小于100"; break}
Default {"没有匹配条件"}
}
# 大于0
# 方式4.比较字符串(大小写敏感/通配符/正则匹配)
# 即大小写敏感比较字符串
$domain="Www.weiyigeek.top"
switch -case ($domain)
{
"Www.weiyigeek.top" {"Ok 1"}
"www.weiyiGeek.com" {"Ok 2" }
"WWW.weiyiGeegk.COM" {"Ok 3"}
}
#使用通配符
$domain="www.mossfly.com"
switch -wildcard($domain)
{
"*" {"匹配'*'"}
"*.com" {"匹配*.top" }
"*.*.*" {"匹配*.*.*"}
}
$mail="master@weiyigeek.top"
#使用通配符
switch -regex ($mail)
{
"^master" {"master"}
"top$" {"top结尾" }
"d{1,3}.d{1,3}.d{1,3}.d{1,3}" {"IP地址"}
}
#www打头
#com结尾
# 方式5.Switch支持对集合所有元素进行匹配,例如使用 Switch语句演示打印水仙花数(即该数得每个数的三次方只和=该数)
$value=100..999
switch($value)
{
{
[Math]::Pow($_%10,3) + [Math]::Pow( [Math]::Truncate($_%100/10) ,3) + [Math]::Pow( [Math]::Truncate($_/100) , 3) -eq $_
} {$_}
}
#153
#370
#371
#407
1.循环执行
描述: PowerShell 优势是确定了如何为某个项执行某些操作后,就可以很容易地为数百个项执行相同的任务。 只需使用 PowerShell 中多种不同类型的循环之一循环访问这些项即可。
ForEach-Object 语句
描述: ForEach-Object 是用于循环访问管道中的项的 cmdlet,例如使用 PowerShell 单行命令然后通过管道流式处理对象。其实是ForEach-Object可以接受三个脚本块用于管道的流模式处理,分别代表begin,process和end。
基础示例:
# 方式1.采用 ForEach-Object 循环处理
WeiyiGeek> 1..10 | ForEach-Object { Write-Host -NoNewline "当前 $_ 次序 ->"; $_ * 10}
当前 1 次序 ->10
当前 2 次序 ->20
当前 3 次序 ->30
当前 4 次序 ->40
当前 5 次序 ->50
当前 6 次序 ->60
当前 7 次序 ->70
当前 8 次序 ->80
当前 9 次序 ->90
当前 10 次序 ->100
# 方式2.在下面的情形中,如果我想通过管道将两个字符串按值传递到 Get-Command 以便与 Module 参数一起使用,则需要使用 ForEach-Object cmdlet。
'ActiveDirectory', 'SQLServer' |
ForEach-Object {Get-Command -Module $_} |
Group-Object -Property ModuleName -NoElement |
Sort-Object -Property Count -Descending
# Count Name
# ----- ----
# 147 ActiveDirectory
# 82 SqlServer
'Get-ComputerInfo', 'Test-Path' |
ForEach-Object {Get-Command -Name $_} |
Group-Object -Property ModuleName -NoElement |
Sort-Object -Property Count -Descending
# Count Name
# ----- ----
# 2 Microsoft.PowerShell.M...
# 方式3.采用 % 以及别名进行使用处理
1..5 | % { Write-Host -NoNewline "第{$_}次时间:"; Get-Date;Start-Sleep 1 }
# 第{1}次时间:
# 2021年4月1日 16:58:55
# 第{2}次时间:2021年4月1日 16:58:56
# 第{3}次时间:2021年4月1日 16:58:57
# 第{4}次时间:2021年4月1日 16:58:58
# 第{5}次时间:2021年4月1日 16:58:59
# 方式4.采用 foreach 别名进行使用处理
foreach ( $a in 1..3) { foreach ( $b in 1..3) { Write-Host -NoNewline "$a + $b = "; $a + $B } }
# 1 + 1 = 2
# 1 + 2 = 3
# 1 + 3 = 4
# 2 + 1 = 3
# 2 + 2 = 4
# 2 + 3 = 5
# 3 + 1 = 4
# 3 + 2 = 5
# 3 + 3 = 6
foreach ($Computer in 'DC01', 'WEB01') {
Get-ADComputer -Identity $Computer
}
# 方式5.逐个处理所有管道结果(个性化- 值得学习类似于print %s 占位符)
ls | ForEach-Object {"文件名:{0} 文件大小{1}KB: " -f $_.Name,($_.length/1kb).tostring()}
文件名:a.html 文件大小65.99609375KB:
文件名:a.txt 文件大小25.765625KB:
文件名:alias 文件大小11.77734375KB:
For 语句
描述: 当指定的条件为 true 时,for 循环会进行循环访问,在PS中应该使用较少。
# (1) 在前面的示例中,循环从数字 1 开始循环访问 4 次,并在计数器变量 $i 小于 5 时继续循环访问。
# 休眠时间共计 10 秒。
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
}
Do 语句
描述: PowerShell 中有两个不同的 do 循环。
指定的条件为 false 时, Do Until 运行。指定的条件为 True 时, Do While 运行
# (1) 数字游戏,在你猜测的值等于 Get-Random cmdlet 生成的相同数字时游戏结束。
$number = Get-Random -Minimum 1 -Maximum 10
do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
}
elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
until ($guess -eq $number)
# (2) 只通过将测试条件反转为不等于,使用 Do While 循环可实现相同的结果。
$number = Get-Random -Minimum 1 -Maximum 10
do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
} elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
while ($guess -ne $number)
Tips : Do 循环始终运行至少一次,因为将在循环结束时计算条件的结果。
While 语句
描述: 与 Do While 循环类似,只要指定的条件为 true,While 循环就会运行。 但差别在于 While 循环会在运行任何代码之前,计算循环顶部条件的结果, 如果条件计算结果为 false,它就不会运行代码块中的内容。
# 1.使用案例
$week = (Get-Date).DayOfWeek
while ( $week -eq 'Thursday') {
Write-Output "今天是星期三将在此基础上加1天: "
$date = (Get-Date).AddDays(1)
break
}
Write-Output $date
# 今天是星期三将在此基础上加1天:
# 2021年4月2日 17:23:49
Tips : 从 PowerShell 版本 3.0 开始,可以使用 PSItem 而不是 。 但我发现,大多数经验丰富的 PowerShell 用户仍更喜欢使用
Tips : 使用 foreach 关键字时,必须先将所有项存储在内存中,然后才能循环访问这些项,如果不知道要处理的项数,此操作可能会很困难。
Switch 循环语句
描述: Switch 本是多路分支的关键字,但是在Powershell中由于Switch支持集合,所以也可以使用它进行循环处理。
基础示例:
# 1.使用Switch循环
Switch (10..1)
{
Default { " n = $_" }
}
# n = 10
# n = 9
# n = 8
# n = 7
# n = 6
# n = 5
# n = 4
# n = 3
# n = 2
# n = 1
# 2.有时对集合的处理,在循环中还须条件判断,使用Switch循环可以一部到位例如奇数和偶数
$nums = 10..7
Switch ($nums)
{
{($_ % 2) -eq 0} {"$_ 偶数"}
{($_ % 2) -ne 0} {"$_ 奇数"}
}
# 10 偶数
# 9 奇数
# 8 偶数
# 7 奇数
2.终止操作
描述: 如何在循环中当满足某些条件时跳出循环, 我们可以采用以下关键字 Break、Continue 和 Return。
1) Break 旨在中断循环。它通常与 switch 语句一起使用。2) Continue 旨在跳到循环的下一次迭代。它通常与 while 语句一起使用。3) Return 旨在退出现有作用域。
基础案例:
# 1.示例中所示的 break 语句导致循环在第一次迭代时退出。
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
break
}
# 2.示例中,将输出数字 1、2、4 和 5。 它跳过数字 3,并继续执行循环的下一次迭代。与 break 类似 continue 将中断除当前迭代以外的循环。
# Execution 将继续进行下一次迭代,而不是中断循环并停止。(此处 $i 默认为0)
while ($i -lt 5) {
$i += 1
if ($i -eq 3) {
continue
}
Write-Output $i
}
# 3.示例中,return 输出第一个结果,然后退出循环
$number = 1..10
foreach ($n in $number) {
if ($n -ge 4) {
Return $n
}
}