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

การจับชื่อด้วย PowerShell และนิพจน์ทั่วไป


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

เริ่มต้นด้วยสตริงเช่นนี้

$t = "2019-06-21 17:12:31Z : 172.16.1.123 [ Begin process data ]"

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

เริ่มต้นด้วยรูปแบบ

เพื่อให้สิ่งนี้ได้ผลและเพื่อให้คุณใช้นิพจน์ทั่วไปได้ คุณต้องรู้ว่าข้อมูลของคุณจะมีลักษณะอย่างไร และจะต้องสอดคล้องกันและสามารถคาดเดาได้ ในตัวอย่างนี้ ฉันมีสตริงวันที่เวลา ที่อยู่ IPv4 และข้อความอยู่ในวงเล็บ ขั้นตอนแรกคือการสร้างรูปแบบนิพจน์ทั่วไปที่ตรงกับองค์ประกอบต่างๆ เหล่านี้ เริ่มต้นด้วยวันที่และเวลา

$t -match "\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}Z"

รูปแบบบอกว่าให้หาสิ่งที่ขึ้นต้นด้วยตัวเลข 4 หลักพอดี \d หมายถึงตัวเลข และ {4} หมายถึงตัวเลข 4 หลักพอดี จากนั้นจะมีขีดกลางตามด้วยตัวเลข 2 หลัก (\d{2}) อีกขีดกลางและตัวเลข 2 หลัก นั่นควรจะให้วันที่แก่ฉัน แต่มีอีกนิดหน่อย ฉันต้องจับพื้นที่ (\s) จากนั้นฉันก็มีรูปแบบเพื่อให้ตรงกับเวลาที่คุณควรจำได้ในตอนนี้ จุดสิ้นสุดคือตัวอักษร Z

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

ต่อไปฉันต้องจับคู่ที่อยู่ IP

$t -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

รูปแบบบอกว่าเริ่มต้นด้วยอย่างน้อย 1 หลักและไม่เกิน 3. (\d{1,3}) ตามด้วยจุดตามตัวอักษร (\.) จุดเป็นอักขระนิพจน์ทั่วไปพิเศษที่มีความหมายอะไรก็ได้\คืออักขระหลีกซึ่งบอกให้ PowerShell ค้นหาจุดตามตัวอักษร รูปแบบนี้จะเกิดขึ้นซ้ำกับออคเต็ตที่เหลือ

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

สุดท้ายคือข้อความระหว่างวงเล็บเหลี่ยม

$t -match "\[.*\]"

วงเล็บปีกกาเป็นอักขระนิพจน์ทั่วไปพิเศษ ดังนั้นฉันจึงต้องหลีกเลี่ยง ฉันขอให้จับคู่อักขระใดๆ (.) หลายตัว (*)

กำหนดชื่อ

เมื่อคุณมีรูปแบบที่ตรงกันแล้ว คุณสามารถกำหนดรูปแบบเหล่านั้นด้วยชื่อได้ เค้าโครงทั่วไปมีลักษณะดังนี้:

(?<capture-name>Your-Pattern)

วงเล็บเป็นสิ่งสำคัญ รูปแบบวันที่และเวลาของฉันสามารถกำหนดเป็นการจับภาพที่มีชื่อได้:

(?<date>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}Z)

นี่คือรูปแบบที่อธิบายข้อความทั้งบรรทัดตั้งแต่ต้นจนจบ

[regex]$rx = '(?<date>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}Z)\s:\s(?<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s\[\s(?<status>.*)\]'

ฉันได้ปรับแต่งรูปแบบสุดท้ายเพื่อไม่ให้มีวงเล็บเหลี่ยม มีเทคนิคนิพจน์ทั่วไปขั้นสูงอื่นๆ ที่ฉันสามารถใช้ได้ แต่ฉันทำให้มันเรียบง่าย สิ่งสำคัญที่ควรทราบคือฉันกำลังกำหนด $rx ให้เป็นวัตถุชนิดพิเศษ ออบเจ็กต์ regex นี้ช่วยให้ฉันทำได้มากกว่าการใช้ตัวดำเนินการ -match ในสถานการณ์นี้ ฉันสามารถใช้มันเพื่อค้นหาการแข่งขันได้

ดีจัง. แต่ชื่อต่างๆ เข้ามามีบทบาทได้อย่างไร?

การใช้การจับภาพที่มีชื่อใน PowerShell

ในการแข่งขัน คุณจะเห็นพร็อพเพอร์ตี้ Groups นี่คือที่ที่คุณสามารถค้นหาการจับภาพที่มีชื่อได้

การใช้ PowerShell ทำให้ง่ายต่อการรับเฉพาะการจับภาพที่มีชื่อโดยการข้ามกลุ่มแรกที่ตรงกัน

นั่นเกือบจะดูเหมือนวัตถุ! การสร้างวัตถุจริงนั้นใช้เวลาไม่นานนัก

$m.groups | Select-Object -Skip 1 | foreach-object -begin { $h = @{}  } -process {
    $h.Add($_.name,$_.value.trim())
} -end {
    [pscustomobject]$h
}

แม้ว่ามันจะดีกว่าถ้าวันที่เป็นวัตถุ datetime แทนที่จะเป็นสตริง นี่เป็นอีกทางเลือกหนึ่งโดยสมมติว่าคุณรู้ลำดับการจับชื่อของคุณ

$o = [pscustomobject]@{
    Date = $m.groups[1].value -as [datetime]
    IPAddress = $m.groups[2].value -as [ipaddress]
    Status = $m.groups[3].value 
}

อย่างที่คุณเห็นนี่คือวัตถุ

ด้วยโค้ดนี้ ฉันสามารถเขียนสคริปต์เพื่อประมวลผลแต่ละบรรทัดของไฟล์บันทึก และสร้างออบเจ็กต์แบบกำหนดเองได้ ทำให้กรอง จัดเรียง หรือทำสิ่งอื่นๆ ที่เกี่ยวข้องกับข้อมูลได้ง่ายขึ้นมาก

แปลงจากข้อความ

หรือวิธีที่ง่ายกว่านั้นล่ะ? ตอนนี้คุณรู้วิธีสร้างรูปแบบนิพจน์ทั่วไปโดยใช้การจับภาพที่มีชื่อแล้ว คุณสามารถใช้คำสั่ง ConvertFrom-Text ในโมดูล PSScriptTools ของฉัน ซึ่งคุณสามารถติดตั้งได้จาก PowerShell Gallery ด้วยคำสั่งนี้ คุณสามารถสร้างโค้ดเพื่อเปลี่ยนเอาต์พุตข้อความใดๆ ให้เป็นออบเจ็กต์ PowerShell ได้

$c = "(?<Protocol>\w{3})\s+(?<LocalIP>(\d{1,3}\.){3}\d{1,3}):(?<LocalPort>\d+)\s+(?<ForeignIP>.*):(?<ForeignPort>\d+)\s+(?<State>\w+)?"
netstat -an | select -skip 4 | convertfrom-text $c | where-object {$_.LocalIP -ne '0.0.0.0'} | format-table -autosize

เมื่อคุณมีทักษะการแสดงออกปกติขั้นพื้นฐานแล้ว คุณจะพบว่าตัวเองใช้ทักษะนั้นบ่อยครั้ง และเช่นเดียวกับภาษาใหม่อื่นๆ ยิ่งคุณใช้มันมากเท่าไร คุณก็จะยิ่งคล่องแคล่วมากขึ้นเท่านั้น

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