วิธีใช้ Powershell Foreach Loop พร้อมตัวอย่าง
คำสั่ง foreach ใน PowerShell เป็นคำสั่งวนซ้ำซึ่งช่วยให้คุณสามารถรันคำสั่งหรือสคริปต์ซ้ำกับแต่ละรายการในคอลเลกชันหรืออาร์เรย์ สิ่งนี้ช่วยให้คุณสามารถเร่งการประมวลผลสำหรับคอลเลกชันรายการจำนวนมากที่กระบวนการหรือฟังก์ชันเดียวกันจำเป็นต้องรันกับแต่ละรายการ
ในบทช่วยสอนนี้ ฉันจะลงรายละเอียดเพื่ออธิบายประโยชน์ของการใช้คำสั่ง foreach ภายในสคริปต์ PowerShell ของคุณและให้ตัวอย่างที่เป็นประโยชน์แก่คุณซึ่งอาจมีประโยชน์
Foreach loop มีประโยชน์อย่างไร
หากไม่มี foreach loop การดำเนินการที่คล้ายกันมากกว่าหนึ่งครั้งกับหลายรายการจะน่าเบื่อและไม่มีประสิทธิภาพ ไม่เพียงแต่จะใช้เวลานานในการเขียนคำสั่งเดิมซ้ำแล้วซ้ำอีก แต่ยังเป็นการใช้โค้ดที่ไม่มีประสิทธิภาพอีกด้วย คำสั่ง 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 loop
Foreach loop มีโครงสร้างพื้นฐานเมื่อคุณเขียนมัน คำสั่ง foreach ตามด้วยวงเล็บเหลี่ยม และภายในวงเล็บคือตัวดำเนินการ in เมื่อดูที่โครงสร้างด้านล่าง $item จะกำหนดรายการเดียวในแต่ละรอบของการวนซ้ำ และ $itemcollection เป็นตัวแปรที่มีหลายรายการที่มีการวนซ้ำ
จากนั้นตามด้วยเครื่องหมายปีกกา (หรือวงเล็บปีกกา) และภายในเครื่องหมายปีกกาเหล่านี้คือคำสั่งที่คุณสามารถเรียกใช้กับแต่ละรายการในคอลเลกชันได้โดยใช้ตัวแปร $item
Foreach ($item in $itemcollection) {
"Do something" $item
}Foreach กับ Foreach-Object
แม้ว่าคำสั่ง foreach และ foreach-object cmdlet จะดูคล้ายกัน แต่ก็มีจุดประสงค์ที่แตกต่างกัน สิ่งที่น่าสับสนก็คือ foreach ยังเป็นนามแฝงของ foreach-object ดังนั้นแม้ว่าจุดประสงค์ของแต่ละคำสั่งจะเหมือนกัน แต่ก็มีการใช้ต่างกันเล็กน้อย
โดยพื้นฐานแล้ว เมื่อใช้คำสั่ง foreach คอลเลกชันของรายการของคุณจะถูกเก็บไว้ในหน่วยความจำล่วงหน้าในตัวแปร เช่นในตัวอย่างข้างต้น โดยก่อนที่จะใช้คำสั่ง foreach รายการของฉันถูกบันทึกไว้ในตัวแปร $itemcollection เนื่องจาก cmdlet foreach-object ได้รับการออกแบบมาเพื่อใช้ในไปป์ไลน์คำสั่งของคุณ และถึงแม้จะใช้เวลานานกว่าในการดำเนินการ แต่ก็มีพารามิเตอร์ที่ใช้งานได้มากกว่า
คุณสามารถดูความแตกต่างของความเร็วระหว่างคำสั่ง foreach และ foreach-object cmdlet ได้โดยใช้คำสั่ง Measure-Command
เริ่มต้นด้วยการวัดความเร็วของการรัน Foreach-Object ในไปป์ไลน์ของเรา
Measure-Command {
$report = [System.Collections.Generic.List[Object]]::new()
Get-Service | Foreach-Object {$report += $_ | Select Name, ServiceType, Status}
}อย่างที่คุณเห็นใช้เวลาทั้งหมด 72 มิลลิวินาทีในการรันคำสั่ง
ตอนนี้เราจะดูความเร็วเมื่อรันคำสั่งเดียวกันโดยใช้คำสั่ง foreach
Measure-Command {
$services = Get-Service
$report = [System.Collections.Generic.List[Object]]::new()
Foreach ($Service in $Services) {
$report += $service | Select Name, ServiceType, Status
}
}อย่างที่คุณเห็น แม้ว่าในสถานการณ์ของเรา เวลาจะต่างกันเพียงเล็กน้อย แต่คำสั่งก็เสร็จสิ้นเร็วกว่ามาก โดยใช้เวลาเพียง 47 มิลลิวินาที เมื่อเทียบกับการใช้ foreach-object
ตัวอย่างวง foreach
ด้านล่างนี้เป็นตัวอย่างที่แตกต่างกันสำหรับการใช้ foreach loops กับ PowerShell
เรียกใช้คำสั่งเดียวกันสำหรับหลายรายการ
ในรูปแบบที่ง่ายที่สุด เมื่อใช้ foreach loop คุณสามารถรันคำสั่งเดียวกันกับหลายรายการในคอลเลกชันได้ ในตัวอย่างด้านล่าง ฉันได้กำหนดชุดของชื่อหรือบริการที่พบในเครื่องคอมพิวเตอร์ด้วยตนเอง จากนั้น ฉันวนซ้ำแต่ละบริการและรันทั้งคำสั่ง stop-service และ start-service ซึ่งจะดำเนินการที่เกี่ยวข้องกับแต่ละบริการ
$Services = "Spooler","NetLogon","dbupdate","BITS"
Foreach ($service in $services) {
Stop-service $service
start-service $service
}แก้ไขการตั้งค่าสำหรับหลายรายการ
Foreach loop สามารถใช้สำหรับงานที่ซับซ้อนมากขึ้นได้ ตัวอย่างเช่น เนื่องจากฉันทำงานใน 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 Loop
เมื่อจัดการกับสคริปต์ขนาดใหญ่ที่มีการดำเนินการที่ซับซ้อนมากขึ้นภายในลูป 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 loop
สิ่งที่ฉันพบว่าตัวเองทำเกือบทุกครั้งที่ใช้ลูป foreach คือการสร้างอาร์เรย์บางรูปแบบ สามารถสร้างอาร์เรย์ได้อย่างรวดเร็วและมีประสิทธิภาพโดยใช้ลูป foreach ขั้นแรกให้เริ่มต้นด้วยการสร้างอาร์เรย์ว่างก่อนลูป foreach จากนั้นใช้ตัวดำเนินการ += เพื่อเพิ่มรายการใหม่ลงในอาร์เรย์ของคุณ
ด้านล่างนี้เป็นตัวอย่างง่ายๆ ที่เราวนซ้ำแต่ละรายการที่จัดเก็บไว้ใน $items จากนั้นวนซ้ำแต่ละรายการและเพิ่มคุณสมบัติของรายการลงในอาร์เรย์
$items = "1","2","3","4","5"
$array = @()
Foreach ($item in $items) {
$array += $item.property
}สร้างรายงานด้วย foreach loop
การสร้างรายงานด้วยออบเจ็กต์ PowerShell แบบกำหนดเองถือเป็นทักษะที่มีประโยชน์อย่างเหลือเชื่อ แม้ว่าคุณจะสามารถค้นหาข้อมูลทั้งหมดที่ต้องการได้บ่อยครั้งโดยใช้คำสั่ง GET ที่เกี่ยวข้อง แต่การสร้างรายงานที่มีการวนซ้ำ foreach จะทำให้คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับแต่ละรายการในคอลเลกชัน และสร้างรายงานโดยละเอียดตรงตามความต้องการของคุณได้ ข้อมูลที่จำเป็น
ในตัวอย่างด้านล่าง ฉันกำลังค้นหาผู้ใช้ทั้งหมดใน Active Directory จากนั้นฉันใช้ข้อมูลนั้นเพื่อวนซ้ำผู้ใช้แต่ละรายและค้นหากล่องจดหมาย Exchange ของพวกเขาด้วยคำสั่ง Get-Mailbox
$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 ที่จุดเริ่มต้นของการวนซ้ำของเรา

