Aufgaben mit PowerShell PSake automatisieren: Eine Anleitung

Sie haben also gelernt, wie man Aufgaben mit einem PowerShell-Skript automatisiert. Das ist großartig! Aber jetzt haben Sie ein durcheinandergebrachtes Durcheinander von Skripten und Modulen mit einer Mischung aus manuellen Skriptausführungen, geplanten Aufgaben und mehr. Es ist Zeit, etwas Ordnung in das Chaos zu bringen und den Automatisierungs-Orchestrierungsmechanismus namens PowerShell PSake einzusetzen.

PSake ist ein als PowerShell-Modul geschriebener Orchestrierungsmechanismus, der Ihren Skripten Struktur verleiht und Ihnen die volle Kontrolle darüber gibt, was wann und unter welchen Bedingungen ausgeführt wird. Obwohl PSake ein Build-Automatisierungstool ist und sein Hauptanwendungsfall in Build-Skripten liegt (die normalerweise von einem Build-Server in Release-Automatisierungsszenarien ausgeführt werden), wird es im täglichen Skripting meist übersehen. Das wollen wir ändern.

In diesem Tutorial lernen Sie, wie PSake funktioniert, zusammen mit einigen großartigen Beispielen, die Sie noch heute in die Praxis umsetzen können!

Voraussetzungen

In diesem Artikel wird ein Tutorial erwartet, bei dem Sie Schritt für Schritt mitmachen. Wenn Sie genau wie hier beschrieben vorgehen möchten, stellen Sie sicher, dass Sie Folgendes haben:

  • Windows PowerShell 3+. Das Tutorial verwendet Windows PowerShell v5.1
  • Die PSake-Zip-Datei von Github. Dieses Tutorial verwendet v4.9.0.

Einrichten des PSake-Moduls

Angenommen, Sie haben das PSake-Projekt von GitHub auf Ihrem lokalen Computer, müssen Sie zuerst einige Schritte ausführen, um es einzurichten.

  1. Entpacken Sie die PSake-Zip-Datei, die von GitHub heruntergeladen wurde.
  2. Verschieben Sie den Ordner src in den extrahierten ZIP-Dateiinhalt an einen Pfad unter $env:PSModulePath, um sicherzustellen, dass PowerShell von dem neuen Modul weiß.
  3. Benennen Sie den Ordner src in PSake um.
  4. Führen Sie nun Get-Module PSake -ListAvailable aus, um zu bestätigen, dass es angezeigt wird. Wenn Sie keine Fehlermeldung erhalten, können Sie fortfahren.

Verwandt: Verständnis und Erstellung von PowerShell-Modulen

Erstellen eines grundlegenden PowerShell-PSake-Skripts

Um PSake zu verstehen, müssen Sie etwas erstellen. Erstellen wir ein einfaches PSake-Skript, um zu sehen, was es kann.

  1. Erstellen Sie ein Skript mit dem Namen psakefile.ps1 mit einer einzigen Aufgabe. Eine Aufgabe sollte mindestens einen Namen und einen Aktionsblock haben. Der Name psakefile.ps1 ist nicht zwingend erforderlich, wird jedoch vom System erwartet.

A PSake task in its basic form is very similar to a PowerShell function:
a container for one or more commands that, when performed together, achieve a certain goal. These commands go into a script block that is passed to the Action parameter. A task has many advantages over a function. You will learn about these advantages as you read along.

Nachfolgend finden Sie ein Beispiel für eine psakefile.ps1 mit einer relativ einfachen Aufgabe:

task HelloWorld -Action {
    Write-Host '*** Hello World ***' -ForegroundColor Yellow
}

2. Nachdem Sie die PSake-Datei erstellt haben, können Sie sie über die PowerShell-Konsole mit dem Befehl Invoke-PSake aufrufen und den Aufgabennamen als Wert für den Parameter TaskList übergeben.

Invoke-PSake ist der Ausführungsmotor für PSake. Dieser Befehl löst Aufgaben aus, die in der Datei psakefile.ps1 definiert sind. Sie geben einen Aufgabennamen oder eine Liste von durch Kommas getrennten Aufgaben an den TaskList-Parameter weiter. Wenn Sie mehrere Aufgaben ausführen, werden sie in der Reihenfolge ausgeführt, in der Sie sie an den TaskList-Parameter übergeben haben, unabhängig von ihrer Position in der Datei psakefile.ps1.

Unten sehen Sie, wie Sie die Aufgabe HelloWorld auslösen können:

Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList 'HelloWorld'

