Automatisches Einfügen von Änderungen während des Paketimports

Hallo zusammen,

ich habe in den letzten Tagen an einer Pipeline gearbeitet, die man grundsätzlich für alle zu importierende Pakete nutzen kann. Damit lassen sich bei Bedarf Änderungen im Paketverzeichnis oder an der Deployment-Application.ps1 vornehmen.

Es gibt dazu schon ein paar Community- und GitHub-Artikel, die mir aber nicht ganz ausgereicht haben:

Kurz zu mir: Ich bin noch ziemlich frisch im PowerShell-Scripting unterwegs und lerne jeden Tag dazu. Teile meiner Skripte wurden mit Hilfe von ChatGPT erstellt. Sicherlich könnte man hier und da noch optimieren, aber für unsere Zwecke funktioniert das bisher super. Deshalb wollte ich meine Lösung einfach mal teilen. Vielleicht hilft sie ja anderen, die noch nicht so fit im Umgang mit PowerShell sind, einen Einstieg in die automatisierte Paketanpassung zu finden.

Mein Beispiel: Learnpulse Screenpresso

Bei diesem Paket soll eine activation.lic-Datei beim Import in das SupportFiles-Verzeichnis kopiert werden, mehrere Registry-Schlüssel während der Installation geschrieben und bei der Deinstallation wieder entfernt werden.

Umsetzung in der Pipeline

Ich habe dafür die Pipeline-Funktion Inline-Skript ausführen verwendet. Diese läuft direkt vor der Funktion Skript-Signierung.

## Inline-Skript ##
[string]$apcPackageName = "<Run.PackageName>"
[string]$apcWorkingDirectory = "<Phase.EmpirumPackagePath>\<Run.Version>"
[string]$customScriptShare = "\\empirum\Scripts"
[string]$customScriptPath = Join-Path $customScriptShare -ChildPath $apcPackageName
[string]$customScriptFile = Join-Path $customScriptPath -ChildPath "CustomScript.ps1"

if (Test-Path -Path $customScriptFile) {
    Write-Host "-------------------------------------------------------------"
    Write-Host "$customScriptFile ist vorhanden und wird gestartet..."
    & $customScriptFile `
        -apcPackageName $apcPackageName `
        -apcWorkingDirectory $apcWorkingDirectory `
        -customScriptShare $customScriptShare `
        -customScriptPath $customScriptPath
    Write-Host "-------------------------------------------------------------"
} else {
    Write-Host "-------------------------------------------------------------"
    Write-Host "$customScriptFile ist nicht vorhanden."
    Write-Host "Es findet keine individuelle Anpassung des Pakets statt."
    Write-Host "-------------------------------------------------------------"
}

Damit die Pipeline für alle Pakete funktioniert, habe ich mir folgendes überlegt:
Auf dem Empirum-Server gibt es eine Freigabe, in der Unterordner nach dem Schema Hersteller Produktname liegen könnnen, in meinem Fall Learnpulse Screenpresso. Wenn in so einem Ordner ein Skript namens CustomScript.ps1 liegt, wird es ausgeführt. Wenn nicht, passiert einfach nichts und die Pipeline läuft fehlerfrei weiter.

Das Skript CustomScript.ps1 erwartet beim Aufruf vier Parameter, die über das Inline-Skript übergeben werden. Im Skript selbst gibt es zwei Abschnitte.

## CustomScript.ps1 ##
param (
    [Parameter(Mandatory = $true)]
    [string]$apcPackageName,
    [Parameter(Mandatory = $true)]
    [string]$apcWorkingDirectory,
    [Parameter(Mandatory = $true)]
    [string]$customScriptShare,
    [Parameter(Mandatory = $true)]
    [string]$customScriptPath
)

#region Variablen
[string]$neo42AddContentToCustomFunctionFile = Join-Path -Path $customScriptShare -ChildPath "Add-ContentToCustomFunction.ps1"
[string]$neo42DeployApplicationFile          = Join-Path -Path $apcWorkingDirectory -ChildPath "PSADT\Deploy-Application.ps1"
#endregion Variablen

#region CustomPackageChanges
[string]$customSupportFiles    = Join-Path -Path $customScriptPath -ChildPath "SupportFiles\*"
[string]$neo42SupportFilesPath = Join-Path -Path $apcWorkingDirectory -ChildPath "PSADT\SupportFiles"

