Beheersing van PowerShell-functies: Een Stapsgewijze Gids

Eenmaal gewend aan het schrijven van PowerShell-scripts, moet je leren over code-modularisatie. Modularisatie is gewoon een chique woord voor het creëren van code in bouwstenen. In de wereld van PowerShell zijn PowerShell-functies een van de beste manieren om dit te doen.

Als je een PowerShell-script schrijft, heb je veel opties voor het schrijven van de code. Je zou duizenden regels code kunnen schrijven die honderden taken uitvoeren, allemaal in een enkel, ononderbroken blok code. Dat zou een ramp zijn. In plaats daarvan zou je functies moeten schrijven.

Functies verhogen aanzienlijk de bruikbaarheid en leesbaarheid van je code, waardoor het veel gemakkelijker wordt om ermee te werken. In deze tutorial leer je functies schrijven, parameters toevoegen en beheren, en functies instellen om invoer vanuit de pipeline te accepteren. Maar laten we eerst naar wat terminologie kijken.

Deze post is geëxtraheerd uit mijn boek PowerShell voor systeembeheerders: Eenvoudige automatisering van workflows. Als je iets leert in deze tutorial, zorg er dan voor dat je het boek bekijkt om meer te leren over functies en allerlei andere PowerShell-goodies.

Functies vs. Cmdlets

Het concept van een functie klinkt misschien bekend omdat het een beetje lijkt op de cmdlets die je waarschijnlijk al hebt gebruikt. Opdrachten zoals Start-Service en Write-Host, bijvoorbeeld, zijn vergelijkbaar met functies. Dit zijn benoemde stukjes code die een enkel probleem oplossen. Het verschil tussen een functie en een cmdlet is hoe elk van deze constructies is gemaakt.

A cmdlet isn’t written with PowerShell. It’s written in another language, typically something like C#. The cmdlet is then compiled and made available inside PowerShell.

Functies daarentegen zijn geschreven in PowerShell; niet in een andere taal.

Je kunt zien welke opdrachten cmdlets zijn en welke functies zijn door de Get-Command cmdlet te gebruiken en zijn CommandType-parameter zoals hieronder getoond

Get-Command –CommandType Function

Deze opdracht hierboven retourneert alle functies die momenteel geladen zijn in je PowerShell-sessie, of binnen modules die beschikbaar zijn voor PowerShell.

Gerelateerd: Begrijpen en bouwen van PowerShell-modules

Vereisten

Als je alle voorbeelden wilt volgen, zorg er dan voor dat je een versie van PowerShell beschikbaar hebt. Er zijn geen specifieke versievereisten voor deze tutorial. Zorg er ook voor dat je een goede code-editor hebt zoals Visual Studio Code om wat codefragmenten te kopiëren, plakken en uit te voeren.

Het bouwen van een eenvoudige functie

Voordat je een functie kunt gebruiken, moet je deze definiëren. Om een functie te definiëren, gebruik je het sleutelwoord “function”, gevolgd door een beschrijvende, door de gebruiker gedefinieerde naam, gevolgd door een set accolades. Binnen de accolades bevindt zich een scriptblok dat je wilt dat PowerShell uitvoert.

Hieronder zie je een eenvoudige functie en hoe je die functie uitvoert. Deze functie, genaamd Install-Software, gebruikt Write-Host om een bericht weer te geven in de console. Eenmaal gedefinieerd, kun je de naam van deze functie gebruiken om de code binnen zijn scriptblok uit te voeren.

PS> function Install-Software { Write-Host 'I installed some software. Yippee!' }
PS> Install-Software
I installed some software, Yippee!

Naamgeving met Werkwoord-Zelfstandig Naamwoord

A function’s name is important. You can name your functions whatever you want, but the name should always describe what the function does. The function-naming convention in PowerShell is the Verb-Noun syntax.

Je moet altijd een functienaam beginnen met een werkwoord gevolgd door een streepje en een zelfstandig naamwoord. Gebruik de Get-Verb cmdlet om de lijst met “goedgekeurde” werkwoorden te vinden.

Wijzigen van Functiegedrag

Als je het gedrag van een functie wilt wijzigen, kun je eenvoudig de code wijzigen die de functie uitvoert, zoals hieronder wordt getoond.

PS> function Install-Software { Write-Host 'You installed some software, Yay!' }
PS> Install-Software
You installed some software, Yay!

Nu je de code binnen de functie hebt gewijzigd, wordt er een iets ander bericht weergegeven.

Het definiëren van een Geavanceerde Functie

