สัปดาห์การเขียนบล็อก PowerShell: สนับสนุน WhatIf และยืนยัน
เราหวังว่าคุณจะเพลิดเพลินกับการทดลองนี้ในการเขียนบล็อกของชุมชน ในการสนับสนุนของวันนี้ ฉันต้องการสาธิตวิธีที่คุณสามารถเพิ่มการสนับสนุนสำหรับ WhatIf และยืนยันให้กับฟังก์ชัน PowerShell ขั้นสูงของคุณ จริงๆ แล้วค่อนข้างง่าย โดยเฉพาะอย่างยิ่งหากฟังก์ชันของคุณเรียกใช้คำสั่ง PowerShell อื่นๆ ที่รองรับ -Whatif และ -Confirm อยู่แล้ว แนวทางปฏิบัติที่ดีที่สุดที่แนะนำคือ หากฟังก์ชันของคุณจะทำอะไรก็ตามที่เปลี่ยนแปลงบางสิ่ง ก็ควรสนับสนุนพารามิเตอร์เหล่านี้ นี่คือวิธีการ
ในฟังก์ชันของคุณ คุณจะต้องใช้แอตทริบิวต์ cmdletbinding และระบุ SupportsShouldProcess
[cmdletbinding(SupportsShouldProcess)]เริ่มต้นด้วย PowerShell 3.0 นี่คือทั้งหมดที่คุณต้องการ แต่คุณจะเห็นสคริปต์ตั้งค่าอย่างชัดเจนเป็น $True
[cmdletbinding(SupportsShouldProcess=$True)]ไม่เป็นไร แม้ว่าโดยส่วนตัวแล้วฉันจะพบว่ามันซ้ำซ้อน ถ้า SupportsShouldProcess อยู่ในรายการ ตามค่าเริ่มต้นจะเป็น True ไม่จำเป็นต้องตั้งค่านี้เป็น $False อย่างชัดเจน เพียงแค่ละเว้นมัน เมื่อคุณเพิ่มแอตทริบิวต์นี้ คุณจะได้รับพารามิเตอร์ -WhatIf และ -Confirm โดยอัตโนมัติ ส่วนที่ดีที่สุดคือหากฟังก์ชันของคุณเรียก PowerShell cmdlets ที่รองรับ -WhatIf อยู่แล้ว ฟังก์ชันเหล่านั้นจะสืบทอดการตั้งค่านี้โดยอัตโนมัติ นี่คือฟังก์ชันตัวอย่าง
#requires -version 4.0
Function Remove-TempFile {
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Position=0)]
[ValidateScript({Test-Path $_})]
[string]$Path = $env:temp
)
#get last bootup time
$LastBoot = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUptime
Write-Verbose "Finding all files in $path modified before $lastboot"
(Get-Childitem -path $path -File).Where({$_.lastWriteTime -le $lastboot}) | Remove-Item
} #end function
ฟังก์ชันนี้จะลบไฟล์ทั้งหมดออกจากโฟลเดอร์ %TEMP% ที่มีเวลาที่แก้ไขล่าสุดซึ่งเก่ากว่าเวลาบูตเครื่องครั้งล่าสุด ดังที่คุณเห็นในความช่วยเหลือ PowerShell ได้เพิ่มพารามิเตอร์ที่จำเป็น
เมื่อฉันรันฟังก์ชันด้วย -จะเกิดอะไรขึ้นถ้ามันถูกส่งต่อไปยัง Remove-Item
มันง่ายมากจริงๆ ฉันยังได้รับการสนับสนุนโดยอัตโนมัติสำหรับ -ยืนยัน
สิ่งต่างๆ จะยุ่งยากขึ้นเล็กน้อยเมื่อคุณต้องการรองรับ WhatIf สำหรับฟังก์ชันที่คำสั่งของคุณไม่รู้จัก SupportsShouldProcess โดยกำเนิด สิ่งนี้จะเกิดขึ้นจริงกับวิธี .NET static ใดๆ หรือแม้แต่เครื่องมือบรรทัดคำสั่งที่คุณอาจใช้งานอยู่ เพื่อเป็นตัวอย่างบางส่วน หากต้องการเพิ่มการสนับสนุนของคุณเอง คุณต้องเรียกใช้วัตถุ $PSCmdlet ในตัวและเมธอด shouldProcess() นี่เป็นตัวอย่างง่ายๆ
Function Set-Folder {
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".")
Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
if ($PSCmdlet.ShouldProcess($Path)) {
#do the action
$Path.ToUpper()
}
} #Process
} #end function
ฟังก์ชั่นนี้สมมุติฐานว่าจะดำเนินการบางอย่างกับโฟลเดอร์ และฉันแค่แสดงชื่อโฟลเดอร์เป็นตัวพิมพ์ใหญ่ ส่วนที่สำคัญคือคำสั่ง If นี่คือขั้นต่ำเปล่าที่คุณต้องการ หากคุณระบุ -WhatIf คุณจะได้รับแจ้ง
การดำเนินการจะเป็นชื่อของสคริปต์หรือฟังก์ชันของคุณ เป้าหมายคือค่าพารามิเตอร์ shouldProcess ซึ่งในตัวอย่างของฉันคือเส้นทาง แต่คุณสามารถให้ข้อมูลที่เจาะจงมากขึ้นได้โดยการระบุพารามิเตอร์ shouldProcess สำหรับเป้าหมายและการดำเนินการ นี่คือฟังก์ชันที่แก้ไขแล้ว
Function Set-Folder2 {
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".")
Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
if ($PSCmdlet.ShouldProcess($Path,"Updating")) {
#do the action
$Path.ToUpper()
}
} #Process
} #end function
คุณต้องมีรหัสสำหรับ shouldProcess มิฉะนั้นแม้ว่าคุณจะตั้งค่าแอตทริบิวต์ cmdletbinding แล้ว PowerShell จะไม่ทราบว่าคำสั่งใดต้องการ WhatIf คุณยังสามารถมีคำสั่ง shouldProcess ได้มากเท่าที่คุณต้องการ
เมื่อพูดถึงการยืนยัน สิ่งต่างๆ จะยุ่งยากขึ้นเล็กน้อยและอาจขึ้นอยู่กับสิ่งที่คุณต้องการจริงๆ ดังที่คุณเห็นข้างต้น cmdlet ใด ๆ ที่รองรับ -Confirm ควรสืบทอดการตั้งค่าโดยอัตโนมัติ วิธีนี้ใช้ได้เนื่องจากมีแอตทริบิวต์ cmdletbinding อื่นที่เรียกว่า ConfirmImpact ซึ่งมีค่าเริ่มต้นเป็น Medium ตัวเลือกอื่นๆ ได้แก่ ต่ำและสูง ฟังก์ชันแรกของฉันก็เขียนได้แบบนี้:
[cmdletbinding(SupportsShouldProcess,ConfirmImpact="medium ")]การยืนยันเกิดขึ้นโดยการเปรียบเทียบค่าของ ConfirmImpact กับตัวแปร $ConfirmPreference ในตัว ซึ่งมีค่าเริ่มต้นเป็น High หากค่าของ $ConfirmPreference เท่ากับหรือมากกว่า ConfirmImpact PowerShell จะพร้อมท์ให้ยืนยัน มาทดสอบสิ่งนี้กัน
Function Set-Folder6 {
[cmdletbinding(SupportsShouldProcess,ConfirmImpact="High")]
Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path="."
)
Begin {
Write-Verbose "Starting $($MyInvocation.Mycommand)"
} #begin
Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
Write-Verbose "Processing $path"
if ($PSCmdlet.ShouldProcess($Path,"Updating")) {
#do the action
$Path.ToUpper()
} #ShouldProcess
} #Process
End {
Write-Verbose "Ending $($MyInvocation.Mycommand)"
} #end
} #end function
โปรดสังเกตว่าฉันใช้สำหรับ WhatIf ด้วย ในฟังก์ชันนี้ ConfirmImpact ถูกตั้งค่าเป็นสูง ซึ่งหมายความว่า PowerShell จะพร้อมท์เสมอ
หากฉันแก้ไขฟังก์ชันและเปลี่ยนเป็น ConfirmImpact เป็น Medium หรือ Low PowerShell จะยืนยันเฉพาะเมื่อฉันถามเท่านั้น
คุณไม่จำเป็นต้องระบุอะไรสำหรับ cmdletbinding หากคุณรู้ว่าคุณต้องการการยืนยันอยู่เสมอ คุณสามารถดำเนินการดังนี้:
Function Set-Folder4 {
[cmdletbinding()]
Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".",
[switch]$Force
)
Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
Write-Verbose "Processing $path"
if ($Force -OR $PSCmdlet.ShouldContinue("Do you want to continue modifying folder?",$path)) {
#do the action
$Path.ToUpper()
}
} #Process
} #end function
สังเกตการใช้เมธอด shouldContinue เมื่อฉันเรียกใช้ฟังก์ชันนี้ PowerShell จะแจ้งให้ยืนยันเสมอ
ฉันยังเพิ่มพารามิเตอร์สวิตช์ที่เรียกว่า Force เพื่อว่าหากมีการระบุ ผู้ใช้จะไม่ได้รับแจ้งให้ยืนยัน
ข้อเสียของแนวทางนี้คือความช่วยเหลือไม่แสดงอะไรเลย
บางทีในกรณีพิเศษนี่คือสิ่งที่คุณต้องการ โดยส่วนตัวแล้ว ฉันคิดว่าคุณควรใช้แอตทริบิวต์ cmdletbinding ดีกว่าเหมือนที่ฉันทำกับตัวอย่าง Set-Folder6 ของฉัน
การเพิ่มการรองรับ WhatIf และ Confirm ไม่ได้ใช้ความพยายามมากนัก และจะช่วยยกระดับฟังก์ชันขั้นสูงของคุณไปอีกระดับ
โพสต์นี้เป็นส่วนหนึ่งของชุด PowerShell Blogging Week ใน Windows PowerShell Advanced Functions ซึ่งเป็นชุดโพสต์ที่ประสานงานกันซึ่งออกแบบมาเพื่อให้มุมมองที่ครอบคลุมของหัวข้อใดหัวข้อหนึ่ง
บทความอื่นๆ ในชุดนี้:
- ฟังก์ชันมาตรฐานและขั้นสูง โดย Francois-Xavier Cat
- ฟังก์ชันขั้นสูงของ PowerShell: เราสามารถสร้างให้ดีขึ้นได้ไหม โดย Mike F. Robbins
- พารามิเตอร์แบบไดนามิกและการตรวจสอบพารามิเตอร์ โดย Adam Bertram
- การสร้างความช่วยเหลือและความคิดเห็น โดย June Blender
- ลอง/จับและการจัดการข้อผิดพลาดที่จำเป็น โดย Boe Prox
เราหวังว่าคุณจะพบว่างานของเราคุ้มค่ากับเวลาของคุณ









