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

ฟังก์ชั่น


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

เมื่อใดก็ตามที่เป็นไปได้ ฉันชอบเขียนฟังก์ชันมากกว่าเพราะว่ามันเน้นเครื่องมือมากกว่า ฉันสามารถใส่ฟังก์ชันต่างๆ ในโมดูลสคริปต์ ใส่โมดูลนั้นใน $env:PSModulePath และเรียกใช้ฟังก์ชันต่างๆ โดยไม่จำเป็นต้องระบุตำแหน่งทางกายภาพที่บันทึกไว้ การใช้โมดูล PowerShellGet ทำให้การแบ่งปันโมดูลเหล่านั้นในพื้นที่เก็บข้อมูล NuGet เป็นเรื่องง่าย PowerShellGet มาพร้อมกับ PowerShell เวอร์ชัน 5.0 และสูงกว่า มีให้ดาวน์โหลดแยกต่างหากสำหรับ PowerShell เวอร์ชัน 3.0 และสูงกว่า

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

การตั้งชื่อ

เมื่อตั้งชื่อฟังก์ชันของคุณใน PowerShell ให้ใช้ชื่อตัวพิมพ์ Pascal พร้อมด้วยกริยาที่ได้รับอนุมัติและคำนามเอกพจน์ ฉันยังแนะนำให้เติมคำนำหน้าคำนามด้วย ตัวอย่างเช่น: <ApprovedVerb>-

ใน PowerShell มีรายการกริยาที่ได้รับการอนุมัติเฉพาะซึ่งสามารถรับได้โดยการเรียกใช้ Get-Verb

Get-Verb | Sort-Object -Property Verb
Verb        Group
----        -----
Add         Common
Approve     Lifecycle
Assert      Lifecycle
Backup      Data
Block       Security
Checkpoint  Data
Clear       Common
Close       Common
Compare     Data
Complete    Lifecycle
Compress    Data
Confirm     Lifecycle
Connect     Communications
Convert     Data
ConvertFrom Data
ConvertTo   Data
Copy        Common
Debug       Diagnostic
Deny        Lifecycle
Disable     Lifecycle
Disconnect  Communications
Dismount    Data
Edit        Data
Enable      Lifecycle
Enter       Common
Exit        Common
Expand      Data
Export      Data
Find        Common
Format      Common
Get         Common
Grant       Security
Group       Data
Hide        Common
Import      Data
Initialize  Data
Install     Lifecycle
Invoke      Lifecycle
Join        Common
Limit       Data
Lock        Common
Measure     Diagnostic
Merge       Data
Mount       Data
Move        Common
New         Common
Open        Common
Optimize    Common
Out         Data
Ping        Diagnostic
Pop         Common
Protect     Security
Publish     Data
Push        Common
Read        Communications
Receive     Communications
Redo        Common
Register    Lifecycle
Remove      Common
Rename      Common
Repair      Diagnostic
Request     Lifecycle
Reset       Common
Resize      Common
Resolve     Diagnostic
Restart     Lifecycle
Restore     Data
Resume      Lifecycle
Revoke      Security
Save        Data
Search      Common
Select      Common
Send        Communications
Set         Common
Show        Common
Skip        Common
Split       Common
Start       Lifecycle
Step        Common
Stop        Lifecycle
Submit      Lifecycle
Suspend     Lifecycle
Switch      Common
Sync        Data
Test        Diagnostic
Trace       Diagnostic
Unblock     Security
Undo        Common
Uninstall   Lifecycle
Unlock      Common
Unprotect   Security
Unpublish   Data
Unregister  Lifecycle
Update      Data
Use         Other
Wait        Lifecycle
Watch       Common
Write       Communications

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

ฟังก์ชั่นง่ายๆ

ฟังก์ชันใน PowerShell ได้รับการประกาศโดยใช้คำสำคัญฟังก์ชัน ตามด้วยชื่อฟังก์ชัน จากนั้นจึงใช้เครื่องหมายปีกกาเปิดและปิด รหัสที่ฟังก์ชันจะดำเนินการจะอยู่ภายในเครื่องหมายปีกกาเหล่านั้น