Solange Sie den Namen psakefile.ps1 beibehalten und die Konsole auf den Ordner eingestellt haben, in dem er sich befindet, können Sie den BuildFile-Parameter und seinen Wert weglassen.

  1. Wenn Sie Invoke-PSake ausführen, wird die PSake-Ausgabe in der Konsole angezeigt. Wenn Sie die Aufgaben in psakefile.ps1 ausführen, sehen Sie eine Ausgabe ähnlich wie die untenstehende.
Psake script output

Die Ausgabe besteht aus folgenden Komponenten:

  1. Die Details zur PSake-Version.
  2. Der Name jeder Build-Aufgabe, kurz bevor sie ausgeführt wird (PSake betrachtet jede Aufgabe als Build -Aufgabe). Im Beispiel: Ausführen von HelloWorld in Cyan.
  3. Jede Ausgabe, die die Aufgabe erzeugt hat. Im Beispiel: Hello World in Gelb.
  4. Erfolg-/Fehlermeldung. Im Beispiel: psake erfolgreich ausgeführt… in Grün.
  5. Zusammenfassung der Zeit (mit dem Namen Build Time Report) mit der Dauer jeder Aufgabe sowie der Gesamtdauer des gesamten Skripts.

SQL mit PSake installieren

In dem vorherigen Abschnitt haben Sie nicht viel getan, außer ein Dummy-PSake-Skript aufzurufen. Bauen Sie nun auf diesem Wissen auf und erstellen Sie ein PSake-Skript, das SQL installiert!

In diesem Beispiel erstellen Sie ein PSake-Skript, das Folgendes durchführt:

  1. Überprüfung des freien Festplattenspeichers auf einem Computer.
  2. Herunterladen einer SQL-ZIP-Datei aus einem lokalen Repository.
  3. Extrahieren der ZIP-Datei.
  4. Ausführung der Installation auf Laufwerk C oder D (je nachdem, welches der beiden vorhanden ist).

Als nächstes sehen wir, wie wir PSake für diese Aufgabe nutzen können.

Entwurf der Bausteine

PSake geht darum, Aufgaben zu orchestrieren. Jede Aufgabe sollte einen eindeutigen Namen haben und idealerweise eine einzelne atomare Operation wie eine PowerShell-Funktion ausführen. Mit diesem Konzept können Sie die Schritte unten beschreiben, um für jede eine Aufgabe zu erstellen.

  1. ValidateDiskSpace
  2. DownloadSql
  3. ExtractSql
  4. InstallSqlDriveC
  5. InstallSqlDriveD

An diesem Punkt erstellen Sie den Code noch nicht tatsächlich, um etwas auszuführen. Sie erstellen nur die Aufgabenstruktur und die PSake-Datei. Sie werden später zu den Aufgaben hinzufügen, wie Sie an den Write-Host-Verweisen in den Aufgaben unten sehen können.

Sie sollten immer den Parameter Description für jede Aufgabe verwenden. Der Parameter Description liefert weitere Informationen zu jeder Aufgabe sowohl bei der Ausführung der Aufgaben als auch beim Überprüfen des Codes.

task ValidateDiskSpace -Description 'Validate Disk Free Space' -Action {
	
	Write-Host "`n   *** Checking disk free space ***`n" -ForegroundColor Yellow
	
}

task DownloadSql -Description 'Download SQL Setup' -Action {
	
	Write-Host "`n   *** Downloading SQL Setup from LAN ***`n" -ForegroundColor Yellow
	
}

task ExtractSql -Description 'Extract SQL Setup' -Action {
	
	Write-Host "`n   *** Extracting SQL Setup files ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveC -Description 'Install SQL on C:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow

}

task InstallSqlDriveD -Description 'Install SQL on D:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Festlegen der Ausführungsreihenfolge der Aufgaben

Sie haben nun eine PSake-Datei, die eine Reihe von Aufgaben enthält. Zu diesem Zeitpunkt können Sie alle Aufgaben auf einmal ausführen oder wählen, nur einige davon mit dem Befehl Invoke-PSake auszuführen.

Sie können einige (oder alle Aufgaben) mit Invoke-PSake und dem TaskList-Parameter aufrufen, wie Sie es zuvor im einfachen Beispiel getan haben. Wenn Sie mehr als eine Aufgabe aufrufen möchten, erstellen Sie ein Array und definieren Sie den Namen jeder Aufgabe als Element wie unten gezeigt.

Invoke-PSake führt jede Aufgabe in der im Array definierten Reihenfolge aus.

$taskList = @()

