PowerShell-Funktionen meistern: Ein schrittweiser Leitfaden

Sobald Sie sich daran gewöhnt haben, PowerShell-Skripte zu schreiben, müssen Sie sich mit der Modularisierung des Codes vertraut machen. Modularisierung ist nur ein schicker Begriff für die Erstellung von Code in Bausteinen. In der PowerShell-Welt sind PowerShell-Funktionen eine der besten Möglichkeiten, dies zu tun.

Wenn Sie ein PowerShell-Skript schreiben, haben Sie viele Optionen, wie Sie den Code schreiben. Sie könnten tausend Zeilen Code schreiben, die Hunderte von Aufgaben erledigen, alles in einem einzigen, ununterbrochenen Codeblock. Das wäre eine Katastrophe. Stattdessen sollten Sie Funktionen schreiben.

Funktionen erhöhen die Benutzerfreundlichkeit und Lesbarkeit Ihres Codes erheblich und erleichtern die Arbeit damit. In diesem Tutorial lernen Sie, Funktionen zu schreiben, Funktionenparameter hinzuzufügen und zu verwalten und Funktionen so einzurichten, dass sie Pipeline-Eingaben akzeptieren. Aber zuerst werfen wir einen Blick auf ein paar Begriffe.

Dieser Beitrag wurde aus meinem Buch PowerShell für Sysadmins: Workflow-Automatisierung leicht gemacht entnommen. Wenn Sie in diesem Tutorial etwas lernen, sollten Sie unbedingt das Buch lesen, um mehr über Funktionen und viele weitere PowerShell-Leckereien zu erfahren.

Funktionen vs. Cmdlets

Das Konzept einer Funktion könnte Ihnen vertraut vorkommen, weil es ein wenig wie die Cmdlets klingt, die Sie wahrscheinlich bereits verwendet haben. Befehle wie Start-Service und Write-Host sind zum Beispiel ähnlich wie Funktionen. Dies sind benannte Code-Stücke, die ein einzelnes Problem lösen. Der Unterschied zwischen einer Funktion und einem Cmdlet besteht darin, wie diese Konstrukte erstellt werden.

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.

Auf der anderen Seite werden Funktionen in PowerShell geschrieben, nicht in einer anderen Sprache.

Sie können sehen, welche Befehle Cmdlets sind und welche Funktionen sind, indem Sie das Cmdlet Get-Command und seinen Parameter CommandType wie unten gezeigt verwenden

Get-Command –CommandType Function

Dieser Befehl gibt alle Funktionen zurück, die derzeit in Ihrer PowerShell-Sitzung geladen sind oder in Modulen, die für PowerShell verfügbar sind.

Verwandt: Verständnis und Erstellung von PowerShell-Modulen

Voraussetzungen

Wenn Sie alle Beispiele mitverfolgen möchten, stellen Sie bitte sicher, dass Sie eine Version von PowerShell zur Verfügung haben. Es gibt keine spezifischen Versionsanforderungen für dieses Tutorial. Stellen Sie außerdem sicher, dass Sie einen geeigneten Code-Editor wie Visual Studio Code haben, um Code-Snippets zu kopieren, einzufügen und auszuführen.

Erstellen einer einfachen Funktion

Bevor Sie eine Funktion verwenden können, müssen Sie sie definieren. Um eine Funktion zu definieren, verwenden Sie das Schlüsselwort „function“, gefolgt von einem beschreibenden, benutzerdefinierten Namen und einer Reihe geschweifter Klammern. Innerhalb der geschweiften Klammern befindet sich ein Skriptblock, das von PowerShell ausgeführt werden soll.

Unten sehen Sie eine grundlegende Funktion und die Ausführung dieser Funktion. Diese Funktion namens Install-Software verwendet Write-Host, um eine Nachricht in der Konsole anzuzeigen. Sobald sie definiert ist, können Sie den Namen dieser Funktion verwenden, um den Code innerhalb ihres Skriptblocks auszuführen.

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

Namensgebung mit Verb-Nomen

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.

Der Name einer Funktion sollte immer mit einem Verb gefolgt von einem Bindestrich und einem Nomen beginnen. Verwenden Sie das Cmdlet Get-Verb, um die Liste der „zugelassenen“ Verben zu finden.

Ändern des Funktionsverhaltens

Wenn Sie das Verhalten einer Funktion ändern möchten, können Sie einfach den Code ändern, den die Funktion ausführt, wie unten gezeigt.

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

Jetzt, da Sie den Code innerhalb der Funktion geändert haben, wird eine etwas andere Nachricht angezeigt.

Definition einer erweiterten Funktion