function Get-Version {
    $PSVersionTable.PSVersion
}

ฟังก์ชันที่แสดงเป็นตัวอย่างง่ายๆ ที่ส่งคืนเวอร์ชันของ PowerShell

Get-Version
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      14393  693

มีโอกาสสูงที่ชื่อจะขัดแย้งกับฟังก์ชันที่มีชื่อบางอย่างเช่น Get-Version และคำสั่งเริ่มต้นใน PowerShell หรือคำสั่งที่ผู้อื่นอาจเขียน นี่คือเหตุผลที่ฉันแนะนำให้นำหน้าส่วนนามของฟังก์ชันของคุณเพื่อช่วยป้องกันความขัดแย้งในการตั้งชื่อ ในตัวอย่างต่อไปนี้ ฉันจะใช้คำนำหน้า "PS"

function Get-PSVersion {
    $PSVersionTable.PSVersion
}

นอกเหนือจากชื่อแล้ว ฟังก์ชันนี้ยังเหมือนกับฟังก์ชันก่อนหน้า

Get-PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      14393  693

แม้ว่าจะขึ้นต้นคำนามด้วยคำอย่างเช่น PS แต่ก็ยังมีโอกาสสูงที่ชื่อจะขัดแย้งกัน ฉันมักจะนำหน้าคำนามฟังก์ชันของฉันด้วยชื่อย่อของฉัน พัฒนามาตรฐานและยึดมั่นกับมัน

function Get-MrPSVersion {
    $PSVersionTable.PSVersion
}

ฟังก์ชันนี้ไม่แตกต่างจากสองฟังก์ชันก่อนหน้านี้ ยกเว้นการใช้ชื่อที่สมเหตุสมผลมากกว่าเพื่อพยายามป้องกันการขัดแย้งในการตั้งชื่อกับคำสั่ง PowerShell อื่นๆ

Get-MrPSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      14393  693

เมื่อโหลดลงในหน่วยความจำแล้ว คุณจะสามารถดูฟังก์ชันต่างๆ บน ฟังก์ชัน PSDrive ได้

Get-ChildItem -Path Function:\Get-*Version
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Get-Version
Function        Get-PSVersion
Function        Get-MrPSVersion

หากคุณต้องการลบฟังก์ชันเหล่านี้ออกจากเซสชันปัจจุบัน คุณจะต้องลบออกจาก ฟังก์ชัน PSDrive หรือปิดและเปิด PowerShell อีกครั้ง

Get-ChildItem -Path Function:\Get-*Version | Remove-Item

ตรวจสอบว่าฟังก์ชันถูกลบออกไปแล้วจริงๆ

Get-ChildItem -Path Function:\Get-*Version

หากฟังก์ชันถูกโหลดเป็นส่วนหนึ่งของโมดูล ก็สามารถยกเลิกการโหลดโมดูลเพื่อลบออกได้

Remove-Module -Name <ModuleName>

Remove-Module cmdlet จะลบโมดูลออกจากหน่วยความจำในเซสชัน PowerShell ปัจจุบันของคุณ แต่จะไม่ลบออกจากระบบของคุณหรือจากดิสก์

พารามิเตอร์

อย่ากำหนดค่าคงที่! ใช้พารามิเตอร์และตัวแปร เมื่อพูดถึงการตั้งชื่อพารามิเตอร์ของคุณ ให้ใช้ชื่อเดียวกันกับ cmdlets เริ่มต้นสำหรับชื่อพารามิเตอร์ของคุณทุกครั้งที่เป็นไปได้

function Test-MrParameter {

    param (
        $ComputerName
    )

    Write-Output $ComputerName

}

เหตุใดฉันจึงใช้ ชื่อคอมพิวเตอร์ และไม่ใช้ คอมพิวเตอร์, ชื่อเซิร์ฟเวอร์ หรือ โฮสต์ สำหรับชื่อพารามิเตอร์ของฉัน เป็นเพราะฉันต้องการให้ฟังก์ชันของฉันเป็นมาตรฐานเหมือน cmdlets เริ่มต้น

