当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 如何通过示例使用 Powershell Foreach 循环

作者:精品下载站 日期:2024-12-14 06:49:00 浏览:15 分类:玩电脑

如何通过示例使用 Powershell Foreach 循环


PowerShell 中的 foreach 语句是一个迭代语句,它允许您针对集合或数组中的每个项目重复执行命令或脚本。这使您能够加快对大型项目集合的处理速度,其中需要对每个项目运行相同的流程或函数。

在本教程中,我将详细解释在 PowerShell 脚本中使用 foreach 语句的有用性,并为您提供可能有用的实际示例。

Foreach 循环有何用处

如果没有 foreach 循环,对多个项目多次执行类似的操作将是乏味且低效的。一遍又一遍地编写相同的命令不仅非常耗时,而且代码使用效率低下。 foreach语句解决了这个问题。

简单地说,你可以使用 foreach 语句将一段代码变成这样:

$report = [System.Collections.Generic.List[Object]]::new()
$report += Get-Service -name BITS -RequiredServices | Select Name, ServiceType, Status
$report += Get-Service -name DHCP -RequiredServices | Select Name, ServiceType, Status
$report += Get-Service -name gpsvc -RequiredServices | Select Name, ServiceType, Status
$report += Get-Service -name iphlpsvc -RequiredServices | Select Name, ServiceType, Status

变成看起来更优雅的东西:

$services = Get-Service
$report = [System.Collections.Generic.List[Object]]::new()
Foreach ($Service in $Services) {
    $report += $service | Select Name, ServiceType, Status
}

甚至:

从上面可以看出,本来有 50 行代码,现在已经缩小到只有 5 行,如果你想真正高效的话,甚至只有 2 行!这两个改进的示例都很好用,但是,根据阅读代码的人的经验水平,第一个示例(有 5 行)可能更容易阅读和理解。

$report = [System.Collections.Generic.List[Object]]::new()
Get-Service | Foreach-Object {$report += $_ | Select Name, ServiceType, Status}

如何编写 Foreach 循环

当您编写 Foreach 循环时,它们有一个基本结构。 foreach 语句后面是括号,括号内是 in 运算符。查看下面的结构 $item 定义循环每个周期中的单个项目,而 $itemcollection 是包含正在循环的多个项目的变量。

然后是大括号(或大括号),这些大括号内是可以使用 $item 变量对集合中的每个项目运行的命令。

Foreach ($item in $itemcollection) {
    "Do something" $item
}

Foreach 与 Foreach 对象

尽管foreach 语句和foreach-object cmdlet 看起来很相似,但它们的用途不同。令人困惑的是,foreach也是foreach-object的别名,因此,尽管每个命令的意图相同,但它们的使用略有不同。

从根本上讲,当使用 foreach 语句时,您的项目集合会预先存储在内存中的变量中,例如上面的示例,在使用 foreach 语句之前,我的项目保存在变量 $itemcollection 中。 foreach-object cmdlet 设计用于在命令管道中使用,尽管执行时间较长,但它有更多可用参数可供使用。

您可以使用 Measure-Command 命令查看 foreach 语句和 foreach-object cmdlet 之间的速度差异。

让我们首先测量管道中 Foreach-Object 的运行速度。

Measure-Command {
    $report = [System.Collections.Generic.List[Object]]::new()
    Get-Service | Foreach-Object {$report += $_ | Select Name, ServiceType, Status}
}

如您所见,运行该命令总共花费了 72 毫秒。

[玩转系统] 如何通过示例使用 Powershell Foreach 循环

现在我们将看看使用 foreach 语句运行相同命令时的速度。

Measure-Command {
    $services = Get-Service
    $report = [System.Collections.Generic.List[Object]]::new()
    Foreach ($Service in $Services) {
        $report += $service | Select Name, ServiceType, Status
    }
}

正如您所看到的,尽管在我们的场景中时间差异很小,但与使用 foreach-object 相比,命令的完成速度要快得多,只需 47 毫秒。

[玩转系统] 如何通过示例使用 Powershell Foreach 循环

Foreach 循环示例

以下是在 PowerShell 中使用 foreach 循环的一些不同示例。

对多个项目运行相同的命令

在最简单的形式中,使用 foreach 循环,您可以对集合中的多个项目运行相同的命令。在下面的示例中,我手动定义了在本地计算机上找到的名称或服务的集合。然后,我循环遍历每个服务并运行 stop-servicestart-service 命令,这些命令将对每个服务执行相关操作。

$Services = "Spooler","NetLogon","dbupdate","BITS"

Foreach ($service in $services) {
    Stop-service $service
    start-service $service
}

修改多个项目的设置

Foreach 循环可用于更复杂的任务,例如,由于我经常在 Active Directory 中工作,我可能想要跨多个用户修改单个属性。在下面的示例中,我将具有特定设置的所有用户存储到变量 $users 中。然后,我循环遍历每个用户,将该设置修改为新值,在本例中是用户主体名称设置。

$users = Get-ADUser -Filter * | Where {$_.UserPrincipalName -match "ourcloudnetwork.co.uk"}
Foreach ($user in $users) {
        $upn = $user.UserPrincipalName.Replace("ourcloudnetwork.co.uk","ourcloudnetwork.com")
        Set-ADUser -Identity $user.SamAccountName -UserPrincipalName $upn
}

