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

สัปดาห์การเขียนบล็อก 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

เราหวังว่าคุณจะพบว่างานของเราคุ้มค่ากับเวลาของคุณ

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