ฉันจะสร้างฟังก์ชันเพื่อสืบค้นคำสั่งทั้งหมดบนระบบและส่งกลับจำนวนคำสั่งที่มีชื่อพารามิเตอร์เฉพาะ

function Get-MrParameterCount {
    param (
        [string[]]$ParameterName
    )

    foreach ($Parameter in $ParameterName) {
        $Results = Get-Command -ParameterName $Parameter -ErrorAction SilentlyContinue

        [pscustomobject]@{
            ParameterName = $Parameter
            NumberOfCmdlets = $Results.Count
        }
    }
}

ดังที่คุณเห็นในผลลัพธ์ที่แสดงด้านล่าง 39 คำสั่งที่มีพารามิเตอร์ ชื่อคอมพิวเตอร์ ไม่มี cmdlet ใดที่มีพารามิเตอร์ เช่น คอมพิวเตอร์, ชื่อเซิร์ฟเวอร์, โฮสต์ หรือ เครื่อง

Get-MrParameterCount -ParameterName ComputerName, Computer, ServerName, Host, Machine
ParameterName NumberOfCmdlets
------------- ---------------
ComputerName               39
Computer                    0
ServerName                  0
Host                        0
Machine                     0

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

คำสั่ง param ช่วยให้คุณสามารถกำหนดพารามิเตอร์ตั้งแต่หนึ่งตัวขึ้นไป คำจำกัดความของพารามิเตอร์คั่นด้วยเครื่องหมายจุลภาค (,) สำหรับข้อมูลเพิ่มเติม โปรดดู about_Functions_Advanced_Parameters

ฟังก์ชั่นขั้นสูง

การเปลี่ยนฟังก์ชันใน PowerShell ให้เป็นฟังก์ชันขั้นสูงนั้นง่ายมาก ความแตกต่างประการหนึ่งระหว่างฟังก์ชันและฟังก์ชันขั้นสูงก็คือ ฟังก์ชันขั้นสูงมีพารามิเตอร์ทั่วไปจำนวนหนึ่งที่จะถูกเพิ่มลงในฟังก์ชันโดยอัตโนมัติ พารามิเตอร์ทั่วไปเหล่านี้ประกอบด้วยพารามิเตอร์ เช่น Verbose และ Debug

ฉันจะเริ่มต้นด้วยฟังก์ชัน Test-MrParameter ที่ใช้ในหัวข้อที่แล้ว

function Test-MrParameter {

    param (
        $ComputerName
    )

    Write-Output $ComputerName

}

สิ่งที่ฉันต้องการให้คุณสังเกตคือฟังก์ชัน Test-MrParameter ไม่มีพารามิเตอร์ทั่วไป มีสองวิธีในการดูพารามิเตอร์ทั่วไป วิธีหนึ่งคือการดูไวยากรณ์โดยใช้ Get-Command

Get-Command -Name Test-MrParameter -Syntax
Test-MrParameter [[-ComputerName] <Object>]

อีกประการหนึ่งคือการเจาะลึกลงในพารามิเตอร์ด้วย Get-Command

(Get-Command -Name Test-MrParameter).Parameters.Keys
ComputerName

เพิ่ม CmdletBinding เพื่อเปลี่ยนฟังก์ชันให้เป็นฟังก์ชันขั้นสูง

function Test-MrCmdletBinding {

    [CmdletBinding()] #<<-- This turns a regular function into an advanced function
    param (
        $ComputerName
    )

    Write-Output $ComputerName

}

การเพิ่ม CmdletBinding จะเพิ่มพารามิเตอร์ทั่วไปโดยอัตโนมัติ CmdletBinding จำเป็นต้องมีบล็อก param แต่บล็อก param สามารถเว้นว่างได้

Get-Command -Name Test-MrCmdletBinding -Syntax
Test-MrCmdletBinding [[-ComputerName] <Object>] [<CommonParameters>]