Write-Host "## Abschnitt CustomPackageChanges ##"
Write-Host "Starte Kopiervorgang der SupportFiles..."
Write-Host "Quelle: $customSupportFiles"
Write-Host "Ziel: $neo42SupportFilesPath"

try {
    Copy-Item -Path $customSupportFiles -Destination $neo42SupportFilesPath -Force -ErrorAction Stop
    Write-Host "Datei(en) erfolgreich kopiert."
}
catch {
    Write-Error "Fehler beim Kopieren der Datei(en): $_"
    exit 1
}
#endregion CustomPackageChanges

#region CustomCodeInjection
Write-Host "## Abschnitt CustomCodeInjection ##"

if (-not (Test-Path -Path $neo42AddContentToCustomFunctionFile)) {
    Write-Error "Die Datei '$neo42AddContentToCustomFunctionFile' existiert nicht."
    exit 1
}

if (-not (Test-Path -Path $neo42DeployApplicationFile)) {
    Write-Error "Die Datei '$neo42DeployApplicationFile' existiert nicht."
    exit 1
}

try {
    & $neo42AddContentToCustomFunctionFile `
        -DeployApplicationFile $neo42DeployApplicationFile `
        -ContentFile (Join-Path -Path $customScriptPath -ChildPath "CustomInstallAndReinstallEnd.ps1") `
        -FunctionName "CustomInstallAndReinstallEnd" `
        -InsertAtEnd

    & $neo42AddContentToCustomFunctionFile `
        -DeployApplicationFile $neo42DeployApplicationFile `
        -ContentFile (Join-Path -Path $customScriptPath -ChildPath "CustomUninstallBegin.ps1") `
        -FunctionName "CustomUninstallBegin" `
        -InsertAtEnd

    Write-Host "Custom Code erfolgreich in '$neo42DeployApplicationFile' injiziert."
}
catch {
    Write-Error "Fehler beim Injizieren des Codes in die Zieldatei: $_"
    exit 1
}
#endregion CustomCodeInjection 

Im Abschnitt CustomPackageChanges kopiere ich den Inhalt der Freigabe \\empirum\Scripts\Learnpulse Screenpresso\SupportFiles in das SupportFiles-Verzeichnis des Pakets.

Im Abschnitt CustomCodeInjection rufe ich mehrfach die Funktion Add-ContentToCustomFunction auf, die von neo42 bereitgestellt wird. Dabei wird der Inhalt einer .ps1-Datei aus dem Verzeichnis \\empirum\Scripts\Learnpulse Screenpresso in die Deployment-Application.ps1 eingefügt.
Ich habe mich dazu entschieden, die zu importierende Datei genauso zu benennen wie den Skriptblock, in den der Code eingefügt werden soll.

Der gesamte Inhalt der ps1-Dateien, die in die Deployment-Application.ps1 eingefügt werden sollen, wird einfach an die jeweilige Stelle kopiert. Hier ein Beispiel:

## CustomInstallAndReinstallEnd.ps1 ##
# Registry-Key für Screenpresso Policies
[string]$registryKey = 'HKEY_LOCAL_MACHINE\SOFTWARE\Learnpulse\Screenpresso\Policies'

$stvRegistrySettings = @{
    NoRoaming              = 0
    NoUpdate               = 1
    NoUpdateBeta           = 1
    NoSharing              = 1
    NoGoogleTranslate      = 1
    NoVideo                = 0
    NoDevice               = 1
    NoOcr                  = 0
    NoInstall              = 1
    NoBrowserExtension     = 1
    NoErrorReportingEmail  = 1
    NoLicenseManagement    = 1
    NoFirstTimeMessages    = 1
    NoSettings             = 0
    NoImagePack            = 1
    SupportEmail           = 'support@hotline.de'
}

foreach ($setting in $registrySettings.GetEnumerator()) {
    $type = if ($setting.Value -is [string]) { 'String' } else { 'DWord' }
    Set-RegistryKey -Key $registryKey -Name $setting.Key -Type $type -Value $setting.Value
}

Ich hoffe, der Text ist verständlich und kann dem einen oder anderen bei der Umsetzung helfen. Falls weitere Fragen bestehen, meldet euch gerne.

Gruß

2 „Gefällt mir“

In der Beispieldatei hat sich leider ein Fehler in der Variablenbenennung des Arrays eingeschlichen. $stvRegistrySettings muss in $registrySettings umbenannt werden, damit die Schleife funktioniert.