ไปป์ไลน์พร้อม: ฟังก์ชัน PowerShell ขั้นสูง
style="letter-spacing: 0px; text-transform: unset; background-color: transparent;">การทำงานกับไปป์ไลน์ PowerShell นั้นมีประสิทธิภาพ คุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับไปป์ไลน์หรือไม่ ในโพสต์บนบล็อกนี้ Philip Lorenz เจาะลึกในหัวข้อนี้
การแนะนำ
ไปป์ไลน์เป็นแนวคิดหลักใน PowerShell ที่อนุญาตให้ส่งผ่านเอาต์พุตจากฟังก์ชันหนึ่งหรือ cmdlet เป็นอินพุตไปยังอีกฟังก์ชันหนึ่ง สิ่งนี้สร้างวิธีการประมวลผลข้อมูลที่ยืดหยุ่นและมีประสิทธิภาพโดยอนุญาตให้แต่ละงานที่มีการกำหนดไว้ชัดเจนสามารถเชื่อมโยงเข้าด้วยกันได้ หลักการ "ทีละครั้ง" ทำให้สามารถประมวลผลข้อมูลจำนวนมากในลักษณะที่ประหยัดทรัพยากรได้ ในบทความ "การทำงานอย่างมีประสิทธิภาพกับไปป์ไลน์ PowerShell: คำแนะนำสำหรับผู้ดูแลระบบ" ฉันได้แสดงให้คุณเห็นแล้วว่าคุณสามารถใช้ไปป์ไลน์เพื่อเชื่อมโยง cmdlets ที่มีอยู่ได้อย่างไร ในบล็อกโพสต์นี้ ฉันจะแสดงให้คุณเห็นถึงวิธีเตรียมฟังก์ชันไปป์ไลน์ของคุณเองให้พร้อม!
การรวมการสนับสนุนไปป์ไลน์เข้ากับฟังก์ชันของคุณไม่เพียงแต่เป็นแนวทางปฏิบัติที่ดี แต่ยังขยายฟังก์ชันการทำงานและการนำโค้ดกลับมาใช้ซ้ำอีกด้วย การให้การสนับสนุนไปป์ไลน์ในฟังก์ชันของคุณเองจำเป็นต้องมีความเข้าใจเกี่ยวกับกลไกไปป์ไลน์และการประยุกต์ใช้พารามิเตอร์และเทคนิคการประมวลผลที่เหมาะสม ตลอดบทความนี้ เราจะอธิบายแนวคิดเหล่านี้ตั้งแต่ฟังก์ชันพื้นฐานไปจนถึงฟังก์ชันขั้นสูง และแสดงให้เห็นว่าคุณสามารถเพิ่มประสิทธิภาพไปป์ไลน์ในสคริปต์ของคุณได้อย่างไร
ข้อมูลพื้นฐานเกี่ยวกับการสนับสนุนไปป์ไลน์
หากต้องการใช้ไปป์ไลน์ใน PowerShell อย่างมีประสิทธิภาพ สิ่งสำคัญคือต้องเข้าใจพื้นฐานบางประการ องค์ประกอบสำคัญสองประการที่นี่คือ คำหลักตัวกรอง และตัวแปรพิเศษ $_ มีบทบาทสำคัญในการสร้างฟังก์ชันง่ายๆ ที่ให้การสนับสนุนไปป์ไลน์
คำหลักตัวกรอง ใน PowerShell ทำให้สามารถสร้างประเภทของฟังก์ชันที่ออกแบบมาเพื่อประมวลผลอินพุตไปป์ไลน์โดยเฉพาะ ตัวกรองจะรับอินพุตจากไปป์ไลน์ ประมวลผล และส่งคืนบางสิ่งไปยังไปป์ไลน์ ตัวแปร $_ แสดงถึงอ็อบเจ็กต์ปัจจุบันในไปป์ไลน์ที่กำลังประมวลผล ต่อไปนี้เป็นฟังก์ชันง่ายๆ ที่แสดงวิธีใช้คำหลักตัวกรองและตัวแปร $_:
Filter Convert-ToUpperCase {
Write-Output "Input in uppercase: $($_.ToUpper())"
}
ในตัวอย่างนี้ เราได้สร้างตัวกรองชื่อ Convert-ToUpperCase ตัวกรองนี้รับรายการข้อความจากไปป์ไลน์ และสำหรับแต่ละรายการจะมีการเรียกเมธอด ToUpper เพื่อแปลงข้อความเป็นตัวพิมพ์ใหญ่ นอกจากนี้ยังมีเอาต์พุตโดยตรงไปยังคอนโซล หากคุณใช้ตัวกรองนี้ในไปป์ไลน์ รายการข้อความแต่ละรายการจะได้รับการประมวลผลแยกกันและส่งต่อไปยังเอาต์พุตด้วยตัวพิมพ์ใหญ่:
"hello", "world" | Convert-ToUpperCase
ผลลัพธ์จะเป็น:
Input in uppercase: HELLO
Input in uppercase: WORLD
การใช้ตัวกรองและ $_ เป็นวิธีที่ง่ายและมีประสิทธิภาพในการผสานรวมการสนับสนุนไปป์ไลน์เข้ากับฟังก์ชันของคุณ โดยให้วิธีการที่ชัดเจนและเข้าใจง่ายในการรับออบเจ็กต์จากไปป์ไลน์ ประมวลผลและส่งต่อ ซึ่งเป็นพื้นฐานสำหรับฟังก์ชันและการดำเนินการไปป์ไลน์ที่ซับซ้อนมากขึ้น
ในส่วนถัดไป เราจะดูที่ พารามิเตอร์ที่มีชื่อ และสร้างฟังก์ชันขั้นสูงที่นอกเหนือไปจากขอบเขตของฟังก์ชันแบบง่าย และให้วิธีอื่นๆ ในการโต้ตอบกับไปป์ไลน์
ฟังก์ชันขั้นสูงที่มี พารามิเตอร์ที่มีชื่อ
แม้ว่าฟังก์ชันและตัวกรองแบบธรรมดาจะเพียงพอสำหรับงานหลายๆ อย่าง แต่ฟังก์ชันขั้นสูงใน PowerShell ช่วยให้สามารถควบคุมและมีความยืดหยุ่นได้มากขึ้น โดยเฉพาะอย่างยิ่งเมื่อต้องทำงานกับไปป์ไลน์ สิ่งสำคัญอย่างหนึ่งของฟังก์ชันขั้นสูงนี้คือ พารามิเตอร์ที่มีชื่อ
พารามิเตอร์ที่มีชื่อ
พารามิเตอร์ที่มีชื่อช่วยให้เราสามารถควบคุมการป้อนข้อมูลในลักษณะที่มีโครงสร้างและเข้าใจได้ ไม่เพียงแต่คุณสามารถระบุประเภทสำหรับพารามิเตอร์อินพุตได้ แต่คุณยังสามารถกำหนดค่าเริ่มต้นและเพิ่มการตรวจสอบความถูกต้องได้อีกด้วย
นี่คือตัวอย่างฟังก์ชันขั้นสูงที่มี พารามิเตอร์ที่มีชื่อ:
function Get-ModifiedFiles {
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[string]$Path,
[datetime]$Since
)
process {
$files = Get-ChildItem -Path
$Path -Recurse |
Where-Object { $_.LastWriteTime -gt $Since }
$files
}
}
ในฟังก์ชัน Get-ModifiedFiles นี้ เราได้กำหนด พารามิเตอร์ที่มีชื่อ สองรายการ: $Path และ $Since พารามิเตอร์ $Path เป็นพารามิเตอร์บังคับและยอมรับอินพุตจากไปป์ไลน์ ในขณะที่ $Since เป็นตัวเลือก ในบล็อกกระบวนการ เราใช้ Get-ChildItem เพื่อรับไฟล์ทั้งหมดในเส้นทางที่ระบุ และ Where-Object เพื่อกรองไฟล์ที่ได้รับการแก้ไขหลังจากวันที่ที่ระบุ
นี่คือการโทรที่เป็นแบบอย่าง:
"./" | Get-ModifiedFiles -Since (Get-Date).AddDays(-7)
เอาท์พุต :
ในการเรียกนี้ ไดเร็กทอรีปัจจุบันจะถูกส่งผ่านไปยังฟังก์ชัน Get-ModifiedFiles ในรูปแบบสตริงแบบธรรมดา และไฟล์ทั้งหมดที่ได้รับการแก้ไขในช่วงเจ็ดวันที่ผ่านมาจะถูกส่งคืน
พารามิเตอร์ที่มีชื่อ มอบวิธีการที่ชัดเจนและชัดเจนในการควบคุมอินพุตของฟังก์ชัน และช่วยให้สามารถควบคุมการประมวลผลข้อมูลภายในฟังก์ชันได้ละเอียดยิ่งขึ้น
ในบทต่อไป เราจะดูที่การจัดโครงสร้างฟังก์ชันด้วยบล็อก Begin, Process, End และ Clean
การจัดโครงสร้างฟังก์ชันด้วยบล็อก Begin, Process, End และ Clean
การจัดโครงสร้างฟังก์ชันด้วยบล็อก Begin, Process, End และบล็อก Clean ที่เพิ่งเปิดตัวใน PowerShell 7.3 มอบวิธีที่มีประสิทธิภาพในการประมวลผลข้อมูลไปป์ไลน์และการล้างข้อมูลทรัพยากร บล็อกเหล่านี้ทำให้สามารถแบ่งโค้ดออกเป็นส่วนเชิงตรรกะที่ถูกเรียกในเวลาที่ต่างกันระหว่างการทำงานของฟังก์ชันได้
- บล็อก Begin จะถูกดำเนินการหนึ่งครั้งที่จุดเริ่มต้นของฟังก์ชัน และเหมาะสำหรับการดำเนินการเริ่มต้น
- บล็อก กระบวนการ ถูกดำเนินการสำหรับแต่ละวัตถุที่ถูกส่งผ่านไปป์ไลน์และเป็นตำแหน่งหลักสำหรับการประมวลผลข้อมูล
- บล็อก End จะถูกดำเนินการหนึ่งครั้งหลังจากประมวลผลออบเจ็กต์ไปป์ไลน์ทั้งหมดแล้ว และเหมาะสำหรับการดำเนินการขั้นสุดท้าย
บล็อก ล้าง ซึ่งเปิดตัวใน PowerShell 7.3 มอบวิธีการล้างทรัพยากรที่ครอบคลุมบล็อก เริ่มต้น ดำเนินการ และ สิ้นสุด ความหมายจะคล้ายกับบล็อก Finally และครอบคลุมบล็อกที่มีชื่ออื่นๆ ทั้งหมดของฟังก์ชัน การล้างทรัพยากรถูกบังคับใช้ในสถานการณ์ต่างๆ เช่น เมื่อการดำเนินการไปป์ไลน์เสร็จสมบูรณ์ตามปกติ ถูกขัดจังหวะด้วยข้อผิดพลาดในการยกเลิก หรือหยุดโดย Select-Object -First หรือสิ้นสุดโดย CTRL+C หรือ StopProcessing().
นี่คือตัวอย่างที่สาธิตการใช้บล็อคทั้งหมด:
function Get-Size {
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[string]$Path
)
begin {
# Initializing variables
$totalSize = 0
$tempDirectory = "./tmp"
# Initialization: Creating temporary directory
if (-not (Test-Path $tempDirectory)) {
New-Item -Path $tempDirectory -ItemType Directory | Out-Null
}
}
process {
# Checking if the path exists and is a file
if (Test-Path $Path -PathType Leaf) {
$fileInfo = Get-Item $Path $fileSize = $fileInfo.Length
$totalSize += $fileSize
# Writing file information to a temporary file
$outputPath = Join-Path $tempDirectory ($fileInfo.Name + ".txt")
$fileInfo | Out-File $outputPath
}
}
end {
# Outputting the total size of all processed files
Write-Output "Total size of all processed files: $($totalSize / 1MB) MB"
}
clean {
# Deleting temporary directory
Remove-Item $tempDirectory -Recurse -Force
}
}
- เริ่มต้นสร้างไดเร็กทอรีชั่วคราวที่ใช้ระหว่างการประมวลผล
- บล็อก กระบวนการ ตรวจสอบว่าเส้นทางที่ส่งเป็นไฟล์หรือไม่ รวบรวมข้อมูลเกี่ยวกับไฟล์ อัปเดตขนาดทั้งหมด และจัดเก็บข้อมูลไฟล์ไว้ในไฟล์ชั่วคราว
- บล็อก Der End จะแสดงขนาดรวมของไฟล์ที่ประมวลผลทั้งหมด
- บล็อก Der Clean จะลบไดเร็กทอรีชั่วคราวหลังจากการประมวลผลเสร็จสิ้นเพื่อให้แน่ใจว่าไม่มีข้อมูลที่ไม่ต้องการหลงเหลืออยู่
ดำเนินการรหัสต่อไปนี้:
$files = @()
$files += "/Users/philip/Code/blog-post-code-examples/blog.docx"
$files += "/Users/philip/Code/blog-post-code-examples/image.dmg"
$files | Get-Size
และรับผลลัพธ์ต่อไปนี้:
Total size of all processed files: 615.562695503235 MB
ด้วยการใช้บล็อก เริ่มต้น ประมวลผล สิ้นสุด และ ล้าง ฟังก์ชันนี้จึงมีโครงสร้างและช่วยให้สามารถประมวลผลและล้างข้อมูลได้อย่างมีประสิทธิภาพ
การใช้งาน ByPropertyName ในฟังก์ชันของตัวเอง
จนถึงตอนนี้ เราได้จัดการกับการส่งค่า ByValue ไปยังฟังก์ชันแล้ว อย่างไรก็ตาม PowerShell ยังเสนอตัวเลือกในการส่งค่า ByPropertyName อีกด้วย ช่วยให้สามารถโต้ตอบกับฟังก์ชันต่างๆ ได้อย่างยืดหยุ่นและเป็นธรรมชาติมากขึ้น
ByPropertyName กับ ByValue
- ByValue: ที่นี่ ค่าของอาร์กิวเมนต์จะถูกส่งโดยตรงไปยังพารามิเตอร์ที่เกี่ยวข้องของฟังก์ชัน สิ่งนี้ตรงไปตรงมา แต่อาจทำให้เกิดความสับสนในสถานการณ์ที่ความสัมพันธ์ของพารามิเตอร์ไม่ชัดเจน
- ByPropertyName: ด้วยวิธีนี้ ค่าของอาร์กิวเมนต์จะถูกส่งผ่านตามชื่อของพารามิเตอร์ สิ่งนี้มีประโยชน์อย่างยิ่งหากฟังก์ชันมีพารามิเตอร์หลายตัว หรือหากฟังก์ชันถูกใช้ในไปป์ไลน์ที่เอาต์พุตของ cmdlet ก่อนหน้าถูกใช้เป็นอินพุตสำหรับ cmdlet ถัดไป
นี่คือตัวอย่างที่สาธิตการใช้งาน ByPropertyName:
function Get-FileDetail {
param (
[Parameter(ValueFromPipelineByPropertyName=$true)]
[string]$FullName
)
process {
$fileInfo = Get-Item $FullName
$fileDetail = @{
Name = $fileInfo.Name
Size = $fileInfo.Length
LastModified = $fileInfo.LastWriteTime
}
$fileDetail
}
}
Get-ChildItem -Path "./" | Get-FileDetail
สิ่งต่อไปนี้จะแสดงในคอนโซล:
ในฟังก์ชัน Get-FileDetail เราได้กำหนดพารามิเตอร์ $FullName ด้วยแอตทริบิวต์ ValueFromPipelineByPropertyName=$true ซึ่งช่วยให้ฟังก์ชันยอมรับค่าจากไปป์ไลน์ที่กำหนดตามชื่อของพารามิเตอร์ $FullName ในการเรียกตัวอย่าง เอาต์พุตของ Get-ChildItem จะถูกส่งต่อไปยัง Get-FileDetail โดยที่คุณสมบัติ FullName ของวัตถุเอาต์พุตของ Get-ChildItem ถูกแมปกับพารามิเตอร์ $FileName ของ Get-FileDetail
การใช้ ByPropertyName ช่วยให้สามารถใช้ฟังก์ชันต่างๆ ได้อย่างเป็นธรรมชาติและยืดหยุ่นมากขึ้นในไปป์ไลน์ และการกำหนดค่าอินพุตให้กับฟังก์ชันต่างๆ จะมีความโปร่งใสมากขึ้น
ในย่อหน้าถัดไป เราจะดูตัวแปรอัตโนมัติ $Input ซึ่งให้วิธีอื่นในการประมวลผลอินพุตไปป์ไลน์ โดยเฉพาะอย่างยิ่งหากอินพุตนั้นถือเป็นบล็อกแทนที่จะเป็นแต่ละรายการ
$Input ตัวแปรอัตโนมัติ
แม้ว่านักพัฒนา PowerShell จำนวนมากจะคุ้นเคยกับตัวแปร $_ ไปป์ไลน์ แต่ $Input ยังเป็นที่รู้จักน้อย แต่มีฟังก์ชันการทำงานที่มีคุณค่าในบางสถานการณ์
ตัวแปร $Input อนุญาตให้อินพุตไปป์ไลน์ทั้งหมดถือเป็นตัวแจงนับ ซึ่งหมายความว่าแทนที่จะประมวลผลแต่ละองค์ประกอบของไปป์ไลน์ คุณสามารถเข้าถึงอินพุตทั้งหมดโดยรวมได้ สิ่งนี้มีประโยชน์ในสถานการณ์ที่คุณต้องการให้อินพุตเป็นบล็อก เช่น เมื่อเรียงลำดับหรือจัดกลุ่มข้อมูล
สิ่งสำคัญคือต้องทราบว่า $Input เป็นตัวแจงนับและไม่สามารถใช้เป็นอาร์เรย์โดยตรงได้ หากต้องการใช้ $Input เป็นอาร์เรย์จริง คุณสามารถรวมไว้ใน @() ได้
นี่เป็นตัวอย่างง่ายๆ:
function Sort-InputData {
process {
$dataArray = @($Input)
$sortedData = $dataArray | Sort-Object
$sortedData
}
}
# Beispielaufruf
1, 5, 3, 4, 2 | Sort-InputData
ในฟังก์ชัน Soft-InputData นี้ ก่อนอื่นเราจะรวบรวมอินพุตไปป์ไลน์ทั้งหมดในอาร์เรย์ $dataArray จากนั้นจึงจัดเรียงข้อมูลนี้ ผลลัพธ์ที่ได้คือรายการตัวเลขที่เรียงลำดับ
เมื่อใดจึงจะใช้ $Input?
การใช้ $Input มีประโยชน์อย่างยิ่งเมื่อคุณต้องการดำเนินการหลายอย่างกับอินพุตไปป์ไลน์ทั้งหมดโดยไม่ต้องประมวลผลแต่ละค่าทีละค่า อย่างไรก็ตาม สิ่งสำคัญคือต้องเข้าใจความแตกต่างระหว่าง $Input และ $_ และเลือกตัวแปรที่เหมาะสมสำหรับสถานการณ์
บทสรุป
ไปป์ไลน์ PowerShell เป็นหนึ่งในคุณสมบัติที่สำคัญที่สุดของ PowerShell อย่างไม่ต้องสงสัย ความสามารถในการถ่ายโอนข้อมูลอย่างมีประสิทธิภาพและราบรื่นระหว่าง cmdlets และฟังก์ชันต่างๆ ทำให้พวกเขาแตกต่างจากภาษาสคริปต์อื่นๆ สำหรับมืออาชีพด้านไอทีที่ต้องการทำให้งานที่ซับซ้อนเป็นอัตโนมัติและเพิ่มประสิทธิภาพเวิร์กโฟลว์ พวกเขาเป็นเครื่องมือที่ขาดไม่ได้


