脚本编写
当你从编写 PowerShell 单行命令到编写脚本时,实际上并没有看上去那么复杂。 脚本只不过是在 PowerShell 控制台中以交互方式运行的相同或类似命令,只是将它们保存为.ps1脚本文件。 可以使用一些脚本构造,例如 foreach 循环而不是 ForEach-Object cmdlet。 考虑到这既是语言关键字,又是 foreach cmdlet 的 ForEach-Object 别名,初学者可能会感到困惑。
循环
PowerShell 的最佳方面之一是其可伸缩性。 一旦你学会了如何为单个项目执行任务,将相同的操作应用于数百个项目几乎同样简单。 在 PowerShell 中使用不同类型的循环之一来遍历项。
ForEach-Object
ForEach-Object 是一个 cmdlet,用于遍历管道中的项,例如使用 PowerShell 单行命令。
ForEach-Object 通过管道流式传输对象。
尽管 模块 参数 Get-Command 接受多个字符串值,但它仅通过属性名称通过管道输入接受它们。 在以下方案中,如果要通过管道将两个字符串值 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
在上一个示例中, $_ 是当前对象。 从 PowerShell 版本 3.0 开始, $PSItem 可以使用而不是 $_。 大多数经验丰富的 PowerShell 用户更喜欢使用 $_ ,因为它向后兼容且不太适合键入。
使用 foreach 关键字时,必须先将项存储在内存中,然后才能循环访问它们,如果不知道正在使用的项数,这可能很困难。
$ComputerName = 'DC01', 'WEB01'
foreach ($Computer in $ComputerName) {
Get-ADComputer -Identity $Computer
}
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
很多时候,例如 foreach 或 ForEach-Object 这样的循环是必需的。 否则会收到错误消息。
Get-ADComputer -Identity 'DC01', 'WEB01'
Get-ADComputer : Cannot convert 'System.Object[]' to the type
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter
'Identity'. Specified method is not supported.
At line:1 char:26
+ Get-ADComputer -Identity 'DC01', 'WEB01'
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], Parame
terBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirecto
ry.Management.Commands.GetADComputer
其他情况下,可以在消除循环的同时获得相同的结果。 请参阅 cmdlet 帮助以了解选项。
'DC01', 'WEB01' | Get-ADComputer
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
如前面的示例所示, 标识 参数 Get-ADComputer 仅在通过参数输入提供时接受单个值。 但是,通过使用管道,可以将多个值发送到命令,因为一次处理一个值。
为
循环 for 在满足指定条件时循环。 我不经常使用 for 循环,但它有使用。
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
}
Sleeping for 1 seconds
Sleeping for 2 seconds
Sleeping for 3 seconds
Sleeping for 4 seconds
在上一示例中,循环从数字 1 开始循环,只要计数器变量 $i 小于 5,该循环将执行四次。 它总共睡眠了 10 秒。
去做
PowerShell 中有两个不同的 do 循环: do until 和 do while。
do until 在指定条件为 false 时运行。
下面的示例是一个数字游戏,它一直持续到你猜到的值等于 cmdlet 生成的相同数字 Get-Random 。
$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)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Do While 是相反的。 只要指定条件的计算结果为 true,它就运行。
$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)
What's your guess?: 1
Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Too low!
What's your guess?: 4
相同的结果可以通过将测试条件反转为不相等的 Do While 循环来实现。
do 循环始终至少运行一次,因为条件是在循环结束时计算的。
当
do while与循环一样,只要指定的条件为 true,循环while就运行。 但是,区别在于 while 循环在运行任何代码之前,会先在循环顶部评估条件。 因此,如果条件的计算结果为 false,则不会运行。
下面的示例计算美国感恩节的日期。 它总是在11月的第四个星期四。 循环从 11 月的第 22 天开始,并添加一天,而一周中的日期不等于星期四。 如果 22 号是星期四,循环根本不会运行。
$date = Get-Date -Date 'November 22'
while ($date.DayOfWeek -ne 'Thursday') {
$date = $date.AddDays(1)
}
Write-Output $date
Thursday, November 23, 2017 12:00:00 AM
break、continue 和 return
关键字 break 旨在退出循环,通常用于 switch 语句。 在以下示例中, break 导致循环在第一次迭代后结束。
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
break
}
Sleeping for 1 seconds
关键字 continue 旨在跳到循环的下一次迭代。
以下示例输出数字 1、2、4 和 5。 它跳过数字 3,并继续执行循环的下一次迭代。 如同break一样,continue打破循环,但仅限于当前的迭代。 执行将继续进行下一次迭代,而不是完全中断循环并停止。
while ($i -lt 5) {
$i += 1
if ($i -eq 3) {
continue
}
Write-Output $i
}
1
2
4
5
关键字 return 旨在退出现有范围。
请注意,在以下示例中输出 return 第一个结果,然后退出循环。
$number = 1..10
foreach ($n in $number) {
if ($n -ge 4) {
return $n
}
}
4
可在我的博客文章之一中找到对结果语句的更彻底的解释: PowerShell 返回关键字。
概要
在本章中,你了解了 PowerShell 中存在的不同类型的循环。
回顾
-
ForEach-Objectcmdlet 和foreach语句之间有什么区别? - 使用
while循环而不是do while或do until循环的主要优势是什么? - 语句
break和continue语句有何不同?
参考文献
后续步骤
在 第 7 章中,你将了解如何使用 Windows Management Instrumentation(WMI)和通用信息模型(CIM)检索和使用系统信息。 你将探索基于 CIM 的新式 cmdlet,了解它们与旧版 WMI 命令有何不同,并使用这些 cmdlet 高效查询本地和远程系统。