Sie können Funktionen an vielen verschiedenen Stellen definieren. In dem obigen Abschnitt geht das Tutorial davon aus, dass Sie den Code einfach direkt in die PowerShell-Konsole kopiert und eingefügt haben. Aber das ist nicht die einzige Möglichkeit. Sie können Funktionen auch in einem Skript definieren.

In dem vorherigen Abschnitt haben Sie mit einer kleinen Funktion gearbeitet, daher war es kein großes Problem, sie in der Konsole zu definieren. Meistens werden Sie jedoch viel größere Funktionen haben. Es ist einfacher, diese Funktionen in einem Skript oder einem Modul zu definieren und dann dieses Skript oder Modul aufzurufen, um die Funktion in den Speicher zu laden.

Wie Sie sich vielleicht vorstellen können, könnte es etwas frustrierend sein, eine größere Funktion jedes Mal neu einzutippen, wenn Sie ihre Funktionalität anpassen möchten.

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.

Hinzufügen von Parametern zu Funktionen

PowerShell-Funktionen können eine beliebige Anzahl von Parametern haben. Wenn Sie Ihre eigenen Funktionen erstellen, haben Sie die Möglichkeit, Parameter einzuschließen und zu entscheiden, wie diese Parameter funktionieren sollen. Die Parameter können obligatorisch oder optional sein und entweder alles akzeptieren oder dazu gezwungen werden, eine begrenzte Liste möglicher Argumente zu akzeptieren.

Verwandt: Alles, was Sie über PowerShell-Parameter wissen wollten

Zum Beispiel könnte die fiktive Software, die Sie über die Funktion Install-Software installieren, viele Versionen haben. Aber derzeit bietet die Funktion Install-Software dem Benutzer keine Möglichkeit, anzugeben, welche Version er installieren möchte.

Wenn Sie der einzige Benutzer der Funktion wären, könnten Sie den Code darin jedes Mal ändern, wenn Sie eine bestimmte Version möchten, aber das wäre Zeitverschwendung. Dieser Prozess wäre auch anfällig für potenzielle Fehler, ganz zu schweigen davon, dass Sie möchten, dass andere Ihren Code verwenden können.

Die Einführung von Parametern in Ihre Funktion ermöglicht es ihr, variabel zu sein. Genau wie Variablen es Ihnen ermöglichten, Skripte zu schreiben, die viele Versionen derselben Situation bewältigen konnten, ermöglichen Ihnen Parameter das Schreiben einer einzigen Funktion, die eine Sache auf viele Arten erledigt.

In diesem Fall möchten Sie, dass sie Versionen derselben Software installiert und dies auf vielen Computern tut.

Lassen Sie uns zunächst einen Parameter zur Funktion hinzufügen, der es Ihnen oder einem Benutzer ermöglicht, die zu installierende Version anzugeben.

Erstellen eines einfachen Parameters

Das Erstellen eines Parameters für eine Funktion erfordert einen param-Block. Der param-Block enthält alle Parameter für die Funktion. Definieren Sie einen param-Block mit dem Schlüsselwort param, gefolgt von Klammern, wie unten gezeigt.

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

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

An diesem Punkt hat sich die tatsächliche Funktionalität Ihrer Funktion nicht geändert. Sie haben lediglich die Rohrleitung installiert, um die Funktion für einen Parameter vorzubereiten.

Zu diesem Zeitpunkt installiert die Funktion tatsächlich keine Software. Sie verwendet nur das Cmdlet Write-Host, um die Softwareinstallation zu simulieren, damit Sie sich auf das Schreiben der Funktion konzentrieren können.

Nachdem Sie den param-Block hinzugefügt haben, können Sie den Parameter erstellen, indem Sie ihn innerhalb der Klammern des param-Blocks platzieren, wie unten gezeigt.

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

}

In dem oben gezeigten param-Block würden Sie zunächst den Parameterblock definieren. Durch Verwendung des Parameterblocks Parameter() wird er zu einem „erweiterten Parameter“. Ein leerer Parameterblock wie der hier hat keine Funktion, ist aber erforderlich. Ich werde erklären, wie man ihn im nächsten Abschnitt verwendet.

Lassen Sie uns stattdessen auf den [string]-Typ vor dem Parametername konzentrieren. Wenn Sie den Parametertyp zwischen eckigen Klammern vor dem Parametervariablennamen platzieren, wandeln Sie den Wert des Parameters in einen bestimmten Typ um. PowerShell versucht immer, jeden Wert, der diesem Parameter übergeben wird, in einen String zu konvertieren – sofern er nicht bereits einer ist. Oben wird alles, was als $Version übergeben wird, immer als String behandelt.

Das Umwandeln Ihres Parameters in einen Typ ist nicht zwingend erforderlich, aber ich empfehle es dringend. Es definiert explizit den Typ und reduziert Fehler erheblich.