$taskList += 'ValidateDiskSpace'
$taskList += 'DownloadSql'
$taskList += 'ExtractSql'
$taskList += 'InstallSqlDriveC'
$taskList += 'InstallSqlDriveD'

Invoke-PSake -TaskList $taskList

Wenn Sie den obigen Code ausführen, erhalten Sie ein Ergebnis wie das folgende:

PSake script output

Hinzufügen einer Vorbedingung

Vielleicht müssen Sie eine Aktion nur dann ausführen, wenn eine bestimmte Bedingung erfüllt ist. In unserem Beispiel-SQL-Installationsskript müssen Sie möglicherweise beispielsweise testen, ob das Volume, in dem Sie den Installer speichern, verfügbar ist, bevor Sie die Aufgabe zum Aufrufen dieses Installers ausführen.

Sie können den PreCondition-Parameter verwenden, um einen Code auszuführen, der entweder einen booleschen Wert True oder False zurückgibt, der angibt, ob diese Aufgabe ausgeführt wird oder nicht.

Beachten Sie im folgenden Beispiel die Variablen $installSqlOn_C_Drive und $installSqlOn_D_Drive. Wenn Invoke-PSake dieses Skript aufruft, enthalten diese Variablen einen Wert True oder False, je nachdem, ob ein C- oder D-Volume vorhanden ist.

Auf jeder task-Zeile können Sie dann sehen, dass jede Aufgabe einen PreCondition-Skriptblock-Parameter enthält, der den Wert dieser Variablen enthält. Zur Laufzeit wird entweder die Aufgabe InstallSqlDriveC oder die Aufgabe InstallSqlDriveD ausgeführt, abhängig von diesen Variablen.

$installSqlOn_C_Drive = (Test-Path -Path 'C:') -and (-not (Test-Path -Path 'D:'))
$installSqlOn_D_Drive = (-not (Test-Path -Path 'C:')) -and (Test-Path -Path 'D:')