การเจาะลึกพารามิเตอร์ด้วย Get-Command จะแสดงชื่อพารามิเตอร์จริงรวมถึงชื่อทั่วไปด้วย

(Get-Command -Name Test-MrCmdletBinding).Parameters.Keys
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable

รองรับกระบวนการควร

SupportsShouldProcess เพิ่มพารามิเตอร์ WhatIf และ Confirm สิ่งเหล่านี้จำเป็นสำหรับคำสั่งที่ทำการเปลี่ยนแปลงเท่านั้น

function Test-MrSupportsShouldProcess {

    [CmdletBinding(SupportsShouldProcess)]
    param (
        $ComputerName
    )

    Write-Output $ComputerName

}

โปรดสังเกตว่าขณะนี้มีพารามิเตอร์ WhatIf และ ยืนยัน

Get-Command -Name Test-MrSupportsShouldProcess -Syntax
Test-MrSupportsShouldProcess [[-ComputerName] <Object>] [-WhatIf] [-Confirm] [<CommonParameters>]

อีกครั้ง คุณยังสามารถใช้ Get-Command เพื่อส่งคืนรายการชื่อพารามิเตอร์จริง รวมถึงชื่อทั่วไปพร้อมกับ WhatIf และ Confirm

(Get-Command -Name Test-MrSupportsShouldProcess).Parameters.Keys
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
WhatIf
Confirm

การตรวจสอบพารามิเตอร์

ตรวจสอบอินพุตตั้งแต่เนิ่นๆ เหตุใดจึงอนุญาตให้โค้ดของคุณดำเนินต่อไปบนเส้นทางเมื่อไม่สามารถทำงานหากไม่มีอินพุตที่ถูกต้อง

พิมพ์ตัวแปรที่ใช้สำหรับพารามิเตอร์ของคุณเสมอ (ระบุประเภทข้อมูล)

function Test-MrParameterValidation {

    [CmdletBinding()]
    param (
        [string]$ComputerName
    )

    Write-Output $ComputerName

}

ในตัวอย่างก่อนหน้านี้ ฉันได้ระบุ String เป็นประเภทข้อมูลสำหรับพารามิเตอร์ ComputerName ซึ่งทำให้อนุญาตให้ระบุชื่อคอมพิวเตอร์เครื่องเดียวเท่านั้น หากมีการระบุชื่อคอมพิวเตอร์มากกว่าหนึ่งชื่อผ่านรายการที่คั่นด้วยเครื่องหมายจุลภาค จะเกิดข้อผิดพลาดขึ้น

Test-MrParameterValidation -ComputerName Server01, Server02
Test-MrParameterValidation : Cannot process argument transformation on parameter
'ComputerName'. Cannot convert value to type System.String.
At line:1 char:42
+ Test-MrParameterValidation -ComputerName Server01, Server02
+
    + CategoryInfo          : InvalidData: (:) [Test-MrParameterValidation], ParameterBindingArg
     umentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Test-MrParameterValidation

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

function Test-MrParameterValidation {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$ComputerName
    )

    Write-Output $ComputerName

}

ไวยากรณ์ที่ใช้ในตัวอย่างก่อนหน้านี้คือ PowerShell เวอร์ชัน 3.0 และเข้ากันได้สูงกว่า [Parameter(Mandatory=$true)] สามารถระบุแทนได้เพื่อทำให้ฟังก์ชันเข้ากันได้กับ PowerShell เวอร์ชัน 2.0 และสูงกว่า เมื่อจำเป็นต้องมี ชื่อคอมพิวเตอร์ แล้ว หากไม่มีการระบุ ฟังก์ชันจะแจ้งให้ระบุ

Test-MrParameterValidation
cmdlet Test-MrParameterValidation at command pipeline position 1
Supply values for the following parameters:
ComputerName:

หากคุณต้องการอนุญาตให้มีค่ามากกว่าหนึ่งค่าสำหรับพารามิเตอร์ ComputerName ให้ใช้ประเภทข้อมูล String แต่เพิ่มวงเล็บเหลี่ยมแบบเปิดและแบบปิดให้กับประเภทข้อมูลเพื่ออนุญาตให้มีอาร์เรย์ของสตริง .