Sie fügen auch $Version in Ihre Write-Host-Anweisung ein. Das bedeutet, dass Sie beim Ausführen der Funktion Install-Software mit dem Parameter Version und der Übergabe einer Versionsnummer eine entsprechende Anweisung erhalten sollten, wie unten gezeigt.

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

Lassen Sie uns nun sehen, was Sie mit diesem Parameter tun können.

Das obligatorische Parameterattribut

Sie können den Parameterblock verwenden, um verschiedene Parameterattribute zu steuern, mit denen Sie das Verhalten des Parameters ändern können. Wenn Sie beispielsweise sicherstellen möchten, dass jeder, der die Funktion aufruft, einen bestimmten Parameter übergeben muss, könnten Sie diesen Parameter als obligatorisch definieren.

Standardmäßig sind Parameter optional. Erzwingen wir das Übergeben einer Version, indem wir das Schlüsselwort „Mandatory“ innerhalb des Parameterblocks wie unten gezeigt verwenden.

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

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

}

Wenn Sie die obige Funktion ausführen, sollten Sie die folgende Aufforderung erhalten:

Prompting for a mandatory parameter

Sobald Sie das Attribut „Obligatorisch“ festgelegt haben, wird die Ausführung der Funktion ohne den Parameter gestoppt, bis der Benutzer einen Wert eingibt. Die Funktion wartet nun, bis der Benutzer einen Wert für den Parameter „Version“ angibt. Sobald dies erfolgt ist, führt PowerShell die Funktion aus.

Um die Abfrage des obligatorischen Parameters zu vermeiden, können Sie einfach einen Wert für den Parameter angeben, wenn Sie die Funktion aufrufen, wie im folgenden Beispiel gezeigt.

Install-Software -Version 2

Standardparameterwerte

Wenn Sie beispielsweise feststellen, dass Sie immer wieder denselben Wert für einen Parameter übergeben, können Sie einen Standardparameterwert festlegen. Standardparameter sind nützlich, wenn Sie einen bestimmten Wert für einen Parameter erwarten, die meiste Zeit.

Zum Beispiel, wenn Sie 90 Prozent der Zeit Version 2 dieser Software installieren möchten und den Wert nicht jedes Mal festlegen möchten, wenn Sie diese Funktion ausführen, können Sie einen Standardwert von 2 für den Parameter „$Version“ festlegen. Sie können dieses Beispiel unten sehen.

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

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

}

Das Vorhandensein eines Standardparameters hindert Sie nicht daran, einen eigenen Wert zu übergeben. Ihr übergebener Wert überschreibt den Standardwert.

Hinzufügen von Parametervalidierungsattributen

Es ist immer eine gute Idee, die Werte, die Sie über Parameter an eine Funktion übergeben können, einzuschränken. Die beste Möglichkeit, dies zu tun, sind Parametervalidierungsattribute.

Wenn Sie die Informationen begrenzen, die Benutzer (oder auch Sie selbst!) an Ihre Funktionen oder Skripte übergeben können, eliminieren Sie unnötigen Code innerhalb Ihrer Funktion. Angenommen, Sie übergeben den Wert 3 an Ihre Funktion „Install-Software“ und wissen, dass Version 3 eine vorhandene Version ist.

Ihre Funktion geht davon aus, dass jeder Benutzer weiß, welche Versionen existieren, daher berücksichtigt sie nicht, was passiert, wenn Sie Version 4 angeben möchten. In diesem Fall findet die Funktion den entsprechenden Ordner nicht, weil er nicht existiert.

Leben ohne Parametervalidierung

Schauen Sie sich das folgende Beispiel an, wenn Sie den String $Version in einem Dateipfad verwenden. Wenn jemand einen Wert übergibt, der keinen vorhandenen Ordnernamen vervollständigt (z.B. SoftwareV3 oder SoftwareV4), schlägt der Code fehl.

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

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

}
Failing on unexpected parameter values

Sie könnten Fehlerbehandlungscode schreiben, um dieses Problem zu berücksichtigen, oder Sie könnten das Problem von vornherein beheben, indem Sie verlangen, dass der Benutzer nur eine vorhandene Version der Software übergibt. Um die Eingabe des Benutzers einzuschränken, fügen Sie eine Parametervalidierung hinzu.

Hinzufügen der Parametervalidierung

Es gibt verschiedene Arten der Parametervalidierung, aber in Bezug auf Ihre Install-Software-Funktion funktioniert das [ValidateSet-Attribut](https://adamtheautomator.com/powershell-validateset/) am besten. Das ValidateSet-Validierungsattribut ermöglicht es Ihnen, eine Liste der für den Parameter zugelassenen Werte anzugeben. Wenn Sie nur die Zeichenfolge 1 oder 2 berücksichtigen, stellen Sie sicher, dass der Benutzer nur diese Werte angeben kann, sonst schlägt die Funktion sofort fehl und informiert den Benutzer darüber, warum.

Fügen Sie Parametervalidierungsattribute innerhalb des param-Blocks direkt unter dem ursprünglichen Parameter-Block wie unten gezeigt hinzu.

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

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

}