task InstallSqlDriveC -Description 'Install SQL on C:' -PreCondition { $installSqlOn_C_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Aufgabenparameter

Neben Action und Description unterstützt eine Aufgabe auch diese Parameter:

  • PreCondition – Ein Skriptblock, der einen booleschen Wert zurückgibt. Bei False wird die spezifische Aufgabe übersprungen. (Ein Beispiel für die Verwendung ist oben gezeigt).
  • PostCondition Validierungsschritt. Ein Skriptblock, der einen booleschen Wert zurückgibt. False bedeutet, dass die Validierung fehlgeschlagen ist und das gesamte Skript gestoppt wird.
  • PreAction – Ein Skriptblock, der vor der Aufgabe ausgeführt wird.
  • PostAction Ein Skriptblock, der unmittelbar nach Abschluss der Aufgabe mit Erfolg ausgeführt wird.
  • ContinueOnError Schalterparameter. Wenn verwendet, führen Fehler, die während der Laufzeit der Aufgabe auftreten können, nicht zum Abbruch des gesamten Skripts.
  • Depends Der Name einer Aufgabe (oder eine Liste von Aufgabennamen), die vor der Ausführung der aktuellen Aufgabe ausgeführt werden muss. PSake verwendet diese Informationen, um die Aufgabenabhängigkeiten in der richtigen Reihenfolge auszuführen. Wenn Aufgabe A beispielsweise von Aufgabe B abhängig ist, wird die PSake-Engine B vor A ausführen.

Zunächst klingt der Abhängigkeitsmechanismus wie eine gute Idee. Er hilft dabei, Aufgaben in einer logischen Reihenfolge festzulegen. Allerdings verbindet der Einsatz des Depends-Parameters verschiedene Aufgaben miteinander, was es später schwierig macht, sie unabhängig voneinander zu testen. Da der Benutzer jedoch die Reihenfolge der Aufgabenausführung explizit festlegen und diese Reihenfolge beim Aufruf der PSake-Datei übergeben kann, kann der Einsatz des Depends-Parameters vollständig vermieden werden.

Im nächsten Beispiel sehen wir die Verwendung einiger dieser Aufgabenparameter:

Hinzufügen von PreAction und PostCondition

Verwenden Sie die InstallSqlDriveD Aufgabe aus dem obigen Beispiel als Ausgangspunkt, haben Sie vielleicht eine zusätzliche Anforderung für die Installation.

Vielleicht müssen Sie die Zeiten aufzeichnen, zu denen die Installation beginnt und endet. Sie müssen diese Zeiten in zwei Umgebungsvariablen mit den Namen SqlSetupStartDate und SqlSetupEndDate aufzeichnen. Zweitens müssen Sie nach Abschluss der Installation überprüfen, dass der Ordner D:\TempSqlFiles nicht existiert.

Zum Glück erfüllen die PSake Aufgabenparameter PreAction, PostAction und PostCondition (entsprechend) genau diese neuen Anforderungen. Im Folgenden finden Sie ein Beispiel, wie dies gemacht werden kann:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreAction {

     Write-Host '*** Writing SQL install start time to env. var. SqlSetupStartDate ***' -ForegroundColor Yellow
     $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupStartDate',$date,'Machine')

 } -PreCondition { 

     $installSqlOn_D_Drive

 } -Action {  
  
     Write-Host '*** Installing SQL Server on D drive... please wait... ***' -ForegroundColor Yellow 

} -PostAction {     

    Write-Host '*** Writing SQL install end time to env. var. SqlSetupEndDate ***' -ForegroundColor Yellow     
    $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupEndDate',$date,'Machine') 

} -PostCondition { 
    
Write-Host '*** Verifying temp files deleted ***' -ForegroundColor Yellow
     # falls der Ordner existiert, wird dies False zurückgeben und das gesamte Skript stoppen
     (-not (Test-Path -Path 'D:\TempSqlFiles'))

 }

Ausführen von PSake-Skripten in Pester-Tests

Wo immer Sie ein PowerShell-Skript aufrufen können, können Sie auch eine PSake-Datei aufrufen. Wenn Sie Infrastrukturtests mit Pester erstellen, können Sie PSake innerhalb der Tests aufrufen.

Verwandt: Schreiben von Pester-Tests für PowerShell

Zum Beispiel haben Sie möglicherweise einen Pester-Test, um zu bestätigen, dass die SQL-Setup-ZIP-Datei in einem Ordner vorhanden ist, nachdem Sie die DownloadSql-Aufgabe ausgeführt haben. In diesem Fall erstellen Sie einen einfachen Pester-Test und rufen die DownloadSql-Aufgabe innerhalb des Tests auf und überprüfen, ob die ZIP-Datei direkt nach dem Ausführen vorhanden ist.

Describe 'SQL install with PSake' {

    It 'Downloads Sql files' {

        $setup = 'C:\Downloads\SqlSetup.zip'

        if(Test-Path -Path $setup)
        {
            Remove-Item -Path $setup
        }

        # die einzige Aufgabe, die hier getestet wird, ist DownloadSql
        Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList DownloadSql
        
        $setup | Should -Exist
    }
}

Übergabe von Parametern an Aufgaben

Wenn Sie PSake verwenden, möchten Sie möglicherweise einige der Aufgaben parametrisieren. Normalerweise geben Sie PowerShell-Funktionen und -Skripten verschiedene benannte Parameter an die Funktion/das Skript weiter. PSake ist jedoch anders.

Um Parameter an PSake-Dateien zu übergeben, können Sie einen Properties-Block verwenden, der Schlüssel/Wert-Paare definiert, die PSake dann innerhalb jeder Aufgabe in der Datei verfügbar macht.

Sie müssen den Properties-Block oben in der PSake-Datei definieren. Alle PSake-Operationen werden von oben nach unten gelesen.

Zum Beispiel können Sie die dynamischen Variablen SqlYear und SqlVersion an jede Aufgabe in der PSake-Datei übergeben, indem Sie sie wie folgt definieren.

Properties {
    $SqlYear = '2017'
    $SqlVersion = '14.0'
}

task -Name DownloadSql -Action {
    
    Write-Host "SQL version to install: SQL $SqlYear (version $SqlVersion)"

}

Wenn Sie dann die PSake-Datei mit Invoke-PSake aufrufen, sehen Sie die folgende Ausgabe. Beachten Sie, dass die Variablen $SqlYear und $SqlVersion mit den Werten aus dem Properties-Block erweitert wurden.

psake version 4.9.1
Copyright (c) 2010-2018 James Kovacs & Contributors

Executing DownloadSql
SQL version to install: SQL 2017 (version 14.0)

psake succeeded executing C:\Work\PSakefile.ps1

--------------------------------------------------
Build Time Report
--------------------------------------------------

Name        Duration
----        --------
DownloadSql 00:00:00
------      --------
Total:      00:00:00

Verwendung des Properties-Parameters

Wenn Sie Parameter lieber über einen herkömmlichen Parameter an eine Aufgabe übergeben möchten, kann Ihnen PSake helfen. Sie müssen den Properties-Block immer noch oben in der Datei psakefile.ps1 wie im obigen Beispiel beibehalten, aber PSake ermöglicht es Ihnen, die Werte zu überschreiben.

Um dies zu tun, definieren Sie eine Hashtable mit jedem der Schlüssel/Wert-Paare, die Sie überschreiben möchten. Übergeben Sie dann die Hashtable an den Eigenschaften-Parameter. Die PSake-Engine verwendet die Werte in der übergebenen Hashtable vor denen, die in dem Eigenschaften-Block im Skript psakefile.ps1 angegeben sind.

Beachten Sie die Unterschiede in der Syntax zwischen dem Eigenschaften-Block und dem Eigenschaften-Parameter. Im Eigenschaften-Block ist jede Zeile eine Variable und daher mit einem Dollarzeichen versehen, während der Eigenschaften-Parameter eine Hashtable ist, sodass jedes Element ein Schlüssel ist und ohne ein führendes $ geschrieben wird. Ein weiterer Unterschied besteht darin, dass die Hashtable mit dem @-Zeichen eingeleitet wird.

Unten sehen Sie ein Beispiel für die Verwendung des Eigenschaften-Parameters.

$myNewProperties = @{
    SqlYear = '2019'
    SqlVersion = '15.0'
}

Invoke-PSake -TaskList DownloadSql -Properties $myNewProperties

PSake Task Modularisierung: Aufgaben als Dateien

Irgendwann wird Ihre PSake-Datei wahrscheinlich exponentiell wachsen, insbesondere wenn Sie große Automatisierungsaufgaben orchestrieren müssen. Um sicherzustellen, dass Sie all diese Aufgaben verwalten können, sollten Sie sich auf Modularisierung oder Aufteilung der Aufgaben konzentrieren, um die Verwaltung zu erleichtern.

Verwandt: Wie man das Refactoring eines PowerShell-Skripts aus der Hölle überlebt

In diesem Beispiel des Tutorials haben Sie mit fünf Aufgaben gearbeitet:

  • ValidateDiskSpace
  • DownloadSql
  • ExtractSql
  • InstallSqlDriveC
  • InstallSqlDriveD

Jede dieser Aufgaben ist in einem einzelnen Skript pssakefile.ps1 definiert. Wenn Sie erwarten, im Laufe der Zeit viele weitere Aufgaben hinzuzufügen, sollten Sie diese Aufgaben in separate Dateien aufteilen, wobei jede Aufgabe in Dateien wie z.B. ValidateDiskSpace.ps1, DownloadSql.ps1, InstallSqlDriveD.ps1, InstallSqlDriveD.ps1 usw. enthalten ist.

Beispielweise enthält die Datei InstallSqlDriveD.ps1 nur diesen Code:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Nachdem die Aufgaben ausgelagert wurden, importieren Sie die Dateien in die psakefile.ps1 mit der Include-Funktion. Sobald dies erledigt ist, besteht der Inhalt der Datei psakefile.ps1 nur noch aus diesem Code:

$installSqlOn_C_Drive = $true
$installSqlOn_D_Drive = $false

Include "$PSScriptRoot\ValidateDiskSpace.ps1"
Include "$PSScriptRoot\DownloadSql.ps1"
Include "$PSScriptRoot\ExtractSql.ps1"
Include "$PSScriptRoot\InstallSqlOnC.ps1"
Include "$PSScriptRoot\InstallSqlOnD.ps1"

Wenn Invoke-PSake das Skript psakefile.ps1 auslöst, weiß Invoke-PSake nicht, ob oder wo sich die Aufgaben im psake-Datei befinden oder ob sie durch die Include-Methode importiert wurden.

Nächste Schritte

PSake ist ein leistungsstarker Skriptorchestrator, der für viele Zwecke verwendet werden kann: Software-Builds, CI/CD, Paketbereitstellungen, Erstellung von Installationsprogrammen und mehr. Die einzige Grenze ist Ihre Vorstellungskraft. Das Erstellen großer Skripte mit PSake zwingt Sie dazu, in Aufgaben (Code-Bausteine) zu denken. Das Konzept der Aufgaben nutzt die PowerShell-Syntax und durch die Verwendung von Aufgaben bereichern Sie Ihr vorhandenes Wissen über die Befehlszeile.

Der mit PSake erstellte Code wird lesbarer, wartbarer und einfacher zu testen. Nach etwas Übung werden Sie feststellen, dass das Aufteilen Ihrer Schritte in verschiedene Aufgaben das Skripten erleichtert. Der geringe zusätzliche Aufwand zahlt sich auf mittlere und lange Sicht groß aus.

Wo sehen Sie PSake in Ihre Arbeitsprojekte einpassen?

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