function Test-MrParameterValidation {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string[]]$ComputerName
    )

    Write-Output $ComputerName

}

บางทีคุณอาจต้องการระบุค่าเริ่มต้นสำหรับพารามิเตอร์ ComputerName หากไม่ได้ระบุไว้ ปัญหาคือไม่สามารถใช้ค่าเริ่มต้นกับพารามิเตอร์บังคับได้ คุณจะต้องใช้แอตทริบิวต์การตรวจสอบความถูกต้องของพารามิเตอร์ ValidateNotNullOrEmpty ด้วยค่าเริ่มต้นแทน

function Test-MrParameterValidation {

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [string[]]$ComputerName = $env:COMPUTERNAME
    )

    Write-Output $ComputerName

}

แม้จะตั้งค่าเริ่มต้น พยายามอย่าใช้ค่าคงที่ ในตัวอย่างก่อนหน้านี้ $env:COMPUTERNAME จะถูกใช้เป็นค่าเริ่มต้น ซึ่งจะถูกแปลเป็นชื่อคอมพิวเตอร์ในระบบโดยอัตโนมัติหากไม่มีการระบุค่า

เอาท์พุทแบบละเอียด

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

ฟังก์ชันที่แสดงในตัวอย่างต่อไปนี้มีความคิดเห็นแบบอินไลน์ในลูป foreach แม้ว่าความคิดเห็นเฉพาะนี้อาจค้นหาได้ไม่ยาก แต่ลองจินตนาการดูว่าฟังก์ชันมีโค้ดหลายร้อยบรรทัดหรือไม่

function Test-MrVerboseOutput {

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [string[]]$ComputerName = $env:COMPUTERNAME
    )

    foreach ($Computer in $ComputerName) {
        #Attempting to perform some action on $Computer <<-- Don't use
        #inline comments like this, use write verbose instead.
        Write-Output $Computer
    }

}

ตัวเลือกที่ดีกว่าคือการใช้ Write-Verbose แทนความคิดเห็นแบบอินไลน์

function Test-MrVerboseOutput {

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [string[]]$ComputerName = $env:COMPUTERNAME
    )

    foreach ($Computer in $ComputerName) {
        Write-Verbose -Message "Attempting to perform some action on $Computer"
        Write-Output $Computer
    }

}

เมื่อเรียกใช้ฟังก์ชันโดยไม่มีพารามิเตอร์ Verbose เอาต์พุตแบบละเอียดจะไม่แสดง

Test-MrVerboseOutput -ComputerName Server01, Server02

เมื่อเรียกด้วยพารามิเตอร์ Verbose เอาต์พุตแบบละเอียดจะปรากฏขึ้น

Test-MrVerboseOutput -ComputerName Server01, Server02 -Verbose

อินพุตไปป์ไลน์

เมื่อคุณต้องการให้ฟังก์ชันของคุณยอมรับอินพุตไปป์ไลน์ จำเป็นต้องมีการเข้ารหัสเพิ่มเติมบางอย่าง ตามที่กล่าวไว้ก่อนหน้าในหนังสือเล่มนี้ คำสั่งสามารถรับอินพุตไปป์ไลน์ ตามค่า (ตามประเภท) หรือ ตามชื่อคุณสมบัติ คุณสามารถเขียนฟังก์ชันของคุณได้เหมือนกับคำสั่งเนทีฟ เพื่อให้ฟังก์ชันยอมรับอินพุตประเภทใดประเภทหนึ่งหรือทั้งสองประเภทก็ได้

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

อินพุตไปป์ไลน์มาทีละรายการคล้ายกับวิธีจัดการรายการต่างๆ ในลูป foreach อย่างน้อยที่สุด จำเป็นต้องมีบล็อก กระบวนการ เพื่อประมวลผลแต่ละรายการเหล่านี้ หากคุณยอมรับอาร์เรย์เป็นอินพุต หากคุณยอมรับเพียงค่าเดียวเป็นอินพุต ก็ไม่จำเป็นต้องบล็อก กระบวนการ แต่ฉันยังคงแนะนำให้ระบุเพื่อความสอดคล้องกัน

