Ideale Aufbau einer PowerShell-Script-Datei
9 Schritte zum perfekten PowerShell-Script
Ideale Aufbau einer PowerShell-Script-Datei

PowerShell Scripting Language (.PS1 und PSM1)

Die PowerShell Scripting Language ist eine dynamisch typisierte Skriptsprache, um Skripte für die PowerShell Engine zu entwickeln. Mit einem PowerShell Script können eigene Cmdlets erstellt werden. Die Skriptsprache unter stützt objektorientierte Programmierung (OOP) und somit das Implementieren von Klassen. Scripte haben die Dateiendung .PS1 oder für Scripte die beim Laden eines PowerShell Moduls ausgeführt werden die Erweiterung .PSM1. Beide Dateien gehören zu den ausführbaren Dateien und unterliegen den Ausführungsrichtlinien (Execution Policy).

Die Skriptsprache (PowerShell Scripting Language) unterstützt Variablen, Funktionen, Verzweigungen, Schleifen, strukturierte Fehler- / Ausnahmebehandlung, Lambda-Ausdrücke und die Integration von .NET. Variablen in PowerShell-Skripten wird $ vorangestellt. Variablen kann ein beliebiger Wert oder Objekt zugewiesen werden. Zeichenfolgen können entweder in einfache Anführungszeichen oder in doppelte Anführungszeichen eingeschlossen werden. Bei Verwendung doppelter Anführungszeichen werden Variablen im String aufgelöst.

Unter Verwendung des function Schlüsselworts ermöglicht PowerShell die Erstellung von Funktionen in der folgenden EINFACHEN Form:

function name ([string]$para1, [string]$para2)
{
    $result = "Wert1: $para1 und Wert2: $para2"
    return $result
}

Weitere Einblicke in PowerShell Scripting Language finden Sie in den öffentlich zugänglichen Büchern PowerShell in Depth, Chapter 19. PowerShell’s scripting language und Learn PowerShell Toolmaking in a Month of Lunches, Chapter 3. PowerShell’s scripting language.

Es wurde Wert darauf gelegt die Syntax der PowerShell-Skriptsprache einfach zu halten. Aber behalten Sie trotzdem immer das Thema Sicherheit in und an skripten im Auge:

Wissen vom Trainer mit vielen praxisbezogenen Übungen, Wissenstests und Frage und Antwort-Runden. Jetzt in meinen PowerShell-Seminaren und -Workshops.

VSCode-Screenshot, 9 Schritte zum perfekten PowerShell Script (.PS1, .PSM1)

Welche Elemente gehören in einer PowerShell Script-Datei, was ist sinnvoll und welche Reihenfolge soll eingehalten werden? Die Antwort auf diese Fragen erhalten Sie hier in 8 kompakten Schritten.

1. Module und Namensräume importieren

Diese Modul-Liste ist für Dritte eine Übersicht der benötigten und damit zu installierenden Module. Im Grunde ist using Module identisch mit Import-Module -Name ...

using Module Microsoft.PowerShell.Management
using Module Microsoft.PowerShell.Utility

Als nächstes werden benötigte Namespace bekannt gemacht, um den Zugriff auf Typen zu erleichtern und die Lesbarkeit zu erhöhen. Anstelle [System.Management.Automation.ActionPreference]::Stop kann nun [ActionPreference]::Stop geschrieben werden.

using namespace System.Management.Automation
using namespace System.Windows.Forms

2. Laufzeitverhalten festlegen

Die Skript-Verarbeitung (.PS1 & .PSM1) sollte beim ersten auftretenden Fehler (Exception) abbrechen [ActionPreference]::Stop und nicht fehlerhaft weiterlaufen (Standard ist Continue), um so einen Schaden auf minimum zu beschränken. Sollte das Skript (.PS1 & .PSM1) im aktuellen Kontext laufen, sichern wir vorher die aktuelle Einstellung, um sie zum Schluss wiederherstellen zu können.

$backupErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = [ActionPreference]::Stop

Vor der ersten Verwendung der Variable $sume -eq 99 muss $summe nicht explizit deklariert werden, das Ergeb-nis wäre $false. Ärgerlich ist, das nicht erkennen von Schreibfehler wie $sume anstelle $summe. Diese Anweisung sorgt dafür, das Variablen vor der ersten Verwendung einen Wert zugewiesen bekommen. Ist dies nicht der Fall wird eine Ausnahme ausgelöst.

Set-StrictMode -Version 'Latest'

3. .NET-Assemblies laden

Um Ressourcen zu schonen, sind nur die gebräuchlisten Assemblies sind geladen. Darüber hinaus (z.B. WinForms und WPF) muss manuell nachgeladen werden.

Add-Type -AssemblyName 'System.Windows.Forms'

Welches Assemblies bereits geladen wurden erfahren Sie über:

[AppDomain]::CurrentDomain.GetAssemblies() | Sort-Object -Property FullName | Select-Object -Property FullName

4. PowerShell Script-Übergabe-Parameter definieren