在 Foreach 循环中使用函数

当处理 foreach 循环中包含更复杂操作的较大脚本时,将某些操作移动到函数中,然后从循环内调用该函数可能更有意义。尽管我的示例并不能很好地体现这一点,但对于更复杂的任务来说,这个概念仍然是相同的。

$olddomain = "ourcloudnetwork.com"
$newdomain = "ourcloudnetwork.co.uk"

function Change-Upn {
    $upn = $user.UserPrincipalName.Replace("$olddomain","$newdomain")
    Set-ADUser -Identity $user.SamAccountName -UserPrincipalName $upn
}

$users = Get-ADUser -Filter * | Where {$_.UserPrincipalName -match "$olddomain"}
Foreach ($user in $users) {
        Change-Upn
}

使用 foreach 循环构建数组

我发现自己几乎每次使用 foreach 循环时都会做的事情是构建某种形式的数组。使用 foreach 循环可以快速高效地构建数组。首先在 foreach 循环之前创建一个空数组,然后使用 += 运算符将新项目添加到数组中。

下面是一个简单的示例,我们循环遍历 $items 中存储的每个项目,然后循环每个项目并将 item 属性添加到数组中。

$items = "1","2","3","4","5"

$array = @()

Foreach ($item in $items) {
        $array += $item.property
}

使用 foreach 循环构建报告

使用自定义 PowerShell 对象构建报告是一项非常有用的技能。虽然您通常可以使用相关的 GET 命令找到所需的所有信息,但使用 foreach 循环构建报告将允许您查询有关集合中每个项目的附加信息,并构建完全适合您的详细报告。要求(提供)的信息

在下面的示例中,我查询 Active Directory 中的所有用户,然后使用该信息循环访问每个用户并使用 Get-Mailbox 命令查询他们的 Exchange 邮箱。

$users = Get-ADUser -Filter *

$Report = [System.Collections.Generic.List[Object]]::new()

forEach ($user in $users) {
    $Aliases = $null
    $mailbox = $null
    $mailbox = Get-Mailbox -Identity $user.UserPrincipalName
    $Aliases = ($mailbox.EmailAddresses | ForEach-Object {$_ -replace "smtp:",""}) -join ","
    $obj = [PSCustomObject][ordered]@{
        "DisplayName" = $cuser.DisplayName
        "UserPrincipalName" = $cuser.UserPrincipalName
        "Aliases" = $Aliases
    }
    $report.Add($obj)
 }

你可以从代码中看到我首先创建一个 Collection 对象:

$Report=[System.Collections.Generic.List[Object]]::new()

然后,我构建一个自定义 PowerShell 对象,该对象使用以下代码添加到集合中:

$report.Add($obj)

创建嵌套的 foreach 循环

您还可以在现有的 foreach 语句中嵌套 foreach 语句。在下面的示例中,我正在构建有关 Exchange 中的电子邮件组的报告。我循环遍历每个组,然后获取每个组的组成员,并循环遍历每个成员以提取特定信息并构建基本报告。

$Report = [System.Collections.Generic.List[Object]]::new()

$GroupList = Get-DistributionGroup

Foreach ($group in $grouplist) {
    $groupmembers = $null
    $groupmembers = Get-DistributionGroupMember -Identity $group.Name
    Foreach ($member in $groupmembers) {
        $obj = [PSCustomObject][Ordered]@{  
         "Member"                 = $member.PrimarySmtpAddress
         "Member Type"            = $Member.RecipientType
         "Group"                  = $Group.Name
         "Group Address"          = $Group.PrimarySmtpAddress
         }
    $Report.Add($obj)
    }
}

将 IF 语句集成到 foreach 循环中

与嵌套 foreach 语句类似,您还可以在循环中嵌套或集成 IF 语句,以根据条件执行特定操作或在脚本中提供额外的错误检查。我们可以以非常基本的方式在前面的示例中实现 IF 语句,以确保捕获报告中不包含任何成员的任何组。

$Report = [System.Collections.Generic.List[Object]]::new()

$GroupList = Get-DistributionGroup

Foreach ($group in $grouplist) {
    $groupmembers = $null
    $groupmembers = Get-DistributionGroupMember -Identity $group.Name
    If ($groupmembers -eq "") {
        $obj = [PSCustomObject][Ordered]@{  
         "Member"                 = "No members"
         "Member Type"            = "N/A"
         "Group"                  = $Group.Name
         "Group Address"          = $Group.PrimarySmtpAddress
         }
         $Report.Add($obj)
    } else {
         Foreach ($member in $groupmembers) {
                $obj = [PSCustomObject][Ordered]@{  
                 "Member"                 = $member.PrimarySmtpAddress
                 "Member Type"            = $Member.RecipientType
                 "Group"                  = $Group.Name
                 "Group Address"          = $Group.PrimarySmtpAddress
                }
         $Report.Add($obj)
    }
}

在上一个脚本中,如果组不包含成员,则不会将任何信息添加到报告中,现在我们通过在循环开始时实现 IF 语句来捕获空组。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