Je kunt functies op veel verschillende plaatsen definiëren. In het bovenstaande gedeelte gaat de tutorial ervan uit dat je de code rechtstreeks in de PowerShell-console hebt gekopieerd en geplakt. Maar dit is niet de enige manier. Je kunt functies ook definiëren in een script.

In het vorige gedeelte werkte je met een kleine functie, dus het definiëren ervan in de console was niet echt een probleem. Meestal zul je echter veel grotere functies hebben. Het is handiger om die functies in een script of een module te definiëren en vervolgens dat script of die module aan te roepen om de functie in het geheugen te laden.

Zoals je je kunt voorstellen, kan het opnieuw typen van een grotere functie telkens wanneer je de functionaliteit ervan wilt aanpassen een beetje frustrerend worden.

I suggest you now open your favorite editor and store the function in a .ps1 file as you work through the rest of the tutorial.

Parameters toevoegen aan Functies

PowerShell-functies kunnen een willekeurig aantal parameters hebben. Wanneer je je eigen functies maakt, heb je de mogelijkheid om parameters op te nemen en te beslissen hoe die parameters werken. De parameters kunnen verplicht of optioneel zijn, en ze kunnen alles accepteren of gedwongen worden om een van een beperkte lijst met mogelijke argumenten te accepteren.

Gerelateerd: Alles wat je ooit wilde weten over PowerShell-parameters

Bijvoorbeeld, de fictieve software die je installeert via de Install-Software-functie kan vele versies hebben. Maar momenteel biedt de Install-Software-functie een gebruiker geen manier om aan te geven welke versie ze willen installeren.

Als je de enige bent die de functie gebruikt, zou je de code erin telkens kunnen wijzigen wanneer je een specifieke versie wilt, maar dat zou verspilling van tijd zijn. Dit proces zou ook gevoelig zijn voor mogelijke fouten, om nog maar te zwijgen van het feit dat je wilt dat anderen je code kunnen gebruiken.

Het introduceren van parameters in je functie maakt het mogelijk om variabiliteit te hebben. Net zoals variabelen je in staat stelden scripts te schrijven die veel versies van dezelfde situatie konden afhandelen, stellen parameters je in staat om een enkele functie te schrijven die één ding op vele manieren doet.

In dit geval wil je verschillende versies van dezelfde software installeren, en dit doen op veel computers.

Laten we eerst een parameter toevoegen aan de functie waarmee jij of een gebruiker de te installeren versie kan specificeren.

Het maken van een eenvoudige parameter

Het maken van een parameter voor een functie vereist een param-blok. Het param-blok bevat alle parameters voor de functie. Definieer een param-blok met het param-trefwoord gevolgd door haakjes zoals hieronder weergegeven.

function Install-Software {
	[CmdletBinding()]
	param()

	Write-Host 'I installed software version 2. Yippee!'
}

Op dit punt is de daadwerkelijke functionaliteit van je functie niet veranderd. Je hebt alleen de basis gelegd, waardoor de functie gereed is voor een parameter.

Op dit moment installeert de functie eigenlijk geen software. Het gebruikt alleen de Write-Host-cmdlet om de software-installatie te simuleren, zodat je je kunt richten op het schrijven van de functie.

Nadat je het param-blok hebt toegevoegd, kun je de parameter maken door deze binnen de haakjes van het param-blok te plaatsen zoals hieronder weergegeven.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string] $Version
	)
	
	Write-Host "I installed software version $Version. Yippee!"

}

Binnen het hierboven getoonde param-blok zou je eerst het Parameter-blok definiëren. Door het Parameter()-blok op deze manier te gebruiken, wordt het een “geavanceerde parameter”. Een leeg Parameter-blok zoals dit doet niets, maar is vereist; ik zal uitleggen hoe je het in de volgende sectie kunt gebruiken.

Laten we ons in plaats daarvan richten op het [string] type voor de parameter naam. Door het type van de parameter tussen vierkante haken te plaatsen vóór de variabele naam van de parameter, zet je de waarde van de parameter om naar een specifiek type. PowerShell zal altijd proberen om elke waarde die aan deze parameter wordt doorgegeven om te zetten naar een string – als het dat nog niet is. Bovenstaand zal alles wat wordt doorgegeven als $Versie altijd worden behandeld als een string.

Het casten van je parameter naar een type is niet verplicht, maar ik moedig het sterk aan. Het definieert expliciet het type en zal fouten aanzienlijk verminderen in de toekomst.

Je voegt ook $Versie toe aan je Write-Host statement nu. Dit betekent dat wanneer je de Install-Software functie uitvoert met de Versie parameter en er een versienummer aan doorgeeft, je een statement zou moeten krijgen zoals hieronder getoond.