Diese Script-Datei (.PS1) könnte wie folgt mit Parametern aufgerufen werden.

MyScript.ps1 -Path x:\wtf -BenutzerId 47110815

OPTIONAL - Sind Parameter nicht nötigt, so entfällt dieser Punkt.

Um dies zu realisieren muss der folgende Block hinzugefügt werden.

param (
    [string]$Path,
    [int]$BenutzerId
)

5. Funktions-Definitionen implementieren

Vor dem ersten Aufruf einer Funktion muss derer function-Definition stehen.

OPTIONAL - Werden keine eigenen Funktionen benötigt entfällt dieser Block.

function Invoke-Irgendwas {
    param ([string]$Stadtname)
    $Stadtname
}

6. Business-Logik implementieren

Ab jetzt kommt der eigentliche Code, der Ihrem Skript den Sinn gibt.

$prozesse = Get-Process
foreach($p in $prozesse) {
    $prozessname = $p.Name
    if($prozessname -eq "notepad") {
        $p.Kill()
    }
}

$fenster = New-Object -TypeName Form
$fenster.ShowDialog()

Invoke-Irgendwas -Stadtname Köln

7. Aufräumen

Zum Schluss wird so aufgeräumt das Spuren, außer unser Skript-Ziel bleiben.

Remove-Variable -Name prozesse, prozessname, p, fenster -Force
Remove-Item -Path function:\Invoke-Irgendwas -Force
Set-StrictMode -Off
$ErrorActionPreference = $backupErrorActionPreference
Remove-Module -Name Module Microsoft.PowerShell.Utility -Force
Remove-Module -Name Microsoft.PowerShell.Management -Force

8. Digitale Signatur

Mit dem letzten Schritt können wir unser Skript (.PS1 & .PSM1) mit einer digitalen Signatur vor Veränderung schützen.

OPTIONAL - Eine digitale Signatur ist nur nötigt, wenn die Ausführungsrichtlinien ExecutionPolicy auf AllSigned stehen.

# SIG # Begin signature block
# MIIkBwYJKoZIhvcNAQcCoIIj+DCCI/QCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# ...
# Dg4zxvPhyyMhIuS/Rz2KOG8Ly6rTmGC1C5VxdjpP96xuhz6IefLKVxRZqZQNRJ25
# oCid85NU8LI2+rA=
# SIG # End signature block

Epilog

Zum Schluss überprüfen Sie das PowerShell Script noch mittels der folgenden Punkte.

  1. Im PowerShell Script dürfen keine Aliase verwendet werden - Diese könnten sich ändern oder in einer späteren Version wegfallen.
  2. Wenden Sie Invoke-ScriptAnalyzer -Path .\MeinSkript.ps1 auf Ihr PowerShell Script an, um schwachstellen zu finden und Code smell zu vermeiden.
  3. Sie können PowerShell Scripte und Code-Blöcke per Invoke-Formatter -Settings CodeFormattingAllman -ScriptDefinition (Get-Clipboard -Raw) formatieren - So schauen alle immer gleich aus.

Für Ihre PowerShell Script-Vorlagen können Sie sich, ohne Erklärungen den folgenden Block kopieren.

## 1. Module und Namensräume importieren

using Module Microsoft.PowerShell.Management
using Module Microsoft.PowerShell.Utility
using namespace System.Management.Automation
using namespace System.Windows.Forms

## 2. Laufzeitverhalten festlegen

$backupErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = [ActionPreference]::Stop
Set-StrictMode -Version 'Latest'

## 3. .NET-Assemblies laden

Add-Type -AssemblyName 'System.Windows.Forms'

## 4. PowerShell Script-Übergabe-Parameter definieren

param (
    [string]$Path,
    [int]$BenutzerId
)

## 5. Funktions-Definitionen implementieren

function Invoke-Irgendwas {
    param ([string]$Stadtname)
    $Stadtname
}

## 6. Business-Logik implementieren

$prozesse = Get-Process
foreach($p in $prozesse) {
    $prozessname = $p.Name
    if($prozessname -eq "notepad") {
        $p.Kill()
    }
}
$fenster = New-Object -TypeName Form
$fenster.ShowDialog()
Invoke-Irgendwas -Stadtname Köln

## 7. Aufräumen

Remove-Variable -Name prozesse, prozessname, p, fenster -Force
Remove-Item -Path function:\Invoke-Irgendwas -Force
Set-StrictMode -Off
$ErrorActionPreference = $backupErrorActionPreference
Remove-Module -Name Module Microsoft.PowerShell.Utility -Force
Remove-Module -Name Microsoft.PowerShell.Management -Force

## 8. Digitale Signatur

# SIG # Begin signature block
# MIIkBwYJKoZIhvcNAQcCoIIj+DCCI/QCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# ...
# Dg4zxvPhyyMhIuS/Rz2KOG8Ly6rTmGC1C5VxdjpP96xuhz6IefLKVxRZqZQNRJ25
# oCid85NU8LI2+rA=
# SIG # End signature block

Bitte bewerten Sie diesen Artikel


Schreibe einen Kommentar