脚本编写
当你从编写 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-Object
cmdlet 和foreach
语句之间有什么区别? - 使用
while
循环而不是do while
或do until
循环的主要优势是什么? - 语句
break
和continue
语句有何不同?