function Test-MrPipelineInput {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory,
                   ValueFromPipeline)]
        [string[]]$ComputerName
    )

    PROCESS {
        Write-Output $ComputerName
    }

}

การยอมรับอินพุตไปป์ไลน์ ตามชื่อคุณสมบัติ จะคล้ายกันยกเว้นว่าระบุไว้ด้วยแอตทริบิวต์พารามิเตอร์ ValueFromPipelineByPropertyName และสามารถระบุให้กับพารามิเตอร์จำนวนเท่าใดก็ได้โดยไม่คำนึงถึงประเภทข้อมูล สิ่งสำคัญคือเอาต์พุตของคำสั่งที่กำลังไพพ์ต้องมีชื่อคุณสมบัติที่ตรงกับชื่อของพารามิเตอร์หรือนามแฝงพารามิเตอร์ของฟังก์ชันของคุณ

function Test-MrPipelineInput {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName
    )

    PROCESS {
            Write-Output $ComputerName
    }

}

บล็อก BEGIN และ END เป็นทางเลือก BEGIN จะถูกระบุก่อนบล็อก PROCESS และใช้เพื่อดำเนินการเริ่มต้นใดๆ ก่อนที่จะได้รับรายการจากไปป์ไลน์ นี่เป็นสิ่งสำคัญที่ต้องเข้าใจ ค่าที่ส่งไปไม่สามารถเข้าถึงได้ในบล็อก BEGIN บล็อก END จะถูกระบุหลังบล็อก PROCESS และจะใช้สำหรับการล้างข้อมูลเมื่อรายการทั้งหมดที่มีการไปป์ได้รับการประมวลผลแล้ว

การจัดการข้อผิดพลาด

ฟังก์ชันที่แสดงในตัวอย่างต่อไปนี้จะสร้างข้อยกเว้นที่ไม่สามารถจัดการได้เมื่อไม่สามารถติดต่อกับคอมพิวเตอร์ได้

function Test-MrErrorHandling {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName
    )

    PROCESS {
        foreach ($Computer in $ComputerName) {
            Test-WSMan -ComputerName $Computer
        }
    }

}

มีสองวิธีในการจัดการข้อผิดพลาดใน PowerShell Try/Catch เป็นวิธีที่ทันสมัยกว่าในการจัดการกับข้อผิดพลาด

function Test-MrErrorHandling {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName
    )

    PROCESS {
        foreach ($Computer in $ComputerName) {
            try {
                Test-WSMan -ComputerName $Computer
            }
            catch {
                Write-Warning -Message "Unable to connect to Computer: $Computer"
            }
        }
    }

}

แม้ว่าฟังก์ชันที่แสดงในตัวอย่างก่อนหน้านี้จะใช้การจัดการข้อผิดพลาด แต่ก็ยังสร้างข้อยกเว้นที่ไม่สามารถจัดการได้เนื่องจากคำสั่งไม่สร้างข้อผิดพลาดในการสิ้นสุด นี่เป็นสิ่งสำคัญที่ต้องเข้าใจด้วย ตรวจพบเฉพาะข้อผิดพลาดในการยกเลิกเท่านั้น ระบุพารามิเตอร์ ErrorAction ด้วย Stop เป็นค่าเพื่อเปลี่ยนข้อผิดพลาดที่ไม่ยุติให้กลายเป็นข้อผิดพลาดที่ยุติ

function Test-MrErrorHandling {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory,
                   ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName
    )

    PROCESS {
        foreach ($Computer in $ComputerName) {
            try {
                Test-WSMan -ComputerName $Computer -ErrorAction Stop
            }
            catch {
                Write-Warning -Message "Unable to connect to Computer: $Computer"
            }
        }
    }

}