Durch das Hinzufügen einer Gruppe von Elementen (1 und 2) innerhalb der abschließenden Klammern des Attributs ValidateSet teilen wir PowerShell mit, dass die einzigen gültigen Werte für Version 1 oder 2 sind. Wenn ein Benutzer etwas anderes als das Set übergeben möchte, erhält er eine Fehlermeldung, die ihn darauf hinweist, dass er nur eine bestimmte Anzahl von Optionen hat.

Parameter validation stopping PowerShell function execution

Das Attribut ValidateSet ist ein häufig verwendetes Validierungsattribut, aber es gibt auch andere. Für eine vollständige Aufschlüsselung aller Möglichkeiten, wie Parameterwerte eingeschränkt werden können, schauen Sie sich die Microsoft-Dokumentation an.

Akzeptieren von Pipeline-Eingaben

Bisher haben Sie eine Funktion erstellt, bei der ein Parameter nur mit der typischen Syntax -ParameterName <Wert> übergeben werden kann. Dies funktioniert, aber Sie haben auch die Möglichkeit, Werte über die PowerShell-Pipeline an Parameter zu übergeben. Lassen Sie uns die Fähigkeit zur Verwendung der Pipeline zu unserer Install-Software-Funktion hinzufügen.

Verwandt: Akzeptieren von Pipeline-Eingaben im ATA PowerShell-Parameterartikel

Fügen Sie zunächst einen weiteren Parameter zu Ihrem Code hinzu, der den Computer angibt, auf dem Sie die Software installieren möchten. Fügen Sie diesen Parameter auch zu Ihrer Write-Host-Referenz hinzu, um die Installation zu simulieren.

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!"

}

Nachdem Sie den ComputerName-Parameter zur Funktion hinzugefügt haben, können Sie nun über eine Liste von Computernamen iterieren und die Werte für den Computernamen und die Version an die Install-Software-Funktion übergeben, wie unten gezeigt.

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

Anstatt das alles zu tun, sollten Sie lernen, die Pipeline zu verwenden.

Funktion pipeline-kompatibel machen

Leider können Sie mit einer einfachen zuvor erstellten Funktion nicht von der PowerShell-Pipeline profitieren. Sie müssen sich entscheiden, welche Art von Pipeline-Eingabe die Funktion akzeptieren soll und diese implementieren.

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.

Um die Pipeline-Unterstützung hinzuzufügen, fügen Sie dem Parameter, den Sie möchten, ein Parameterattribut hinzu, indem Sie eines von zwei Schlüsselwörtern verwenden: ValueFromPipeline oder ValueFromPipelineByPropertyName, wie unten gezeigt.

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!"

}

Sobald Sie die aktualisierte Install-Software-Funktion geladen haben, rufen Sie sie wie folgt auf:

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

Führen Sie das Skript erneut aus und Sie sollten etwas Ähnliches erhalten:

I installed software version 2 on SRV3. Yippee!

Bemerken Sie, dass Install-Software nur für den letzten String im Array ausgeführt wird. Sie werden sehen, wie Sie dies im nächsten Abschnitt beheben können.

Hinzufügen eines Prozessblocks

Um PowerShell mitzuteilen, diese Funktion für jedes eingehende Objekt auszuführen, müssen Sie einen Prozessblock einfügen. Platzieren Sie den Code, den Sie jedes Mal ausführen möchten, wenn die Funktion Eingabe über die Pipeline empfängt, innerhalb des Prozessblocks. Fügen Sie Ihrem Skript einen Prozessblock wie unten gezeigt hinzu.

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!"
	}
}

Rufen Sie die Funktion jetzt erneut auf, genau wie zuvor. Die Funktion Install-Software gibt nun drei Zeilen zurück (eine für jedes Objekt).

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

Der Prozessblock enthält den Hauptcode, den Sie ausführen möchten. Sie können auch begin– und end-Blöcke verwenden, um Code auszuführen, der am Anfang und Ende des Funktionsaufrufs ausgeführt wird. Weitere Informationen zu den Blöcken begin, process und end finden Sie in der Microsoft-Dokumentation

Nächste Schritte

Funktionen ermöglichen es Ihnen, Code in diskrete Bausteine aufzuteilen. Sie helfen Ihnen nicht nur, Ihre Arbeit in kleinere, überschaubare Teile zu zerlegen, sondern zwingen Sie auch dazu, lesbaren und testbaren Code zu schreiben.

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/