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

ไปป์ไลน์พร้อม: ฟังก์ชัน 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 และฟังก์ชันต่างๆ ทำให้พวกเขาแตกต่างจากภาษาสคริปต์อื่นๆ สำหรับมืออาชีพด้านไอทีที่ต้องการทำให้งานที่ซับซ้อนเป็นอัตโนมัติและเพิ่มประสิทธิภาพเวิร์กโฟลว์ พวกเขาเป็นเครื่องมือที่ขาดไม่ได้

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