ค้นหาเว็บไซต์

การเรียนรู้ PowerShell เปรียบเทียบอาร์เรย์อันทรงพลัง


การใช้ PowerShell กังฟูทำให้ Powershell เปรียบเทียบอาร์เรย์ของวัตถุทุกประเภทได้อย่างง่ายดาย มีสถานการณ์ต่างๆ มากมายที่คุณอาจพบว่าตัวเองเผชิญ ดังนั้นเรามาเจาะลึกและดูวิธีที่เราสามารถสร้าง PowerShell เพื่อเปรียบเทียบอาร์เรย์กันดีกว่า

ในการกำหนดวิธีที่ดีที่สุดในการเปรียบเทียบอาร์เรย์ คุณต้องทราบก่อนว่าองค์ประกอบประเภทใดในทั้งสองอาร์เรย์

  • อาร์เรย์ทั้งสองมีวัตถุประเภทเดียวกันทั้งหมดหรือไม่
  • อาร์เรย์ทั้งสองมีจำนวนองค์ประกอบเท่ากันหรือไม่
  • แต่ละอาร์เรย์มีวัตถุประเภทต่างๆ กันหรือไม่

คุณต้องรู้คำตอบของคำถามแต่ละข้อก่อนจึงจะสามารถเปรียบเทียบอาร์เรย์ได้อย่างแม่นยำ มาครอบคลุมแต่ละสถานการณ์กันดีกว่า

การเปรียบเทียบอาร์เรย์ของสตริง

วิธีที่ง่ายที่สุดวิธีหนึ่งในการเปรียบเทียบอาร์เรย์กับ PowerShell คือถ้าคุณมีสองอาร์เรย์ที่มีเพียงสตริงเท่านั้น เมื่อคุณพบว่าตัวเองอยู่ในตำแหน่งนี้ คุณจะมีวิธีต่างๆ สองสามวิธีในการเปรียบเทียบสตริงในอาร์เรย์

การใช้ตัวดำเนินการ -Contains หรือ -In

ตัวดำเนินการ -contains คือตัวดำเนินการ PowerShell ที่ให้คุณตรวจสอบเพื่อดูว่ามีออบเจ็กต์อยู่ในคอลเลกชันหรือไม่ ตัวดำเนินการ -contains ไม่เข้าใจคอลเลกชั่น แต่คุณสามารถสร้างโค้ดเพื่อให้เป็นไปตามการเสนอราคาของคุณได้

สมมติว่าคอลเลกชัน (อาร์เรย์) มีสี่สตริงเหมือนด้านล่าง

$array = @('blue','red','purple','pink')

ตัวดำเนินการ -contains ทำงานโดยตรวจสอบว่ามีสตริงเดี่ยวอยู่ในอาร์เรย์นั้นหรือไม่ ดังนี้:

$array -contains 'pink'

เมื่อคอลเลกชันทางด้านซ้าย มี สตริงนั้น PowerShell จะส่งกลับค่า True ถ้าไม่เช่นนั้นก็จะคืนค่าเป็นเท็จ

เราสามารถเปรียบเทียบอาร์เรย์โดยใช้ตัวดำเนินการ -contains โดยการอ่านแต่ละสตริงในอาร์เรย์และตรวจสอบว่าอาร์เรย์อื่น มี สตริงนั้นหรือไม่

สมมติว่าฉันต้องการเปรียบเทียบสองอาร์เรย์เพื่อดูว่ามีสตริงใดในอาร์เรย์แรกที่มีอยู่ในอาร์เรย์ที่สอง

$array = @('blue','red','purple','pink')
$array2 = @('brown','red','black','yellow')