อย่าแก้ไขตัวแปร $ErrorActionPreference ส่วนกลาง เว้นแต่จะจำเป็นจริงๆ หากคุณใช้บางอย่างเช่น .NET โดยตรงจากภายในฟังก์ชัน PowerShell คุณจะไม่สามารถระบุ ErrorAction บนคำสั่งได้ ในสถานการณ์นั้น คุณอาจต้องเปลี่ยนตัวแปร $ErrorActionPreference โกลบอล แต่หากคุณเปลี่ยน ให้เปลี่ยนกลับทันทีหลังจากลองใช้คำสั่ง

ความช่วยเหลือตามความคิดเห็น

ถือเป็นแนวทางปฏิบัติที่ดีที่สุดในการเพิ่มความช่วยเหลือตามความคิดเห็นให้กับฟังก์ชันของคุณ เพื่อให้คนที่คุณแชร์ด้วยจะรู้วิธีใช้งาน

function Get-MrAutoStoppedService {

<#
.SYNOPSIS
    Returns a list of services that are set to start automatically, are not
    currently running, excluding the services that are set to delayed start.

.DESCRIPTION
    Get-MrAutoStoppedService is a function that returns a list of services from
    the specified remote computer(s) that are set to start automatically, are not
    currently running, and it excludes the services that are set to start automatically
    with a delayed startup.

.PARAMETER ComputerName
    The remote computer(s) to check the status of the services on.

.PARAMETER Credential
    Specifies a user account that has permission to perform this action. The default
    is the current user.

.EXAMPLE
     Get-MrAutoStoppedService -ComputerName 'Server1', 'Server2'

.EXAMPLE
     'Server1', 'Server2' | Get-MrAutoStoppedService

.EXAMPLE
     Get-MrAutoStoppedService -ComputerName 'Server1' -Credential (Get-Credential)

.INPUTS
    String

.OUTPUTS
    PSCustomObject

.NOTES
    Author:  Mike F Robbins
    Website: http://mikefrobbins.com
    Twitter: @mikefrobbins
#>

    [CmdletBinding()]
    param (

    )

    #Function Body

}

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

ไวยากรณ์ทั้งหมดสำหรับการเขียนฟังก์ชันใน PowerShell อาจดูล้นหลาม โดยเฉพาะอย่างยิ่งสำหรับผู้ที่เพิ่งเริ่มต้น บ่อยครั้งหากฉันจำไวยากรณ์ของบางสิ่งบางอย่างไม่ได้ ฉันจะเปิดสำเนาที่สองของ ISE บนจอภาพแยกต่างหาก และดูตัวอย่างข้อมูล "Cmdlet (ฟังก์ชันขั้นสูง) - เสร็จสมบูรณ์" ขณะพิมพ์โค้ดสำหรับฟังก์ชันของฉัน คุณสามารถเข้าถึงตัวอย่างได้ใน PowerShell ISE โดยใช้คีย์ผสม Ctrl+J

สรุป

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

ทบทวน

  1. คุณจะได้รับรายการกริยาที่ได้รับอนุมัติใน PowerShell ได้อย่างไร
  2. คุณจะเปลี่ยนฟังก์ชัน PowerShell ให้เป็นฟังก์ชันขั้นสูงได้อย่างไร
  3. เมื่อใดควรเพิ่มพารามิเตอร์ WhatIf และ ยืนยัน ให้กับฟังก์ชัน PowerShell ของคุณ
  4. คุณจะเปลี่ยนข้อผิดพลาดที่ไม่ยุติให้กลายเป็นข้อผิดพลาดที่ยุติได้อย่างไร
  5. เหตุใดคุณจึงควรเพิ่มความช่วยเหลือตามความคิดเห็นให้กับฟังก์ชันของคุณ

แนะนำให้อ่าน

  • about_Functions
  • about_Functions_Advanced_Parameters
  • about_CommonParameters
  • about_Functions_CmdletBindingAttribute
  • about_Functions_ขั้นสูง
  • about_Try_Catch_ในที่สุด
  • about_Comment_Based_Help
  • วิดีโอ: การสร้างเครื่องมือ PowerShell พร้อมฟังก์ชันขั้นสูงและโมดูลสคริปต์

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