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

ความคืบหน้าในการเขียน: วิธีการใช้งานที่ดีกว่า


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

อย่างไรก็ตาม Write-Verbose ค่อนข้างเรียบง่าย มันเป็นเพียงการแสดงข้อความเป็นระยะบนคอนโซล มันไม่มีอะไรมากไปกว่านั้น มีหลายครั้งที่คุณต้องการบางสิ่งที่เด่นชัดกว่านี้และวิธีที่ดีกว่าในการแจ้งให้ผู้ใช้สคริปต์ทราบว่าสคริปต์ของคุณอยู่ในกระบวนการไปไกลแค่ไหน สำหรับสิ่งนี้ ฉันใช้ cmdlet Write-Progress Write-Progress

Powershell cmdlet นี้เหมาะอย่างยิ่งสำหรับการแสดงแถบความคืบหน้าแบบกราฟิกในคอนโซล เป็นวิธีที่ใช้งานง่ายที่ไม่เพียงแต่แสดงข้อความสถานะให้กับผู้ใช้เท่านั้น แต่ยังมีแถบความคืบหน้าเพื่อระบุให้ผู้ใช้ทราบว่าสคริปต์ดำเนินการไปไกลแค่ไหน

วิธีใช้ Cmdlet การเขียนความคืบหน้า

การใช้ cmdlet นี้ค่อนข้างตรงไปตรงมา โดยพื้นฐานที่สุด คุณเพียงแค่ต้องระบุชื่อของแถบความคืบหน้าโดยใช้พารามิเตอร์ กิจกรรม ข้อความสถานะที่จะแสดงโดยใช้พารามิเตอร์ สถานะ และจำนวนที่ต้องกรอก แถบความคืบหน้าโดยใช้พารามิเตอร์ PercentComplete

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete 0

ผู้มาใหม่ของ PowerShell อาจเห็นสิ่งนี้และลองทำสิ่งนี้ทันที:

Write-Progress -Activity 'Title' -Status 'Doing something 2' -PercentComplete 25

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something 3' -PercentComplete 50

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something 4' -PercentComplete 75

## Some process here

เมื่อมองแวบแรก คุณอาจไม่สังเกตเห็นปัญหาที่นี่ แต่ให้ลองพิจารณาว่าจะรักษาปัญหานี้ไว้อย่างไร สังเกตพารามิเตอร์ PercentComplete สังเกตว่าฉันต้องกำหนดค่าคงที่ 0,25,50 และ 75 หรือไม่ เราไม่ต้องการเขียนโค้ดใดๆ แบบคงที่เว้นแต่จำเป็น นอกจากนี้ ฉันไม่ได้ปฏิบัติตามหลักการ DRY ที่นี่โดยการทำซ้ำสตริงเดียวกัน Write-Progress -Activity 'Title' -Status 'Doing some' สี่ครั้งที่แตกต่างกัน เราจำเป็นต้องปรับโครงสร้างโค้ดนี้ใหม่เพื่อให้มีวิธีแบบไดนามิกมากขึ้นในการระบุพารามิเตอร์ PercentComplete และลบการทำซ้ำโค้ดให้ได้มากที่สุด

ในการดำเนินการนี้ ก่อนอื่น ฉันจะต้องหาวิธีป้องกันไม่ให้ต้องฮาร์ดโค้ดค่า PercentComplete ในการเรียก Write-Progress แต่ละครั้ง เมื่อต้องการทำเช่นนี้ ฉันต้องค้นหาก่อนว่ามีการโทร Write-Progress กี่ครั้ง เมื่อฉันหาได้แล้ว ฉันก็สามารถคำนวณหาค่าเปอร์เซ็นต์ที่แท้จริงได้

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

$steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-Progress' }).Count

ตอนนี้ไม่สำคัญว่าฉันจะเพิ่มหรือลบการเรียกใช้ฟังก์ชัน Write-Progress $steps จะมีจำนวนการเรียก Write-Progress ทั้งหมดในฟังก์ชันเสมอ

ขณะนี้เราสามารถส่งค่าไปยัง PercentComplete แบบไดนามิกได้โดยการเพิ่มตัวแปร $stepcounter และสร้างค่าเปอร์เซ็นต์จากตัวแปรนั้น

$steps = ([System.Management.Automation.PsParser]::Tokenize($MyInvocation.MyCommand.Definition, [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-Progress' }).Count

$stepCounter = 0

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here

Write-Progress -Activity 'Title' -Status 'Doing something' -PercentComplete ((($stepCounter++) / $steps) * 100)

## Some process here

ยอดเยี่ยม! แต่นี่ยังดูน่าเกลียดอยู่เลย ดูความซ้ำซ้อนของโค้ดทั้งหมดสิ! ถึงเวลาสร้างฟังก์ชันตัวช่วยแล้ว ฉันจะสร้างอันหนึ่งตอนนี้

function Write-ProgressHelper {
    param(
        [int]$StepNumber,
        [string]$Message
    )
    
    Write-Progress -Activity 'Title' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
}

ตอนนี้เราสามารถเรียกฟังก์ชันตัวช่วยนี้ได้จากภายในฟังก์ชันเอง

$stepCounter = 0

Write-ProgressHelper -Message 'Doing something' -StepNumber ($stepCounter++)

## Some process here

Write-ProgressHelper -Message 'Doing something2' -StepNumber ($stepCounter++)

## Some process here

Write-ProgressHelper -Message 'Doing something3' -StepNumber ($stepCounter++)

## Some process here

แม้ว่าเราจะยังมีโค้ดที่ซ้ำซ้อนอยู่บ้าง แต่เราก็สามารถลบบางส่วนออกได้ เนื่องจากเราแทนที่การอ้างอิง Write-Progress เหล่านั้นเป็น Write-ProgressHelper เราจะต้องเปลี่ยนโค้ดเพื่อค้นหาขั้นตอนต่างๆ เนื่องจากโค้ดขั้นตอนของเรากำลังมองหาชื่ออ้างอิงฟังก์ชัน

$steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count

ในที่สุดก็ทิ้งเราไว้กับสคริปต์นี้

function Write-ProgressHelper {
	param (
	    [int]$StepNumber,
	    [string]$Message
	)

	Write-Progress -Activity 'Title' -Status $Message -PercentComplete (($StepNumber / $steps) * 100)
}

$script:steps = ([System.Management.Automation.PsParser]::Tokenize((gc "$PSScriptRoot\$($MyInvocation.MyCommand.Name)"), [ref]$null) | where { $_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper' }).Count

$stepCounter = 0

Write-ProgressHelper -Message 'Doing something' -StepNumber ($stepCounter++)
Start-Sleep -Seconds 5

## Some process here

Write-ProgressHelper -Message 'Doing something2' -StepNumber ($stepCounter++)

Start-Sleep -Seconds 5

## Some process here

Write-ProgressHelper -Message 'Doing something3' -StepNumber ($stepCounter++)

Start-Sleep -Seconds 5

## Some process here

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