Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Jednořádkové skripty a skripty PowerShellu, které je potřeba často upravovat, jsou vhodnými kandidáty na přeměnu na opakovaně použitelné funkce.
Kdykoli je to možné, můžete psát funkce, protože jsou více orientované na nástroje. Funkce můžete přidat do modulu skriptu, umístit tento modul do umístění definovaného v $env:PSModulePath
a volat funkce, aniž byste museli najít, kam jste funkce uložili. Pomocí modulu PowerShellGet je snadné sdílet moduly PowerShellu v úložišti NuGet.
PowerShellGet se dodává s PowerShellem ve verzi 5.0 a vyšší. Je také k dispozici jako samostatný soubor ke stažení pro PowerShell verze 3.0 a vyšší.
Nepřekombinujte věci. Udržujte to jednoduché a používejte nejjednodušší způsob, jak provést úkol. Vyhněte se aliasům a pozičním parametrům v libovolném kódu, který znovu použijete. Naformátujte kód tak, aby byl čitelný. Nezakódujte hodnoty; použít parametry a proměnné. Nepište nepotřebný kód, i když nic neublíží. Přidává zbytečné složitosti. Při psaní jakéhokoli kódu PowerShellu je potřeba věnovat pozornost podrobnostem.
Pojmenování
Při pojmenování funkcí v PowerShellu použijte Pascal case název se schváleným slovesem a jednotným podstatným jménem. Pokud chcete získat seznam schválených příkazů v PowerShellu, spusťte Get-Verb
. Následující příklad seřadí výsledky podle vlastnosti Sloveso u Get-Verb
.
Get-Verb | Sort-Object -Property Verb
Vlastnost Group vám poskytne představu o tom, jak se mají příkazy použít.
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
Pro funkce PowerShellu je důležité použít schválené příkazy. Moduly, které obsahují funkce s neschválenými příkazy, generují při importu do relace PowerShellu zprávu s upozorněním. Tato zpráva s upozorněním způsobí, že vaše funkce vypadají neprofesionálně. Neschválené příkazy také omezují zjistitelnost vašich funkcí.
Jednoduchá funkce
Funkce v PowerShellu se deklaruje s klíčovým slovem funkce následovaným názvem funkce a potom levou a pravou složenou závorkou ({ }
). Kód spuštěný funkcí je obsažen v těchto složených závorkách.
function Get-Version {
$PSVersionTable.PSVersion
}
Funkce zobrazená v následujícím příkladu je jednoduchý příklad, který vrací verzi PowerShellu.
Get-Version
Major Minor Build Revision
----- ----- ----- --------
5 1 14393 693
Pokud pro funkce použijete obecný název, například Get-Version
, může dojít ke konfliktům pojmenování. Výchozí příkazy přidané v budoucnu nebo příkazy, které můžou napsat ostatní, můžou být v konfliktu s nimi. Přidejte předponu k podstatné části jmen vašich funkcí, abyste předešli konfliktům názvů. Příklad: <ApprovedVerb>-<Prefix><SingularNoun>
.
Následující příklad používá předponu PS
.
function Get-PSVersion {
$PSVersionTable.PSVersion
}
Kromě názvu je tato funkce shodná s předchozím názvem.
Get-PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 14393 693
Konflikt názvů můžete mít i po přidání předpony ke podstatnému jménu. Rád přidávám před své názvy funkcí své iniciály. Vyvíjejte standard a držte se ho.
function Get-MrPSVersion {
$PSVersionTable.PSVersion
}
Tato funkce se neliší od předchozích dvou, s výjimkou použití jedinečnějšího názvu, aby se zabránilo konfliktům názvů s jinými příkazy PowerShellu.
Get-MrPSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 14393 693
Po načtení do paměti uvidíte funkce na Function PSDrive.
Get-ChildItem -Path Function:\Get-*Version
CommandType Name Version
----------- ---- -------
Function Get-Version
Function Get-PSVersion
Function Get-MrPSVersion
Pokud chcete tyto funkce odebrat z aktuální relace, odeberte je z Function PSDrive nebo zavřete PowerShell a znovu ho otevřete.
Get-ChildItem -Path Function:\Get-*Version | Remove-Item
Ověřte, že funkce byly skutečně odebrány.
Get-ChildItem -Path Function:\Get-*Version
Pokud byly funkce načteny jako součást modulu, můžete modul uvolnit, abyste je odebrali.
Remove-Module -Name <ModuleName>
Cmdlet Remove-Module
odebere moduly PowerShellu z paměti v aktuální relaci PowerShellu. Neodebere je ze systému nebo disku.
Parametry
Nepřiřazujte hodnoty staticky. Místo toho použijte parametry a proměnné. Při pojmenování parametrů použijte stejný název jako výchozí rutiny pro názvy parametrů, kdykoli je to možné.
V následující funkci si všimněte, že jsem použil ComputerName, a nikoli Computer, ServerNamenebo Host pro název parametru. Pomocí ComputerName standardizuje název parametru tak, aby odpovídal názvu parametru a případu, jako jsou výchozí rutiny.
function Test-MrParameter {
param (
$ComputerName
)
Write-Output $ComputerName
}
Následující funkce se dotazuje na všechny příkazy ve vašem systému a vrátí číslo s konkrétními názvy parametrů.
function Get-MrParameterCount {
param (
[string[]]$ParameterName
)
foreach ($Parameter in $ParameterName) {
$Results = Get-Command -ParameterName $Parameter -ErrorAction SilentlyContinue
[pscustomobject]@{
ParameterName = $Parameter
NumberOfCmdlets = $Results.Count
}
}
}
Jak vidíte v následujících výsledcích, 39 příkazů, které mají ComputerName parametr. Nejsou k dispozici žádné příkazy s parametry, jako jsoupočítače
Get-MrParameterCount -ParameterName ComputerName, Computer, ServerName,
Host, Machine
ParameterName NumberOfCmdlets
------------- ---------------
ComputerName 39
Computer 0
ServerName 0
Host 0
Machine 0
Použijte stejnou velikost písmen pro názvy parametrů jako ve výchozích rutinách cmdletů. Například použijte ComputerName
, nikoli computername
. Toto schéma pojmenování pomáhá lidem obeznámeným s PowerShellem rozeznat vaše funkce a působí dojmem výchozích rutin (cmdletů).
Příkaz param
umožňuje definovat jeden nebo více parametrů. Čárka (,
) odděluje definice parametrů. Další informace naleznete v části about_Functions_Advanced_Parameters.
Pokročilé funkce
Přeměna funkce na pokročilou funkci v PowerShellu je jednoduchá. Jedním z rozdílů mezi funkcí a pokročilou funkcí je, že pokročilé funkce mají společné parametry, které se automaticky přidají. Mezi běžné parametry patří parametry, jako jsou podrobné a ladění.
Začněte funkcí Test-MrParameter
, která byla použita v předchozí části.
function Test-MrParameter {
param (
$ComputerName
)
Write-Output $ComputerName
}
Existuje několik různých způsobů, jak zobrazit běžné parametry. Jedním ze způsobů je prohlížení syntaxe pomocí Get-Command
.
Get-Command -Name Test-MrParameter -Syntax
Všimněte si, že funkce Test-MrParameter
nemá žádné společné parametry.
Test-MrParameter [[-ComputerName] <Object>]
Další možností je přejít k podrobnostem o vlastnosti parametrů Get-Command
.
(Get-Command -Name Test-MrParameter).Parameters.Keys
ComputerName
Přidejte atribut CmdletBinding
, který převede funkci na pokročilou funkci.
function Test-MrCmdletBinding {
[CmdletBinding()] # Turns a regular function into an advanced function
param (
$ComputerName
)
Write-Output $ComputerName
}
Při zadávání CmdletBinding
se běžné parametry přidají automaticky.
CmdletBinding
vyžaduje blok param
, ale blok param
může být prázdný.
Get-Command -Name Test-MrCmdletBinding -Syntax
Test-MrCmdletBinding [[-ComputerName] <Object>] [<CommonParameters>]
Detailní procházení vlastnosti parametrů Get-Command
zobrazuje skutečné názvy parametrů, včetně těch běžně používaných.
(Get-Command -Name Test-MrCmdletBinding).Parameters.Keys
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
PodporujeShouldProcess
Atribut SupportsShouldProcess
přidá parametry zmírnění rizik WhatIf a Confirm. Tyto parametry jsou potřeba jenom pro příkazy, které provádějí změny.
function Test-MrSupportsShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param (
$ComputerName
)
Write-Output $ComputerName
}
Všimněte si, že teď jsou parametry WhatIf a Confirm.
Get-Command -Name Test-MrSupportsShouldProcess -Syntax
Test-MrSupportsShouldProcess [[-ComputerName] <Object>] [-WhatIf] [-Confirm]
[<CommonParameters>]
Znovu můžete také použít Get-Command
k vrácení seznamu skutečných názvů parametrů, včetně běžných parametrů, a dalších jako WhatIf a Potvrdit.
(Get-Command -Name Test-MrSupportsShouldProcess).Parameters.Keys
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
WhatIf
Confirm
Ověření parametru
Nejdřív ověřte vstup. Nepovolujte kódu pokračovat v cestě, když se nedá dokončit bez platného vstupu.
Vždy zadejte datový typ pro proměnné použité pro parametry. V následujícím příkladu je String zadán jako datový typ pro parametr ComputerName. Toto ověření omezuje, aby bylo možné zadat pouze jeden název počítače pro parametr ComputerName.
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[string]$ComputerName
)
Write-Output $ComputerName
}
Pokud je zadáno více než jeden název počítače, vygeneruje se chyba.
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]
, ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Test-MrP
arameterValidation
Problém s aktuální definicí je, že je možné vynechat hodnotu parametru ComputerName, ale hodnota je potřebná k úspěšnému dokončení funkce. V tomto scénáři je přínosný atribut parametru Mandatory
.
Syntaxe použitá v následujícím příkladu je kompatibilní s PowerShellem verze 3.0 a vyšší.
[Parameter(Mandatory=$true)]
je možné zadat, aby byla funkce kompatibilní s PowerShellem verze 2.0 nebo vyšší.
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$ComputerName
)
Write-Output $ComputerName
}
Nyní, když je ComputerName vyžadován, funkce vyzve k jeho zadání, pokud není uveden.
Test-MrParameterValidation
cmdlet Test-MrParameterValidation at command pipeline position 1
Supply values for the following parameters:
ComputerName:
Pokud chcete pro parametr ComputerName povolit více než jednu hodnotu, použijte datový typ String, ale přidejte do datového typu hranaté závorky ([]
), abyste umožnili pole řetězců.
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string[]]$ComputerName
)
Write-Output $ComputerName
}
Možná chcete zadat výchozí hodnotu pro parametr ComputerName, pokud není zadaný.
Problémem je, že výchozí hodnoty nelze použít s povinnými parametry. Místo toho použijte atribut ověření parametru ValidateNotNullOrEmpty
s výchozí hodnotou.
I když nastavíte výchozí hodnotu, zkuste nepoužívat statické hodnoty. V následujícím příkladu se $env:COMPUTERNAME
použije jako výchozí hodnota, která se automaticky přeloží na název místního počítače, pokud není zadaná hodnota.
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)
Write-Output $ComputerName
}
Podrobný výstup
Vložené komentáře jsou užitečné, pokud píšete složitý kód, ale uživatelé je neuvidí, pokud se na kód nedívají.
Funkce v následujícím příkladu obsahuje komentář přímo ve smyčce foreach
. I když tento konkrétní komentář nemusí být obtížné najít, představte si, jestli funkce obsahovala stovky řádků kódu.
function Test-MrVerboseOutput {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)
foreach ($Computer in $ComputerName) {
#Attempting to perform an action on $Computer <<-- Don't use
#inline comments like this, use write verbose instead.
Write-Output $Computer
}
}
Lepší možností je místo vložených komentářů použít Write-Verbose
.
function Test-MrVerboseOutput {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)
foreach ($Computer in $ComputerName) {
Write-Verbose -Message "Attempting to perform an action on $Computer"
Write-Output $Computer
}
}
Podrobný výstup se nezobrazí, pokud je funkce volána bez parametru Podrobný.
Test-MrVerboseOutput -ComputerName Server01, Server02
Podrobný výstup se zobrazí, když je funkce volána pomocí parametru Verbose.
Test-MrVerboseOutput -ComputerName Server01, Server02 -Verbose
Vstup do potrubí
Pokud chcete, aby funkce přijímala vstup kanálu, je potřeba další kód. Jak bylo zmíněno dříve v této knize, příkazy mohou přijímat vstup kanálu podle hodnoty (podle typu) nebo podle názvu vlastnosti. Funkce můžete psát jako nativní příkazy, aby přijímaly jeden nebo oba tyto typy vstupů.
Pokud chcete přijmout vstup kanálu jako hodnotu, zadejte atribut parametru ValueFromPipeline
pro tento konkrétní parametr. Můžete přijímat vstup kanálu pouze podle hodnoty z jednoho parametru každého datového typu. Pokud máte dva parametry, které přijímají řetězcový vstup, pouze jeden z nich může přijímat kanálový vstup podle hodnoty. Pokud jste pro oba parametry řetězce zadali hodnotou, vstup by nevěděl, ke kterému parametru se má svázat. Tento scénář je dalším důvodem, proč volám tento typ vstupu kanálu podle typu místo podle hodnoty.
Vstup zpracovatelského potrubí je přijímán po jedné položce, podobně jako se položky zpracovávají v cyklu foreach
.
Blok process
je nutný ke zpracování každé položky, pokud vaše funkce přijímá jako vstup pole. Pokud vaše funkce jako vstup přijímá jenom jednu hodnotu, není blok process
nutný, ale doporučuje se pro konzistenci.
function Test-MrPipelineInput {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline)]
[string[]]$ComputerName
)
process {
Write-Output $ComputerName
}
}
Přijetí vstupu kanálu podle názvu vlastnosti je obdobné, až na to, že je nutné použít atribut parametru ValueFromPipelineByPropertyName
a atribut může být specifikován pro libovolný počet parametrů bez ohledu na datový typ. Klíč je výstupem příkazu, který se předá, musí mít název vlastnosti, který odpovídá názvu parametru nebo aliasu parametru vaší funkce.
function Test-MrPipelineInput {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)
process {
Write-Output $ComputerName
}
}
begin
a bloky end
jsou volitelné.
begin
se zadává před blokem process
a slouží k provedení jakékoli počáteční práce před přijetím položek z kanálu. Hodnoty, které jsou přesměrovány, nejsou v bloku begin
přístupné. Blok end
se zadává po bloku process
a slouží k vyčištění po zpracování všech položek.
Zpracování chyb
Funkce zobrazená v následujícím příkladu vygeneruje neošetřenou výjimku, když počítač nelze kontaktovat.
function Test-MrErrorHandling {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)
process {
foreach ($Computer in $ComputerName) {
Test-WSMan -ComputerName $Computer
}
}
}
Existuje několik různých způsobů zpracování chyb v PowerShellu.
Try/Catch
je modernější způsob zpracování chyb.
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"
}
}
}
}
I když funkce zobrazená v předchozím příkladu používá zpracování chyb, vygeneruje neošetřenou výjimku, protože příkaz negeneruje ukončující chybu. Zachyceny jsou pouze ukončující chyby. Zadejte parametr ErrorAction s hodnotou Zastavit, aby se z nekončící chyby stala chyba končící.
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"
}
}
}
}
Neupravujte globální $ErrorActionPreference
proměnnou, pokud to není nezbytně nutné. Pokud ho změníte v místním oboru, při ukončení tohoto oboru se vrátí k předchozí hodnotě.
Pokud používáte něco jako .NET přímo z funkce PowerShellu, nemůžete v samotném příkazu zadat parametr Error Action. Proměnnou $ErrorActionPreference
můžete změnit těsně před voláním metody .NET.
Nápověda založená na komentářích
Přidání nápovědy k funkcím se považuje za osvědčený postup. Pomoc umožňuje lidem, se kterými je sdílíte, vědět, jak je používat.
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: https://mikefrobbins.com
Twitter: @mikefrobbins
#>
[CmdletBinding()]
param (
)
#Function Body
}
Když do funkcí přidáte nápovědu založenou na komentářích, lze ji načíst stejně jako pomoc pro výchozí integrované příkazy.
Veškerá syntaxe pro psaní funkce v PowerShellu se může zdát ohromující pro začátečníka. Pokud si nepamatujete syntaxi něčeho, otevřete druhou instanci integrovaného skriptovacího prostředí PowerShellu (ISE) na samostatném monitoru a při psaní kódu pro vaše funkce si prohlédněte ukázku kódu "Cmdlet (pokročilá funkce) - Complete." Fragmenty kódu jsou přístupné v prostředí PowerShell ISE pomocí kombinace kláves Ctrl + J.
Shrnutí
V této kapitole jste se naučili základy psaní funkcí v PowerShellu, včetně postupu:
- Vytváření pokročilých funkcí
- Použijte ověření parametrů
- Použití podrobného výstupu
- Podpora vstupu kanálu
- Řešení chyb
- Vytvoření nápovědy založené na komentářích
Přezkoumání
- Jak v PowerShellu získáte seznam schválených sloves?
- Jak převést funkci PowerShellu na pokročilou funkci?
- Kdy byste měli přidat parametry WhatIf a Confirm do funkcí PowerShellu?
- Jak změníte neterminující chybu na ukončující chybu?
- Proč byste měli ke svým funkcím přidat nápovědu založenou na komentářích?