$array | ForEach-Object {
    if ($array2 -contains $_) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

หรือคุณสามารถใช้ตัวดำเนินการ -in ซึ่งเหมือนกับตัวดำเนินการ -contains แต่ไวยากรณ์กลับตรงกันข้าม เมื่อใช้ตัวดำเนินการ -contains อาร์เรย์จะถูกกำหนดทางด้านซ้าย เมื่อใช้ตัวดำเนินการ -in อาร์เรย์จะถูกกำหนดไว้ทางด้านขวาดังภาพด้านล่าง:

$array | ForEach-Object {
    if ($_ -in $array2) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

การใช้ Where-Object

หรือคุณสามารถใช้ Where-Object cmdlet เพื่อส่งคืนสตริงทั้งหมดในอาร์เรย์หนึ่งในอีกอาร์เรย์เหมือนด้านล่าง

$array | Where-Object -FilterScript { $_ -in $array2 }

การใช้การเปรียบเทียบ-Object Cmdlet

คุณยังสามารถใช้ PowerShell เพื่อเปรียบเทียบอาร์เรย์โดยใช้ Compare-Object cmdlet cmdlet นี้รับวัตถุอ้างอิงและวัตถุที่แตกต่างและส่งกลับตัวบ่งชี้ด้านข้างเพื่อระบุว่าองค์ประกอบใดอยู่และไม่ได้อยู่ในอาร์เรย์ใดอาร์เรย์หนึ่ง

Compare-Object -ReferenceObject $array -DifferenceObject $array2

คุณสามารถดูด้านล่างได้ว่า Compare-Object cmdlet ช่วยให้คุณสามารถเปรียบเทียบอาร์เรย์ทั้งสองพร้อมกันได้ หากคุณสมบัติ SideIndicator เป็น => หมายความว่าคุณสมบัติ InputObject ที่ส่งคืนอยู่ในค่า DifferenceObject และไม่ได้อยู่ในค่า ค่า ReferenceObject และในทางกลับกันสำหรับ <= SideIndicator

ตามค่าเริ่มต้น Compare-Object จะส่งกลับค่าความแตกต่าง คุณยังสามารถส่งคืนสตริงทั้งหมดในแต่ละอาร์เรย์ที่อยู่ในทั้งสองอาร์เรย์ได้โดยใช้พารามิเตอร์ IncludeEqual

การเปรียบเทียบอาร์เรย์ของวัตถุที่ซับซ้อน

ง่ายพอใช่มั้ย? ตอนนี้เรามานำวัตถุต่างๆ มาผสมกัน สมมติว่าเรามีฟิลด์ในฐานข้อมูล HR นี้ของเรา และเราต้องการเติมข้อมูลนี้ลงในฟิลด์คำอธิบาย Active Directory ก่อนที่จะดำเนินการนี้ เราต้องมีตัวระบุร่วมกันก่อน ในสภาพแวดล้อมของฉัน มีหมายเลขพนักงานทั้งในฐานข้อมูล HR และในแอตทริบิวต์ Active Directory แบบกำหนดเอง เรามาลองจับคู่สิ่งนี้กัน

ขั้นแรก เรามาดูว่าจะเกิดอะไรขึ้นหากเราลองใช้แนวทางเดิม นี่คือไฟล์ CSV ที่เราใช้

นี่คือวิธีที่ฉันได้รับชุดข้อมูลทั้งสองของเรา

$ad_users = Get-AdUser -Filter {enabled -eq $true} -Properties employeeNumber | select employeenumber,samaccountname,description
$users_from_database = Import-Csv 'database_users.csv' | select employee number

จะเกิดอะไรขึ้นเมื่อเรารันอาร์เรย์ทั้งสองนี้ผ่านสถานการณ์เดียวกันกับสตริงของเรา ไม่มีอะไรจริงๆ. ทำไม

สาเหตุเป็นเพราะว่าปกติคุณไม่สามารถพูดว่า $object1 -eq $object2 ได้ เนื่องจากอ็อบเจ็กต์มีความซับซ้อนมากกว่าสตริงธรรมดา บูลีน หรือจำนวนเต็ม มีบางสถานการณ์ที่ไม่เป็นเช่นนั้น แต่ฉันพยายามทำให้เป็นนิสัยในการเปรียบเทียบคุณสมบัติของวัตถุ ไม่ใช่วัตถุทั้งหมด ดังนั้นในกรณีนี้ เราจะต้องดำเนินการดังนี้:

$ad_user[0].employeeNumber -eq $users_from_database[0].employeeNumber

วิธีแก้ปัญหาคืออะไร? ขณะนี้ฉันมีสองวิธีแก้ไข เมื่อจัดการกับวัตถุนับพัน มันไม่รวดเร็วแต่ใช้งานได้ ฉันต้องการทราบว่ามีใครมีข้อเสนอแนะอื่น ๆ หรือไม่

$ad_employee_numbers = $ad_users | % {$_.employeenumber}

## Create an array of strings of only the AD user's employee number
$users_from_database | Where-Object -FilterScript { $ad_employee_numbers -contains $_.employeeNumber }

นอกจากนี้เรายังสามารถใช้ Compare-Object ได้แม้ว่าจะช้ากว่าก็ตาม

$ad_employee_numbers = $ad_users | ForEach-Object {$_.employeenumber}

## Create an array of strings of only the AD user's employee number
$database_user_employee_numbers = $users_from_database | ForEach-Object {$_.employeenumber}

## Create an array of strings of only the database user's employee number
(Compare-Object $ad_employee_numbers $database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$_.SideIndicator -eq '=='}).InputObject

บทสรุป

มีหลายวิธีในการใช้ PowerShell เพื่อเปรียบเทียบอาร์เรย์ อาร์เรย์อาจมีความซับซ้อนและการทำความเข้าใจวัตถุภายในอาร์เรย์อย่างละเอียดจะช่วยให้คุณเปรียบเทียบได้อย่างมาก

บทความที่เกี่ยวข้อง