PS> Install-Software -Version 2
I installed software version 2. Yippee!

Laten we eens kijken wat je nu met deze parameter kunt doen.

De Verplichte Parameter Attribuut

Je kunt het Parameter blok gebruiken om verschillende parameter attributen te controleren, waardoor je het gedrag van de parameter kunt veranderen. Als je bijvoorbeeld wilt zorgen dat iedereen die de functie aanroept een bepaalde parameter moet doorgeven, dan zou je die parameter als Verplicht kunnen definiëren.

Standaard zijn parameters optioneel. Laten we de gebruiker dwingen om een versie door te geven door het gebruik van het Verplichte trefwoord binnen het Parameter blok zoals hieronder getoond.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Write-Host "I installed software version $Version. Yippee!"

}

Als je de bovenstaande functie uitvoert, zou je het volgende prompt moeten krijgen:

Prompting for a mandatory parameter

Zodra u het Verplichte attribuut hebt ingesteld, zal het uitvoeren van de functie zonder de parameter de uitvoering stoppen totdat de gebruiker een waarde invoert. De functie wacht nu tot de gebruiker een waarde opgeeft voor de parameter Versie. Zodra ingevoerd, voert PowerShell de functie uit.

Om de prompt voor de verplichte parameter te vermijden, geeft u eenvoudigweg een waarde door aan de parameter bij het aanroepen van de functie zoals hieronder wordt getoond.

Install-Software -Version 2

Standaardparameterwaarden

Als u bijvoorbeeld merkt dat u steeds weer dezelfde waarde voor een parameter doorgeeft, kunt u een standaardparameterwaarde definiëren. Standaardparameters zijn handig wanneer u de meeste tijd een bepaalde waarde voor een parameter verwacht.

Bijvoorbeeld, als u 90 procent van de tijd versie 2 van deze software wilt installeren, en u niet telkens de waarde wilt instellen wanneer u deze functie uitvoert, kunt u een standaardwaarde van 2 toewijzen aan de parameter $Versie. U kunt dit voorbeeld hieronder zien.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string]$Version = 2
	)

	Write-Host "I installed software version $Version. Yippee!"

}

Het hebben van een standaardparameter voorkomt niet dat u er een doorgeeft. Uw doorgegeven waarde zal de standaardwaarde overschrijven.

Parametervalidatieattributen toevoegen

Het is altijd een goed idee om te beperken welke waarden u via parameters aan een functie kunt doorgeven. De beste manier om dat te doen is met parametervalidatieattributen.

Het beperken van de informatie die gebruikers (of zelfs u!) aan uw functies of scripts kunnen doorgeven, zal onnodige code binnen uw functie elimineren. Stel bijvoorbeeld dat u de waarde 3 doorgeeft aan uw Install-Software-functie, wetende dat versie 3 een bestaande versie is.

Je functie gaat ervan uit dat elke gebruiker weet welke versies bestaan, dus het houdt geen rekening met wat er gebeurt wanneer je probeert versie 4 te specificeren. In dat geval zal de functie niet de juiste map kunnen vinden omdat deze niet bestaat.

Leven Zonder Parametervalidatie

Bekijk het onderstaande voorbeeld wanneer je de $Version-string gebruikt in een bestandspad. Als iemand een waarde doorgeeft die geen bestaande mapnaam voltooit (bijvoorbeeld SoftwareV3 of SoftwareV4), zal de code falen.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}
Failing on unexpected parameter values

Je zou foutafhandelingscode kunnen schrijven om dit probleem aan te pakken, of je zou het probleem meteen kunnen oplossen door te eisen dat de gebruiker alleen een bestaande versie van de software doorgeeft. Om de invoer van de gebruiker te beperken, voeg je parametervalidatie toe.

Parametervalidatie Toevoegen

Er bestaan verschillende soorten parametervalidatie, maar met betrekking tot jouw Install-Software-functie werkt de [ValidateSet-attribuut](https://adamtheautomator.com/powershell-validateset/) het beste. Het ValidateSet-validatieattribuut stelt je in staat om een lijst van toegestane waarden voor de parameter op te geven. Als je alleen rekening houdt met de string 1 of 2, zorg er dan voor dat de gebruiker alleen deze waarden kan specificeren; anders zal de functie onmiddellijk falen en de gebruiker op de hoogte stellen van de reden waarom.

Voeg parametervalidatieattributen toe binnen het param-blok, direct onder het oorspronkelijke Parameter-blok zoals hieronder weergegeven.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}

Door een reeks items (1 en 2) toe te voegen binnen de haakjes aan het einde van het ValidateSet-attribuut, vertelt dit aan PowerShell dat de enige geldige waarden voor Version 1 of 2 zijn. Als een gebruiker iets probeert door te geven dat niet in de set zit, ontvangt hij een foutmelding zoals hieronder weergegeven, waarin staat dat er slechts een specifiek aantal opties beschikbaar is.

Parameter validation stopping PowerShell function execution

Het ValidateSet-attribuut is een veelvoorkomend validatieattribuut, maar er zijn ook andere beschikbaar. Voor een volledige uiteenzetting van alle manieren waarop parameterwaarden beperkt kunnen worden, bekijk de Microsoft-documentatie.

Accepteren van invoer via de pipeline

Tot nu toe heb je een functie gemaakt met een parameter die alleen kan worden doorgegeven via de gebruikelijke syntaxis -ParameterNaam <Waarde>. Dit werkt, maar je hebt ook nog een andere optie om waarden aan parameters door te geven via de PowerShell-pijplijn. Laten we mogelijkheden voor de pijplijn toevoegen aan onze Install-Software functie.

Gerelateerd: Accepteren van invoer via de pijplijn in het ATA PowerShell Parameters-artikel

Eerst voegt u een andere parameter toe aan uw code die aangeeft op welke computer u de software wilt installeren. Voeg ook die parameter toe aan uw referentie van Write-Host om de installatie te simuleren.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
		[ValidateSet('1','2')],
		
		[Parameter(Mandatory)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

Zodra u de ComputerName-parameter aan de functie hebt toegevoegd, kunt u nu itereren over een lijst met computernamen en de waarden voor de computernaam en de versie doorgeven aan de Install-Software-functie, zoals hieronder.

$computers = @("SRV1", "SRV2", "SRV3")
foreach ($pc in $computers) {
	Install-Software -Version 2 -ComputerName $pc
}

In plaats van dit alles te doen, zou u moeten leren de pijplijn te gebruiken.

Maak de Functie Pijplijncompatibel

Helaas kunt u met alleen een eenvoudige eerder gebouwde functie geen gebruik maken van de PowerShell-pijplijn. U moet beslissen welk type pijplijninvoer u wilt accepteren en implementeren.

A PowerShell function uses two kinds of pipeline input: ByValue (entire object) and ByPropertyName (a single object property). Here, because the $computers array contains only strings, you’ll pass those strings via ByValue.

Om pijplijnondersteuning toe te voegen, voegt u een parameterattribuut toe aan de parameter die u wilt door het gebruik van een van de twee trefwoorden: ValueFromPipeline of ValueFromPipelineByPropertyName zoals hieronder weergegeven.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

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

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

Zodra u de bijgewerkte Install-Software-functie hebt geladen, belt u deze als volgt aan:

$computers = @("SRV1", "SRV2", "SRV3")
$computers | Install-Software -Version 2

Voer het script opnieuw uit, en u zou zoiets moeten krijgen:

I installed software version 2 on SRV3. Yippee!

Merk op dat Install-Software alleen wordt uitgevoerd voor de laatste tekenreeks in de array. U zult zien hoe u dit kunt oplossen in de volgende sectie.

Het Toevoegen van een Process Block

Om PowerShell te vertellen deze functie uit te voeren voor elk object dat binnenkomt, moet je een procesblok opnemen. Binnen het procesblok plaats je de code die je wilt uitvoeren telkens wanneer de functie pijplijninvoer ontvangt. Voeg een procesblok toe aan je script zoals hieronder getoond.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

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

	process {
		Write-Host "I installed software version $Version on $ComputerName. Yippee!"
	}
}

Roep nu de functie opnieuw aan zoals je eerder hebt gedaan. De functie Install-Software zal nu drie regels retourneren (één voor elk object).

I installed software version 2 on SRV1. Yippee!
I installed software version 2 on SRV2. Yippee!
I installed software version 2 on SRV3. Yippee!

Het procesblok bevat de hoofdcode die je wilt uitvoeren. Je kunt ook begin– en end-blokken gebruiken voor code die aan het begin en het einde van de functie-oproep zal worden uitgevoerd. Je kunt meer leren over de begin-, process– en end-blokken via de Microsoft-documentatie.

Volgende stappen

Functies stellen je in staat om code op te delen in discrete bouwstenen. Ze helpen je niet alleen om je werk op te splitsen in kleinere, meer beheersbare brokken, maar dwingen je ook om leesbare en testbare code te schrijven.

I now challenge you to look through some old scripts and see where you can add a PowerShell function. Look for patterns in code. Build a function from those patterns. Notice where you’re copying/pasting code snippets and turn those into PowerShell functions!

Source:
https://adamtheautomator.com/powershell-functions/